diff --git a/.travis.yml b/.travis.yml index e619bf6..4855ea4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,42 @@ language: c -# Platform descriptions -# NOTE: These can be used in creating the build matrix by making use of the -# anchor/alias YAML features. +# Coverity Scan can be configured through Travis addons, but this allows for +# more control over the build instructions and does not require the addition +# of a coverity_scan branch in the repository. travisci_build_coverity_scan.sh +# does more checks before it decides to download Coverity (around 500M), but +# these instructions assume Coverity Scan is not installed if the directory +# does not exist and expects the download to fail if the token is incorrect. +# Coverity Scan quota are not checked as the Coverity enabled build must only +# run from cron. +install_coverity: &install_coverity + if [ "${COVERITY_SCAN}" = "true" ]; then + COV_DIR="/tmp/coverity-scan-analysis"; + COV_ARC="/tmp/cov-analysis-${COV_PLATFORM}.tgz"; + test ! -d "${COV_DIR}" && + mkdir -p "${COV_DIR}" && + curl -s -S -F project="${TRAVIS_REPO_SLUG}" + -F token="${COVERITY_SCAN_TOKEN}" + -o "${COV_ARC}" + "https://scan.coverity.com/download/cxx/${COV_PLATFORM}" && + tar -xzf "${COV_ARC}" -C "${COV_DIR}"; + COV_ANALYSIS=$(find "${COV_DIR}" -type d -name "cov-analysis*"); + eval "export PATH=\"${PATH}:${COV_ANALYSIS}/bin\""; + eval "export SCAN_BUILD=\"cov-build --dir cov-int\""; + cov-configure --comptype ${COV_COMPTYPE} --compiler ${CC} --template; + fi + +submit_to_coverity_scan: &submit_to_coverity_scan + if [ "${COVERITY_SCAN}" = "true" ]; then + tar -czf analysis-results.tgz cov-int && + curl -s -S -F project="${TRAVIS_REPO_SLUG}" + -F token="${COVERITY_SCAN_TOKEN}" + -F file=@analysis-results.tgz + -F version=$(git rev-parse --short HEAD) + -F description="Travis CI build" + -F email="${COVERITY_SCAN_EMAIL:=cyclonedds-inbox@eclipse.org}" + "https://scan.coverity.com/builds"; + fi + linux_gcc8: &linux_gcc8 os: linux dist: xenial @@ -12,6 +46,13 @@ linux_gcc8: &linux_gcc8 update: true sources: [ ubuntu-toolchain-r-test ] packages: [ gcc-8 g++-8 ] + before_install: + - eval "export CC=gcc-8" + - eval "export CXX=g++-8" + - eval "export COV_COMPTYPE=gcc COV_PLATFORM=linux64" + install: + - *install_coverity + - pip install conan --upgrade --user linux_clang: &linux_clang os: linux @@ -20,95 +61,106 @@ linux_clang: &linux_clang addons: apt: update: true + before_install: + - eval "export CC=clang" + - eval "export CXX=clang++" + - eval "export COV_COMPTYPE=clang COV_PLATFORM=linux64" + install: + - pip install conan --upgrade --user -osx_xcode10_1: &osx_xcode10_1 +osx_xcode10_2: &osx_xcode10_2 os: osx - osx_image: xcode10.1 + osx_image: xcode10.2 compiler: clang addons: homebrew: packages: - pyenv-virtualenv + before_install: + - eval "export CC=clang" + - eval "export CXX=clang++" + - eval "export COV_COMPTYPE=clang COV_PLATFORM=macOSX" + install: + - eval "$(pyenv init -)" + - pyenv virtualenv conan + - pyenv rehash + - pyenv activate conan + - pip install conan --upgrade windows_vs2017: &windows_vs2017 os: windows + # Conan will automatically determine the best compiler for a given platform + # based on educated guesses. The first check is based on the CC and CXX + # environment variables, the second (on Windows) is to check if Microsoft + # Visual Studio is installed. On Travis CC and CXX are set to gcc on + # Microsoft Windows targets as well, this has the undesired effect that MSVC + # is not detected, unsetting CC and CXX solves that problem. + # + # + # !!! IMPORTANT !!! + # + # Microsoft Windows instances freeze at "install:" if secure environment + # variables are used. There is no option to export secrets only for + # specified platforms. The "filter_secrets: false" option is used to disable + # the filter for Microsoft Windows instances. This is not an issue if the + # secret is removed from the environment at the earliest opportunity, before + # risk of exposure, as secrets are always removed from the environment for + # pull requests and are still filtered when exported to the environment. The + # secret of course will not be available for Microsoft Windows builds, but + # for Coverity Scan, that is fine. + filter_secrets: false + before_install: + - eval "unset COVERITY_SCAN_TOKEN" + - eval "unset COVERITY_SCAN_EMAIL" + - eval "unset CC" + - eval "unset CXX" + - eval "export COV_COMPTYPE=msvc COV_PLATFORM=win64" + - JAVA_HOME=$(find "/c/Program Files/Android/jdk/" -name "*openjdk*" | sort | head -n 1) + - export JAVA_HOME + - export PATH="${PATH}:${JAVA_HOME}/bin" + # Windows targets in Travis are still very much in beta and Python is not yet + # available and installation of Python through Chocolaty does not work well. + # The real fix is to wait until Python and pip are both available on the + # target. Until then download Conan from the official website and simply add + # the extracted folder to the path. + install: + - choco install innoextract + - choco install maven --ignore-dependencies + - wget -q https://dl.bintray.com/conan/installers/conan-win-64_1_10_0.exe + - innoextract conan-win-64_1_10_0.exe + - eval "export PATH=\"$(pwd)/app/conan:${PATH}\"" -matrix: +jobs: include: - <<: *linux_gcc8 - env: [ BUILD_TYPE=Debug, C_COMPILER=gcc-8, CXX_COMPILER=g++-8, USE_SANITIZER=none ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] + if: type = cron - <<: *linux_gcc8 - env: [ BUILD_TYPE=Release, C_COMPILER=gcc-8, CXX_COMPILER=g++-8, USE_SANITIZER=none ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ] + - <<: *linux_gcc8 + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ] + - <<: *linux_gcc8 + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, GENERATOR="Unix Makefiles" ] + - <<: *linux_gcc8 + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ BUILD_TYPE=Debug, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=address ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ BUILD_TYPE=Release, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=none ] - - <<: *osx_xcode10_1 - env: [ BUILD_TYPE=Debug, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=address ] - - <<: *osx_xcode10_1 - env: [ BUILD_TYPE=Release, C_COMPILER=clang, CXX_COMPILER=clang++, USE_SANITIZER=none ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ] + - <<: *osx_xcode10_2 + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ] + - <<: *osx_xcode10_2 + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ] - <<: *windows_vs2017 - env: [ ARCH=x86, BUILD_TYPE=Debug, GENERATOR="Visual Studio 15 2017" ] + env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Visual Studio 15 2017" ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, BUILD_TYPE=Debug, GENERATOR="Visual Studio 15 2017" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Visual Studio 15 2017 Win64" ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, BUILD_TYPE=Release, GENERATOR="Visual Studio 15 2017" ] - -# Conan will automatically determine the best compiler for a given platform -# based on educated guesses. The first check is based on the CC and CXX -# environment variables, the second (on Windows) is to check if Microsoft -# Visual Studio is installed. On Travis CC and CXX are set to gcc on Microsoft -# Windows targets as well, this has the undesired effect that MSVC is not -# detected, unsetting CC and CXX solves that problem. -before_install: - - if [ "${TRAVIS_OS_NAME}" = "windows" ]; then - eval "unset CC"; - eval "unset CXX"; - JAVA_HOME=$(find "/c/Program Files/Android/jdk/" -name "*openjdk*" | sort | head -n 1); - export JAVA_HOME; - export PATH="${PATH}:${JAVA_HOME}/bin"; - else - eval "export CC=${C_COMPILER}"; - eval "export CXX=${CXX_COMPILER}"; - fi - -# Windows targets in Travis are still very much in beta and Python is not yet -# available and installation of Python through Chocolaty does not work well. -# The real fix is to wait until Python and pip are both available on the -# target. Until then download Conan from the official website and simply add -# the extracted folder to the path. -install: - - if [ "${TRAVIS_OS_NAME}" = "windows" ]; then - choco install innoextract; - choco install maven --ignore-dependencies; - wget -q https://dl.bintray.com/conan/installers/conan-win-64_1_10_0.exe; - innoextract conan-win-64_1_10_0.exe; - eval "export PATH=\"$(pwd)/app/conan:${PATH}\""; - elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then - eval "$(pyenv init -)"; - pyenv virtualenv conan; - pyenv rehash; - pyenv activate conan; - pip install conan --upgrade; - else - pip install conan --upgrade --user; - fi - - conan profile new default --detect + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Visual Studio 15 2017 Win64" ] before_script: + - conan profile new default --detect - conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan - - conan profile get settings.arch default - - if [ -z "${ARCH}" ]; then - eval "export ARCH=\"$(conan profile get settings.arch default)\""; - fi - - if [ "${TRAVIS_OS_NAME}" = "windows" ]; then - GENERATOR_ARCH=$(if [ "${ARCH}" = "x86_64" ]; then echo " Win64"; fi); - eval "export GENERATOR=\"${GENERATOR}${GENERATOR_ARCH}\""; - eval "export USE_SANITIZER=none"; - else - eval "export GENERATOR=\"Unix Makefiles\""; - fi - - export script: - mkdir build @@ -116,12 +168,24 @@ script: - conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} .. - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=$(pwd)/install - -DUSE_SANITIZER=${USE_SANITIZER} + -DUSE_SANITIZER=${ASAN} + -DENABLE_SSL=${SSL} -DBUILD_TESTING=on - -G "${GENERATOR}" ../src - - cmake --build . --config ${BUILD_TYPE} --target install - - CYCLONEDDS_URI='all' ctest -T test -C ${BUILD_TYPE} - - if [ "${USE_SANITIZER}" != "none" ]; then + -DWERROR=on + -G "${GENERATOR}" .. + - case "${GENERATOR}" in + "Unix Makefiles") + ${SCAN_BUILD} cmake --build . --config ${BUILD_TYPE} --target install -- -j 4 + ;; + "Visual Studio "*) + ${SCAN_BUILD} cmake --build . --config ${BUILD_TYPE} --target install -- -nologo -verbosity:minimal -maxcpucount -p:CL_MPCount=2 + ;; + *) + ${SCAN_BUILD} cmake --build . --config ${BUILD_TYPE} --target install + ;; + esac + - CYCLONEDDS_URI='allconfigstderr' ctest -j 4 --output-on-failure -T test -C ${BUILD_TYPE} + - if [ "${ASAN}" != "none" ]; then CMAKE_LINKER_FLAGS="-DCMAKE_LINKER_FLAGS=-fsanitize=${USE_SANITIZER}"; CMAKE_C_FLAGS="-DCMAKE_C_FLAGS=-fsanitize=${USE_SANITIZER}"; fi @@ -132,4 +196,8 @@ script: ${CMAKE_LINKER_FLAGS} -G "${GENERATOR}" .. - cmake --build . --config ${BUILD_TYPE} + - cd "${TRAVIS_BUILD_DIR}/build" + +after_success: + - *submit_to_coverity_scan diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4293a6b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,219 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.7) + +# Set a default build type if none was specified +set(default_build_type "RelWithDebInfo") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +# By default the Java-based components get built, but make it possible to disable that: if only the +# core library is required, there's no need to build them, and that in turn eliminates the Maven and +# JDK dependency. +option(BUILD_IDLC "Build IDL preprocessor" ON) +option(BUILD_CONFTOOL "Build configuration file edit tool" ON) + +# By default don't treat warnings as errors, else anyone building it with a different compiler that +# just happens to generate a warning, as well as anyone adding or modifying something and making a +# small mistake would run into errors. CI builds can be configured differently. +option(WERROR "Treat compiler warnings as errors" OFF) + +FUNCTION(PREPEND var prefix) + SET(listVar "") + FOREACH(f ${ARGN}) + LIST(APPEND listVar "${prefix}/${f}") + ENDFOREACH(f) + SET(${var} "${listVar}" PARENT_SCOPE) +ENDFUNCTION(PREPEND) + +# Set module path before defining project so platform files will work. +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules") +set(CMAKE_PROJECT_NAME_FULL "Eclipse Cyclone DDS") +project(CycloneDDS VERSION 0.1.0) + +# Set some convenience variants of the project-name +string(REPLACE " " "-" CMAKE_PROJECT_NAME_DASHED "${CMAKE_PROJECT_NAME_FULL}") +string(TOUPPER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_CAPS) +string(TOLOWER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_SMALL) + +set(CMAKE_C_STANDARD 99) +if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks") + add_definitions(-std=c99) +endif() + +if(${CMAKE_C_COMPILER_ID} STREQUAL "SunPro") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -xc99 -D__restrict=restrict -D__deprecated__=") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -m64") +elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -m64") +endif() + +# Conan +if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") + include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + if(APPLE) + # By default Conan strips all RPATHs (see conanbuildinfo.cmake), which + # causes tests to fail as the executables cannot find the library target. + # By setting KEEP_RPATHS, Conan does not set CMAKE_SKIP_RPATH and the + # resulting binaries still have the RPATH information. This is fine because + # CMake will strip the build RPATH information in the install step. + # + # NOTE: + # Conan's default approach is to use the "imports" feature, which copies + # all the dependencies into the bin directory. Of course, this doesn't work + # quite that well for libraries generated in this Project (see Conan + # documentation). + # + # See the links below for more information. + # https://github.com/conan-io/conan/issues/337 + # https://docs.conan.io/en/latest/howtos/manage_shared_libraries/rpaths.html + # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling + conan_basic_setup(KEEP_RPATHS) + else() + conan_basic_setup() + endif() + conan_define_targets() +endif() + +# Set reasonably strict warning options for clang, gcc, msvc +# Enable coloured ouput if Ninja is used for building +if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + #message(STATUS clang) + set(wflags "-Wall" + "-Wextra" + "-Wconversion" + "-Wunused" + "-Wmissing-prototypes" + "-Winfinite-recursion" + "-Wassign-enum" + "-Wcomma" + "-Wmissing-prototypes" + "-Wdocumentation" + "-Wstrict-prototypes" + "-Wconditional-uninitialized" + "-Wshadow") + add_compile_options(${wflags}) + if(${WERROR}) + add_compile_options(-Werror) + endif() + if("${CMAKE_GENERATOR}" STREQUAL "Ninja") + add_compile_options(-Xclang -fcolor-diagnostics) + endif() +elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + #message(STATUS gcc) + add_compile_options(-Wall -Wextra -Wconversion -Wmissing-prototypes) + if(${WERROR}) + add_compile_options(-Werror) + endif() + if("${CMAKE_GENERATOR}" STREQUAL "Ninja") + add_compile_options(-fdiagnostics-color=always) + endif() +elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + #message(STATUS msvc) + add_compile_options(/W3) + if(${WERROR}) + add_compile_options(/WX) + endif() +endif() + +# I don't know how to enable warnings properly so that they are enabled in Xcode projects as well +if(${CMAKE_GENERATOR} STREQUAL "Xcode") + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_EMPTY_BODY YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_SHADOW YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_BOOL_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_CONSTANT_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_ENUM_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_FLOAT_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INT_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_NON_LITERAL_NULL_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_IMPLICIT_SIGN_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INFINITE_RECURSION YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_RETURN_TYPE YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_MISSING_PARENTHESES YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_NEWLINE YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_ASSIGN_ENUM YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_SIGN_COMPARE YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_STRICT_PROTOTYPES YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_COMMA YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNINITIALIZED_AUTOS YES_AGGRESSIVE) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_FUNCTION YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_LABEL YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_PARAMETER YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_VALUE YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_VARIABLE YES) + set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_DOCUMENTATION_COMMENTS YES) + set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_PROTOTYPES YES) +endif() + +# Make it easy to enable one of Clang's/gcc's analyzers, and default to using +# the address sanitizer for ordinary debug builds; gcc is giving some grief on +# Travis, so don't enable it for gcc by default +if(NOT USE_SANITIZER) + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug" AND + NOT (${CMAKE_GENERATOR} STREQUAL "Xcode") AND + (${CMAKE_C_COMPILER_ID} STREQUAL "Clang" + OR ${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang")) + message(STATUS "Enabling address sanitizer; set USE_SANITIZER=none to prevent this") + set(USE_SANITIZER address) + else() + set(USE_SANITIZER none) + endif() +endif() +if(NOT (${USE_SANITIZER} STREQUAL "none")) + message(STATUS "Sanitizer set to ${USE_SANITIZER}") + add_compile_options(-fno-omit-frame-pointer -fsanitize=${USE_SANITIZER}) + link_libraries(-fno-omit-frame-pointer -fsanitize=${USE_SANITIZER}) +endif() + +include(GNUInstallDirs) +include(AnalyzeBuild) +if(APPLE) + set(CMAKE_INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") +else() + set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") +endif() +set(MEMORYCHECK_COMMAND_OPTIONS "--track-origins=yes --leak-check=full --trace-children=yes --child-silent-after-fork=yes --xml=yes --xml-file=TestResultValgrind_%p.xml --tool=memcheck --show-reachable=yes --leak-resolution=high") + +# By default building the testing tree is enabled by including CTest, but +# since not everybody has CUnit, and because it is not strictly required to +# build the product itself, switch to off by default. +option(BUILD_TESTING "Build the testing tree." OFF) +include(CTest) + +# Build all executables and libraries into the top-level /bin and /lib folders. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") + +add_subdirectory(src) +if(BUILD_IDLC) + add_subdirectory(examples) +endif() + +option(BUILD_DOCS "Build documentation." OFF) +add_subdirectory(docs) + +# Pull-in CPack and support for generating Config.cmake and packages. +include(Packaging) diff --git a/README.md b/README.md index 3817027..1337cab 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,38 @@ # Eclipse Cyclone DDS -Eclipse Cyclone DDS is by far the most performant and robust DDS implementation available on the -market. Moreover, Cyclone DDS is developed completely in the open as an Eclipse IoT project +Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation. Cyclone DDS is developed completely in the open as an Eclipse IoT project (see [eclipse-cyclone-dds](https://projects.eclipse.org/projects/iot.cyclonedds)). +* [Getting Started](#getting-started) +* [Performance](#performance) +* [Configuration](#configuration) + # Getting Started ## Building Eclipse Cyclone DDS -In order to build Cyclone DDS you need a Linux, Mac or Windows 10 machine with the following -installed on your host: +In order to build Cyclone DDS you need a Linux, Mac or Windows 10 machine (or, with some caveats, an +OpenIndiana one or a Solaris 2.6 one) with the following installed on your host: - * [CMake](https://cmake.org/download/), version 3.7 or later. (Version 3.6 should work but you - will have to edit the ``cmake_minimum_required`` version and may have to disable building the - tests.) - * [OpenSSL](https://www.openssl.org/), preferably version 1.1 or later. If you wish, you can - build without support for OpenSSL by setting DDSC\_ENABLE\_OPENSSL to FALSE on the ``cmake `` - command line (i.e., ``cmake -DDDSC_ENABLE_OPENSSL=FALSE`` ../src). In that, there is no need to - have openssl available. - * Java JDK, version 8 or later, e.g., [OpenJDK 11](http://jdk.java.net/11/). - * [Apache Maven](http://maven.apache.org/download.cgi), version 3.5 or later. + * C compiler (most commonly GCC on Linux, Visual Studio on Windows, Xcode on macOS); + * GIT version control system; + * [CMake](https://cmake.org/download/), version 3.7 or later; + * [OpenSSL](https://www.openssl.org/), preferably version 1.1 or later if you want to use TLS over + TCP. You can explicitly disable it by setting ``ENABLE_SSL=NO``, which is very useful for + reducing the footprint or when the FindOpenSSL CMake script gives you trouble; + * Java JDK, version 8 or later, e.g., [OpenJDK](https://jdk.java.net/); + * [Apache Maven](https://maven.apache.org/download.cgi), version 3.5 or later. + +On Ubuntu ``apt install maven default-jdk`` should do the trick for getting Java and Maven +installed, and the rest should already be there. On Windows, installing chocolatey and ``choco +install git cmake openjdk maven`` should get you a long way. On macOS, ``brew install maven cmake`` +and downloading and installing the JDK is easiest. The Java-based components are the preprocessor and a configurator tool. The run-time libraries are -pure C code, so there is no need to have Java available on "target" machines. +pure C code, so there is no need to have Java available on "target" machines. If desired, it is +possible to do a build without Java or Maven installed by defining ``BUILD_IDLC=NO`` and +``BUILD_CONFTOOL=NO``, but that effectively only gets you the core library. For the +current [ROS2 RMW layer](https://github.com/atolab/rmw_cyclonedds), that is sufficient. To obtain Eclipse Cyclone DDS, do @@ -40,13 +50,13 @@ DDS requires a few simple steps. There are some small differences between Linux hand, and Windows on the other. For Linux or macOS: $ cd build - $ cmake -DCMAKE_INSTALL_PREFIX= ../src + $ cmake -DCMAKE_INSTALL_PREFIX= .. $ cmake --build . and for Windows: $ cd build - $ cmake -G "" -DCMAKE_INSTALL_PREFIX= ../src + $ cmake -G "" -DCMAKE_INSTALL_PREFIX= .. $ cmake --build . where you should replace ```` by the directory under which you would like to @@ -65,7 +75,6 @@ which will copy everything to: * ``/bin`` * ``/include/ddsc`` * ``/share/CycloneDDS`` - * ``/etc/CycloneDDS`` Depending on the installation location you may need administrator privileges. @@ -85,7 +94,7 @@ present in the repository and that there is a test suite using CTest and CUnit t locally if desired. To build it, set the cmake variable ``BUILD_TESTING`` to on when configuring, e.g.: $ cd build - $ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON ../src + $ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON .. $ cmake --build . $ ctest @@ -103,37 +112,19 @@ the moment, OpenSSL). ## Documentation The documentation is still rather limited, and at the moment only available in the sources (in the -form of restructured text files in ``src/docs`` and Doxygen comments in the header files), or as +form of restructured text files in ``docs`` and Doxygen comments in the header files), or as a [PDF](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/pdf/CycloneDDS-0.1.0.pdf). The intent is to automate the process of building the documentation and have them available in more convenient formats and in the usual locations. -## Performance - -Median small message throughput measured using the Throughput example between two Intel(R) Xeon(R) -CPU E3-1270 V2 @ 3.50GHz (that's 2012 hardware ...) running Linux 3.8.13-rt14.20.el6rt.x86_64, -connected via a quiet GbE and when using gcc-6.2.0 for a default (i.e., "RelWithDebInfo") build is: - -Throughput - -This is with the subscriber in polling mode. Listener mode is marginally slower; using a waitset the -message rate for minimal size messages drops to 600k sample/s in synchronous delivery mode and about -750k samples/s in asynchronous delivery mode. The configuration is an out-of-the-box configuration, -tweaked only to increase the high-water mark for the reliability window on the writer side. For -details, see the scripts in the ``performance`` directory and -the -[data](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/throughput.txt). - -There is some data on roundtrip latency below. - ## Building and Running the Roundtrip Example We will show you how to build and run an example program that measures latency. The examples are built automatically when you build Cyclone DDS, so you don't need to follow these steps to be able to run the program, it is merely to illustrate the process. - $ cd cyclonedds/src/examples/roundtrip + $ cd cyclonedds/examples/roundtrip $ mkdir build $ cd build $ cmake .. @@ -149,8 +140,8 @@ On another terminal, start the application that will be sending the pings: # payloadSize: 0 | numSamples: 0 | timeOut: 0 # Waiting for startup jitter to stabilise # Warm up complete. - # Round trip measurements (in us) - # Round trip time [us] Write-access time [us] Read-access time [us] + # Latency measurements (in us) + # Latency [us] Write-access time [us] Read-access time [us] # Seconds Count median min 99% max Count median min Count median min 1 28065 17 16 23 87 28065 8 6 28065 1 0 2 28115 17 16 23 46 28115 8 6 28115 1 0 @@ -167,6 +158,83 @@ The numbers above were measured on Mac running a 4.2 GHz Intel Core i7 on Decemb these numbers you can see how the roundtrip is very stable and the minimal latency is now down to 17 micro-seconds (used to be 25 micro-seconds) on this HW. +# Performance + +Reliable message throughput is over 1MS/s for very small samples and is roughly 90% of GbE with 100 +byte samples, and latency is about 30us when measured using [ddsperf](src/tools/ddsperf) between two +Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz (that's 2012 hardware ...) running Ubuntu 16.04, with the +executables built on Ubuntu 18.04 using gcc 7.4.0 for a default (i.e., "RelWithDebInfo") build. + +ThroughputThroughput + +This is with the subscriber in listener mode, using asynchronous delivery for the throughput +test. The configuration is a marginally tweaked out-of-the-box configuration: an increased maximum +message size and fragment size, and an increased high-water mark for the reliability window on the +writer side. For details, see the [scripts](examples/perfscript) directory, +the +[environment details](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/config.txt) and +the +[throughput](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/sub.log) and +[latency](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/ping.log) data +underlying the graphs. These also include CPU usage ([thoughput](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/throughput-async-listener-cpu.png) and [latency](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/latency-sync-listener-bwcpu.png)) and [memory usage](https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/assets/performance/20190730/throughput-async-listener-memory.png). + +# Configuration + +The out-of-the-box configuration should usually be fine, but there are a great many options that can +be tweaked by creating an XML file with the desired settings and defining the ``CYCLONEDDS_URI`` to +point to it. E.g. (on Linux): + + $ cat cyclonedds.xml + + + + auto + auto + 65500B + 4000B + + + + 500kB + + + + config + stdout + + + + $ export CYCLONEDDS_URI=file://$PWD/cyclonedds.xml + +(on Windows, one would have to use ``set CYCLONEDDS_URI=file://...`` instead.) + +This example shows a few things: + +* ``NetworkInterfaceAddress`` can be used to override the interface selected by default (you can use + the address or the interface name). Proper use of multiple network interfaces simultaneously will + come, but is not there yet. +* ``AllowMulticast`` configures the circumstances under which multicast will be used. If the + selected interface doesn't support it, it obviously won't be used (``false``); but if it does + support it, the type of the network adapter determines the default value. For a wired network, it + will use multicast for initial discovery as well as for data when there are multiple peers that + the data needs to go to (``true``); but on a WiFi network it will use it only for initial + discovery (``spdp``), because multicast on WiFi is very unreliable. +* ``Verbosity`` allows control over the tracing, "config" dumps the configuration to the trace + output (which defaults to "cyclonedds.log"). Which interface is used, what multicast settings are + used, etc., is all in the trace. Setting the verbosity to "finest" gives way more output on the + inner workings, and there are various other levels as well. +* ``MaxMessageSize`` and ``FragmentSize`` control the maximum size of the RTPS messages (basically + the size of the UDP payload), and the size of the fragments into which very large samples get + split (which needs to be "a bit" less). Large values such as these typically improve performance + over the (current) default values. +* ``WhcHigh`` determines when the sender will wait for acknowledgements from the readers because it + has buffered too much unacknowledged data. There is some auto-tuning, the (current) default value + is a bit small to get really high throughput. + +The configurator tool ``cycloneddsconf`` can help in discovering the settings, as can the config +dump. Background information on configuring Cyclone DDS can be +found [here](docs/manual/config.rst). + # Trademarks * "Eclipse Cyclone DDS" and "Cyclone DDS" are trademarks of the Eclipse Foundation. diff --git a/appveyor.yml b/appveyor.yml index 0c96ec1..ed302a7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -36,15 +36,15 @@ build_script: - mkdir build - cd build - conan install -s arch=%ARCH% -s build_type=%CONFIGURATION% .. - - cmake -DBUILD_TESTING=on -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=%CD%/install -G "%GENERATOR%" ../src - - cmake --build . --config %CONFIGURATION% --target install -- /maxcpucount + - cmake -DBUILD_TESTING=on -DWERROR=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=%CD%/install -G "%GENERATOR%" .. + - cmake --build . --config %CONFIGURATION% --target install -- /nologo /verbosity:minimal /maxcpucount /p:CL_MPCount=2 - cd install/share/CycloneDDS/examples/helloworld - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%GENERATOR%" .. - - cmake --build . --config %CONFIGURATION% -- /maxcpucount + - cmake --build . --config %CONFIGURATION% -- /nologo /verbosity:minimal /maxcpucount /p:CL_MPCount=2 - cd ../../../../../.. test_script: - - set "CYCLONEDDS_URI=all" - - ctest --test-action test --build-config %CONFIGURATION% + - set "CYCLONEDDS_URI=allconfigstderr" + - ctest --output-on-failure --parallel 4 --test-action test --build-config %CONFIGURATION% diff --git a/src/cmake/modules/AnalyzeBuild.cmake b/cmake/Modules/AnalyzeBuild.cmake similarity index 100% rename from src/cmake/modules/AnalyzeBuild.cmake rename to cmake/Modules/AnalyzeBuild.cmake diff --git a/src/cmake/modules/CUnit.cmake b/cmake/Modules/CUnit.cmake similarity index 100% rename from src/cmake/modules/CUnit.cmake rename to cmake/Modules/CUnit.cmake diff --git a/src/cmake/modules/CUnit/include/CUnit/Test.h b/cmake/Modules/CUnit/include/CUnit/Test.h similarity index 84% rename from src/cmake/modules/CUnit/include/CUnit/Test.h rename to cmake/Modules/CUnit/include/CUnit/Test.h index 4e9f2d4..4797c35 100644 --- a/src/cmake/modules/CUnit/include/CUnit/Test.h +++ b/cmake/Modules/CUnit/include/CUnit/Test.h @@ -28,33 +28,36 @@ typedef struct { #define CU_TestProxyName(suite, test) \ CU_TestProxy_ ## suite ## _ ## test -#define CU_Init(suite) \ - int CU_InitName(suite)(void) #define CU_InitDecl(suite) \ - extern CU_Init(suite) + extern int CU_InitName(suite)(void) +#define CU_Init(suite) \ + CU_InitDecl(suite); \ + int CU_InitName(suite)(void) -#define CU_Clean(suite) \ - int CU_CleanName(suite)(void) #define CU_CleanDecl(suite) \ - extern CU_Clean(suite) + extern int CU_CleanName(suite)(void) +#define CU_Clean(suite) \ + CU_CleanDecl(suite); \ + int CU_CleanName(suite)(void) /* CU_Test generates a wrapper function that takes care of per-test initialization and deinitialization, if provided in the CU_Test signature. */ #define CU_Test(suite, test, ...) \ static void CU_TestName(suite, test)(void); \ + void CU_TestProxyName(suite, test)(void); \ \ void CU_TestProxyName(suite, test)(void) { \ - cu_data_t data = CU_Fixture(__VA_ARGS__); \ + cu_data_t cu_data = CU_Fixture(__VA_ARGS__); \ \ - if (data.init != NULL) { \ - data.init(); \ + if (cu_data.init != NULL) { \ + cu_data.init(); \ } \ \ CU_TestName(suite, test)(); \ \ - if (data.fini != NULL) { \ - data.fini(); \ + if (cu_data.fini != NULL) { \ + cu_data.fini(); \ } \ } \ \ diff --git a/src/cmake/modules/CUnit/include/CUnit/Theory.h b/cmake/Modules/CUnit/include/CUnit/Theory.h similarity index 86% rename from src/cmake/modules/CUnit/include/CUnit/Theory.h rename to cmake/Modules/CUnit/include/CUnit/Theory.h index 81dd7f7..6a1b98a 100644 --- a/src/cmake/modules/CUnit/include/CUnit/Theory.h +++ b/cmake/Modules/CUnit/include/CUnit/Theory.h @@ -44,21 +44,22 @@ extern "C" { #define CU_Theory(signature, suite, test, ...) \ static void CU_TestName(suite, test) signature; \ + void CU_TestProxyName(suite, test)(void); \ \ void CU_TestProxyName(suite, test)(void) { \ - cu_data_t data = CU_Fixture(__VA_ARGS__); \ + cu_data_t cu_data = CU_Fixture(__VA_ARGS__); \ size_t i, n; \ \ - if (data.init != NULL) { \ - data.init(); \ + if (cu_data.init != NULL) { \ + cu_data.init(); \ } \ \ for (i = 0, n = CU_TheoryDataPointsSize(suite, test); i < n; i++) { \ CU_TestName(suite, test) CU_TheoryDataPointsSlice(suite, test, i) ; \ } \ \ - if (data.fini != NULL) { \ - data.fini(); \ + if (cu_data.fini != NULL) { \ + cu_data.fini(); \ } \ } \ \ diff --git a/src/cmake/modules/CUnit/src/main.c.in b/cmake/Modules/CUnit/src/main.c.in similarity index 98% rename from src/cmake/modules/CUnit/src/main.c.in rename to cmake/Modules/CUnit/src/main.c.in index 2be3165..a61ac85 100644 --- a/src/cmake/modules/CUnit/src/main.c.in +++ b/cmake/Modules/CUnit/src/main.c.in @@ -13,12 +13,8 @@ #include #include -#ifndef _WIN32 -#include -#else #define EX_USAGE (64) #define EX_SOFTWARE (70) -#endif /* _WIN32 */ #include #include diff --git a/src/cmake/modules/FindCUnit.cmake b/cmake/Modules/FindCUnit.cmake similarity index 90% rename from src/cmake/modules/FindCUnit.cmake rename to cmake/Modules/FindCUnit.cmake index 5b19165..518ed8a 100644 --- a/src/cmake/modules/FindCUnit.cmake +++ b/cmake/Modules/FindCUnit.cmake @@ -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( diff --git a/src/cmake/modules/FindMaven.cmake b/cmake/Modules/FindMaven.cmake similarity index 100% rename from src/cmake/modules/FindMaven.cmake rename to cmake/Modules/FindMaven.cmake diff --git a/src/cmake/modules/FindOpenSSL.cmake b/cmake/Modules/FindOpenSSL.cmake similarity index 100% rename from src/cmake/modules/FindOpenSSL.cmake rename to cmake/Modules/FindOpenSSL.cmake diff --git a/cmake/Modules/FindSphinx.cmake b/cmake/Modules/FindSphinx.cmake new file mode 100644 index 0000000..70ddc89 --- /dev/null +++ b/cmake/Modules/FindSphinx.cmake @@ -0,0 +1,331 @@ +# +# Copyright(c) 2019 Jeroen Koekkoek +# +# 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(FindPackageHandleStandardArgs) + +macro(_Sphinx_find_executable _exe) + string(TOUPPER "${_exe}" _uc) + # sphinx-(build|quickstart)-3 x.x.x + # FIXME: This works on Fedora (and probably most other UNIX like targets). + # Windows targets and PIP installs might need some work. + find_program( + SPHINX_${_uc}_EXECUTABLE + NAMES "sphinx-${_exe}-3" "sphinx-${_exe}" "sphinx-${_exe}.exe") + + if(SPHINX_${_uc}_EXECUTABLE) + execute_process( + COMMAND "${SPHINX_${_uc}_EXECUTABLE}" --version + RESULT_VARIABLE _result + OUTPUT_VARIABLE _output + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_result EQUAL 0 AND _output MATCHES " v?([0-9]+\\.[0-9]+\\.[0-9]+)$") + set(SPHINX_${_uc}_VERSION "${CMAKE_MATCH_1}") + endif() + + if(NOT TARGET Sphinx::${_exe}) + add_executable(Sphinx::${_exe} IMPORTED GLOBAL) + set_target_properties(Sphinx::${_exe} PROPERTIES + IMPORTED_LOCATION "${SPHINX_${_uc}_EXECUTABLE}") + endif() + set(Sphinx_${_exe}_FOUND TRUE) + else() + set(Sphinx_${_exe}_FOUND FALSE) + endif() + unset(_uc) +endmacro() + +macro(_Sphinx_find_extension _ext) + if(_SPHINX_PYTHON_EXECUTABLE) + execute_process( + COMMAND ${_SPHINX_PYTHON_EXECUTABLE} -c "import ${_ext}" + RESULT_VARIABLE _result) + if(_result EQUAL 0) + set(Sphinx_${_ext}_FOUND TRUE) + else() + set(Sphinx_${_ext}_FOUND FALSE) + endif() + elseif(CMAKE_HOST_WIN32 AND SPHINX_BUILD_EXECUTABLE) + # script-build on Windows located under (when PIP is used): + # C:/Program Files/PythonXX/Scripts + # C:/Users/username/AppData/Roaming/Python/PythonXX/Sripts + # + # Python modules are installed under: + # C:/Program Files/PythonXX/Lib + # C:/Users/username/AppData/Roaming/Python/PythonXX/site-packages + # + # To verify a given module is installed, use the Python base directory + # and test if either Lib/module.py or site-packages/module.py exists. + get_filename_component(_dirname "${SPHINX_BUILD_EXECUTABLE}" DIRECTORY) + get_filename_component(_dirname "${_dirname}" DIRECTORY) + if(IS_DIRECTORY "${_dirname}/Lib/${_ext}" OR + IS_DIRECTORY "${_dirname}/site-packages/${_ext}") + set(Sphinx_${_ext}_FOUND TRUE) + else() + set(Sphinx_${_ext}_FOUND FALSE) + endif() + endif() +endmacro() + +# +# Find sphinx-build and sphinx-quickstart. +# +_Sphinx_find_executable(build) +_Sphinx_find_executable(quickstart) + +# +# Verify both executables are part of the Sphinx distribution. +# +if(SPHINX_BUILD_EXECUTABLE AND SPHINX_QUICKSTART_EXECUTABLE) + if(NOT SPHINX_BUILD_VERSION STREQUAL SPHINX_QUICKSTART_VERSION) + message(FATAL_ERROR "Versions for sphinx-build (${SPHINX_BUILD_VERSION}) " + "and sphinx-quickstart (${SPHINX_QUICKSTART_VERSION}) " + "do not match") + endif() +endif() + +# +# To verify the required Sphinx extensions are available, the right Python +# installation must be queried (2 vs 3). Of course, this only makes sense on +# UNIX-like systems. +# +if(NOT CMAKE_HOST_WIN32 AND SPHINX_BUILD_EXECUTABLE) + file(READ "${SPHINX_BUILD_EXECUTABLE}" _contents) + if(_contents MATCHES "^#!([^\n]+)") + string(STRIP "${CMAKE_MATCH_1}" _shebang) + if(EXISTS "${_shebang}") + set(_SPHINX_PYTHON_EXECUTABLE "${_shebang}") + endif() + endif() +endif() + +foreach(_comp IN LISTS Sphinx_FIND_COMPONENTS) + if(_comp STREQUAL "build") + # Do nothing, sphinx-build is always required. + elseif(_comp STREQUAL "quickstart") + # Do nothing, sphinx-quickstart is optional, but looked up by default. + elseif(_comp STREQUAL "breathe") + _Sphinx_find_extension(${_comp}) + else() + message(WARNING "${_comp} is not a valid or supported Sphinx extension") + set(Sphinx_${_comp}_FOUND FALSE) + continue() + endif() +endforeach() + +find_package_handle_standard_args( + Sphinx + VERSION_VAR SPHINX_BUILD_VERSION + REQUIRED_VARS SPHINX_BUILD_EXECUTABLE SPHINX_BUILD_VERSION + HANDLE_COMPONENTS) + + +# Generate a conf.py template file using sphinx-quickstart. +# +# sphinx-quickstart allows for quiet operation and a lot of settings can be +# specified as command line arguments, therefore its not required to parse the +# generated conf.py. +function(_Sphinx_generate_confpy _target _cachedir) + if(NOT TARGET Sphinx::quickstart) + message(FATAL_ERROR "sphinx-quickstart is not available, needed by" + "sphinx_add_docs for target ${_target}") + endif() + + if(NOT DEFINED SPHINX_PROJECT) + set(SPHINX_PROJECT ${PROJECT_NAME}) + endif() + + if(NOT DEFINED SPHINX_AUTHOR) + set(SPHINX_AUTHOR "${SPHINX_PROJECT} committers") + endif() + + if(NOT DEFINED SPHINX_COPYRIGHT) + string(TIMESTAMP "%Y, ${SPHINX_AUTHOR}" SPHINX_COPYRIGHT) + endif() + + if(NOT DEFINED SPHINX_VERSION) + set(SPHINX_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + endif() + + if(NOT DEFINED SPHINX_RELEASE) + set(SPHINX_RELEASE "${PROJECT_VERSION}") + endif() + + if(NOT DEFINED SPHINX_LANGUAGE) + set(SPHINX_LANGUAGE "en") + endif() + + if(NOT DEFINED SPHINX_MASTER) + set(SPHINX_MASTER "index") + endif() + + set(_known_exts autodoc doctest intersphinx todo coverage imgmath mathjax + ifconfig viewcode githubpages) + + if(DEFINED SPHINX_EXTENSIONS) + foreach(_ext ${SPHINX_EXTENSIONS}) + set(_is_known_ext FALSE) + foreach(_known_ext ${_known_exsts}) + if(_ext STREQUAL _known_ext) + set(_opts "${opts} --ext-${_ext}") + set(_is_known_ext TRUE) + break() + endif() + endforeach() + if(NOT _is_known_ext) + if(_exts) + set(_exts "${_exts},${_ext}") + else() + set(_exts "${_ext}") + endif() + endif() + endforeach() + endif() + + if(_exts) + set(_exts "--extensions=${_exts}") + endif() + + set(_templatedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.template") + file(MAKE_DIRECTORY "${_templatedir}") + execute_process( + COMMAND "${SPHINX_QUICKSTART_EXECUTABLE}" + -q --no-makefile --no-batchfile + -p "${SPHINX_PROJECT}" + -a "${SPHINX_AUTHOR}" + -v "${SPHINX_VERSION}" + -r "${SPHINX_RELEASE}" + -l "${SPHINX_LANGUAGE}" + --master "${SPHINX_MASTER}" + ${_opts} ${_exts} "${_templatedir}" + RESULT_VARIABLE _result + OUTPUT_QUIET) + + if(_result EQUAL 0 AND EXISTS "${_templatedir}/conf.py") + file(COPY "${_templatedir}/conf.py" DESTINATION "${_cachedir}") + endif() + + file(REMOVE_RECURSE "${_templatedir}") + + if(NOT _result EQUAL 0 OR NOT EXISTS "${_cachedir}/conf.py") + message(FATAL_ERROR "Sphinx configuration file not generated for " + "target ${_target}") + endif() +endfunction() + +function(sphinx_add_docs _target) + set(_opts) + set(_single_opts BUILDER OUTPUT_DIRECTORY SOURCE_DIRECTORY) + set(_multi_opts BREATHE_PROJECTS) + cmake_parse_arguments(_args "${_opts}" "${_single_opts}" "${_multi_opts}" ${ARGN}) + + unset(SPHINX_BREATHE_PROJECTS) + + if(NOT _args_BUILDER) + message(FATAL_ERROR "Sphinx builder not specified for target ${_target}") + elseif(NOT _args_SOURCE_DIRECTORY) + message(FATAL_ERROR "Sphinx source directory not specified for target ${_target}") + else() + if(NOT IS_ABSOLUTE "${_args_SOURCE_DIRECTORY}") + get_filename_component(_sourcedir "${_args_SOURCE_DIRECTORY}" ABSOLUTE) + else() + set(_sourcedir "${_args_SOURCE_DIRECTORY}") + endif() + if(NOT IS_DIRECTORY "${_sourcedir}") + message(FATAL_ERROR "Sphinx source directory '${_sourcedir}' for" + "target ${_target} does not exist") + endif() + endif() + + set(_builder "${_args_BUILDER}") + if(_args_OUTPUT_DIRECTORY) + set(_outputdir "${_args_OUTPUT_DIRECTORY}") + else() + set(_outputdir "${CMAKE_CURRENT_BINARY_DIR}/${_target}") + endif() + + + if(_args_BREATHE_PROJECTS) + if(NOT Sphinx_breathe_FOUND) + message(FATAL_ERROR "Sphinx extension 'breathe' is not available. Needed" + "by sphinx_add_docs for target ${_target}") + endif() + list(APPEND SPHINX_EXTENSIONS breathe) + + foreach(_doxygen_target ${_args_BREATHE_PROJECTS}) + if(TARGET ${_doxygen_target}) + list(APPEND _depends ${_doxygen_target}) + + # Doxygen targets are supported. Verify that a Doxyfile exists. + get_target_property(_dir ${_doxygen_target} BINARY_DIR) + set(_doxyfile "${_dir}/Doxyfile.${_doxygen_target}") + if(NOT EXISTS "${_doxyfile}") + message(FATAL_ERROR "Target ${_doxygen_target} is not a Doxygen" + "target, needed by sphinx_add_docs for target" + "${_target}") + endif() + + # Read the Doxyfile, verify XML generation is enabled and retrieve the + # output directory. + file(READ "${_doxyfile}" _contents) + if(NOT _contents MATCHES "GENERATE_XML *= *YES") + message(FATAL_ERROR "Doxygen target ${_doxygen_target} does not" + "generate XML, needed by sphinx_add_docs for" + "target ${_target}") + elseif(_contents MATCHES "OUTPUT_DIRECTORY *= *([^ ][^\n]*)") + string(STRIP "${CMAKE_MATCH_1}" _dir) + set(_name "${_doxygen_target}") + set(_dir "${_dir}/xml") + else() + message(FATAL_ERROR "Cannot parse Doxyfile generated by Doxygen" + "target ${_doxygen_target}, needed by" + "sphinx_add_docs for target ${_target}") + endif() + elseif(_doxygen_target MATCHES "([^: ]+) *: *(.*)") + set(_name "${CMAKE_MATCH_1}") + string(STRIP "${CMAKE_MATCH_2}" _dir) + endif() + + if(_name AND _dir) + if(_breathe_projects) + set(_breathe_projects "${_breathe_projects}, \"${_name}\": \"${_dir}\"") + else() + set(_breathe_projects "\"${_name}\": \"${_dir}\"") + endif() + if(NOT _breathe_default_project) + set(_breathe_default_project "${_name}") + endif() + endif() + endforeach() + endif() + + set(_cachedir "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache") + file(MAKE_DIRECTORY "${_cachedir}") + file(MAKE_DIRECTORY "${_cachedir}/_static") + + _Sphinx_generate_confpy(${_target} "${_cachedir}") + + if(_breathe_projects) + file(APPEND "${_cachedir}/conf.py" + "\nbreathe_projects = { ${_breathe_projects} }" + "\nbreathe_default_project = '${_breathe_default_project}'") + endif() + + add_custom_target( + ${_target} + COMMAND ${SPHINX_BUILD_EXECUTABLE} + -b ${_builder} + -d "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache/_doctrees" + -c "${CMAKE_CURRENT_BINARY_DIR}/${_target}.cache" + "${_sourcedir}" + "${_outputdir}" + DEPENDS ${_depends}) +endfunction() + diff --git a/cmake/Modules/GenerateDummyExportHeader.cmake b/cmake/Modules/GenerateDummyExportHeader.cmake new file mode 100644 index 0000000..8a26e15 --- /dev/null +++ b/cmake/Modules/GenerateDummyExportHeader.cmake @@ -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() + diff --git a/src/cmake/modules/Glob.cmake b/cmake/Modules/Glob.cmake similarity index 100% rename from src/cmake/modules/Glob.cmake rename to cmake/Modules/Glob.cmake diff --git a/src/cmake/modules/Packaging.cmake b/cmake/Modules/Packaging.cmake similarity index 74% rename from src/cmake/modules/Packaging.cmake rename to cmake/Modules/Packaging.cmake index 9f0e53d..da2d7d6 100644 --- a/src/cmake/modules/Packaging.cmake +++ b/cmake/Modules/Packaging.cmake @@ -17,14 +17,21 @@ set(PACKAGING_INCLUDED true) include(CMakePackageConfigHelpers) include(GNUInstallDirs) -set(PACKAGING_MODULE_DIR "${PROJECT_SOURCE_DIR}/cmake/modules/Packaging") +set(PACKAGING_MODULE_DIR "${PROJECT_SOURCE_DIR}/cmake/Modules/Packaging") set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}") # Generates Config.cmake. -configure_package_config_file( - "${PACKAGING_MODULE_DIR}/PackageConfig.cmake.in" - "${CMAKE_PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") +if(BUILD_IDLC) + configure_package_config_file( + "${PACKAGING_MODULE_DIR}/PackageConfig.cmake.in" + "${CMAKE_PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") +else() + configure_package_config_file( + "${PACKAGING_MODULE_DIR}/PackageConfigNoIdlc.cmake.in" + "${CMAKE_PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") +endif() # Generates Version.cmake. write_basic_package_version_file( @@ -37,7 +44,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 Targets.cmake file included by Config.cmake. # The files are placed in CMakeFiles/Export in the build tree. install( @@ -54,15 +61,13 @@ set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION_TWEAK ${PROJECT_VERSION_TWEAK}) set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) -set(VENDOR_INSTALL_ROOT "ADLINK") set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) -set(CPACK_PACKAGE_VENDOR "ADLINK Technology Inc.") -set(CPACK_PACKAGE_CONTACT "${CMAKE_PROJECT_NAME} core developers ") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Leading OMG DDS implementation from ADLINK Technology") -set(CPACK_PACKAGE_ICON "${PACKAGING_MODULE_DIR}/vortex.ico") +set(CPACK_PACKAGE_VENDOR "Eclipse Cyclone DDS project") +set(CPACK_PACKAGE_CONTACT "https://github.com/eclipse-cyclonedds/cyclonedds") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Implementation of the OMG DDS standard") # WiX requires a .txt file extension for CPACK_RESOURCE_FILE_LICENSE -file(COPY "${PROJECT_SOURCE_DIR}/../LICENSE" DESTINATION "${CMAKE_BINARY_DIR}") +file(COPY "${PROJECT_SOURCE_DIR}/LICENSE" DESTINATION "${CMAKE_BINARY_DIR}") file(RENAME "${CMAKE_BINARY_DIR}/LICENSE" "${CMAKE_BINARY_DIR}/license.txt") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/license.txt") @@ -95,24 +100,7 @@ if(WIN32 AND NOT UNIX) set(CPACK_GENERATOR "WIX;ZIP;${CPACK_GENERATOR}" CACHE STRING "List of package generators") set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}-${__arch}") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "${VENDOR_INSTALL_ROOT}/${CMAKE_PROJECT_NAME_FULL}") - - set(CPACK_WIX_LIGHT_EXTENSIONS "WixUtilExtension") - set(CPACK_WIX_COMPONENT_INSTALL ON) - set(CPACK_WIX_ROOT_FEATURE_TITLE "${CMAKE_PROJECT_NAME_FULL}") - set(CPACK_WIX_PRODUCT_ICON "${PACKAGING_MODULE_DIR}/vortex.ico") - # Bitmap (.bmp) of size 493x58px - set(CPACK_WIX_UI_BANNER "${PACKAGING_MODULE_DIR}/banner.bmp") - # Bitmap (.bmp) of size 493x312px - set(CPACK_WIX_UI_DIALOG "${PACKAGING_MODULE_DIR}/dialog.png") - set(CPACK_WIX_PROGRAM_MENU_FOLDER "${CPACK_PACKAGE_NAME_FULL}") - set(CPACK_WIX_PATCH_FILE "${PACKAGING_MODULE_DIR}/examples.xml") - set(CPACK_WIX_PROPERTY_ARPHELPLINK "http://www.adlinktech.com/support") - set(CPACK_WIX_PROPERTY_ARPURLINFOABOUT "http://www.adlinktech.com/") - set(CPACK_WIX_PROPERTY_ARPURLUPDATEINFO "http://www.adlinktech.com/") - - # A constant GUID allows installers to replace existing installations that use the same GUID. - set(CPACK_WIX_UPGRADE_GUID "1351F59A-972B-4624-A7F1-439381BFA41D") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_PROJECT_NAME_FULL}") include(InstallRequiredSystemLibraries) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -159,10 +147,9 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") # Generic tgz package set(CPACK_GENERATOR "TGZ;${CPACK_GENERATOR}" CACHE STRING "List of package generators") endif() -elseif(CMAKE_SYSTEM_NAME MATCHES "VxWorks") - # FIXME: Support for VxWorks packages must still be implemented (probably - # just a compressed tarball) - message(STATUS "Packaging for VxWorks is unsupported") +else() + # Fallback to zip package + set(CPACK_GENERATOR "ZIP;${CPACK_GENERATOR}" CACHE STRING "List of package generators") endif() # This must always be last! diff --git a/src/cmake/modules/Packaging/PackageConfig.cmake.in b/cmake/Modules/Packaging/PackageConfig.cmake.in similarity index 99% rename from src/cmake/modules/Packaging/PackageConfig.cmake.in rename to cmake/Modules/Packaging/PackageConfig.cmake.in index 330d39c..a1b8344 100644 --- a/src/cmake/modules/Packaging/PackageConfig.cmake.in +++ b/cmake/Modules/Packaging/PackageConfig.cmake.in @@ -13,4 +13,3 @@ include("${CMAKE_CURRENT_LIST_DIR}/@CMAKE_PROJECT_NAME@Targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake") - diff --git a/src/etc/CMakeLists.txt b/cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in similarity index 60% rename from src/etc/CMakeLists.txt rename to cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in index 8bba5af..415b481 100644 --- a/src/etc/CMakeLists.txt +++ b/cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in @@ -9,12 +9,6 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -configure_file("cmake/default.xml.in" "${CMAKE_PROJECT_NAME_SMALL}.xml" @ONLY) +@PACKAGE_INIT@ -set(CONFIG_FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME_SMALL}.xml") - -install( - FILES ${CONFIG_FILES} - DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/${CMAKE_PROJECT_NAME}" - COMPONENT lib -) +include("${CMAKE_CURRENT_LIST_DIR}/@CMAKE_PROJECT_NAME@Targets.cmake") diff --git a/colcon.pkg b/colcon.pkg new file mode 100644 index 0000000..043b26c --- /dev/null +++ b/colcon.pkg @@ -0,0 +1,3 @@ +{ + "name": "cyclonedds" +} diff --git a/src/scripts/CMakeLists.txt b/docs/CMakeLists.txt similarity index 50% rename from src/scripts/CMakeLists.txt rename to docs/CMakeLists.txt index 6c82db7..fa1b946 100644 --- a/src/scripts/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0 which is available at @@ -8,14 +8,5 @@ # http://www.eclipse.org/org/documents/edl-v10.php. # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# - -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - configure_file( - "cmake/vdds_install_examples.in" "vdds_install_examples" @ONLY) - - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/vdds_install_examples - DESTINATION "${CMAKE_INSTALL_BINDIR}" - COMPONENT dev) -endif() +add_subdirectory(manual) diff --git a/notes/data path - rbuf.svg b/docs/dev/data path - rbuf.svg similarity index 100% rename from notes/data path - rbuf.svg rename to docs/dev/data path - rbuf.svg diff --git a/notes/data path - receive.svg b/docs/dev/data path - receive.svg similarity index 100% rename from notes/data path - receive.svg rename to docs/dev/data path - receive.svg diff --git a/notes/data path - transmit.svg b/docs/dev/data path - transmit.svg similarity index 100% rename from notes/data path - transmit.svg rename to docs/dev/data path - transmit.svg diff --git a/notes/data path.graffle b/docs/dev/data path.graffle similarity index 100% rename from notes/data path.graffle rename to docs/dev/data path.graffle diff --git a/docs/dev/freertos.md b/docs/dev/freertos.md new file mode 100644 index 0000000..e877f4b --- /dev/null +++ b/docs/dev/freertos.md @@ -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. + diff --git a/docs/manual/CMakeLists.txt b/docs/manual/CMakeLists.txt new file mode 100644 index 0000000..de5d686 --- /dev/null +++ b/docs/manual/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +if(BUILD_DOCS) + find_package(Sphinx REQUIRED breathe) + sphinx_add_docs( + docs + BREATHE_PROJECTS ddsc_api_docs + BUILDER html + SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + install( + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/docs/" + DESTINATION "${CMAKE_INSTALL_DOCDIR}/manual" + COMPONENT dev) +endif() + diff --git a/src/docs/GettingStartedGuide/helloworld.rst b/docs/manual/GettingStartedGuide/helloworld.rst similarity index 99% rename from src/docs/GettingStartedGuide/helloworld.rst rename to docs/manual/GettingStartedGuide/helloworld.rst index 3b0169f..c2c7862 100644 --- a/src/docs/GettingStartedGuide/helloworld.rst +++ b/docs/manual/GettingStartedGuide/helloworld.rst @@ -195,7 +195,7 @@ example. Apart from the native build files, CMake build files are provided as well. See :code:`examples/helloworld/CMakeLists.txt` -.. literalinclude:: ../../examples/helloworld/CMakeLists.export +.. literalinclude:: ../../../examples/helloworld/CMakeLists.export :linenos: :language: cmake diff --git a/src/docs/GettingStartedGuide/helloworld_indepth.rst b/docs/manual/GettingStartedGuide/helloworld_indepth.rst similarity index 98% rename from src/docs/GettingStartedGuide/helloworld_indepth.rst rename to docs/manual/GettingStartedGuide/helloworld_indepth.rst index 94a4575..8313290 100644 --- a/src/docs/GettingStartedGuide/helloworld_indepth.rst +++ b/docs/manual/GettingStartedGuide/helloworld_indepth.rst @@ -77,7 +77,7 @@ There are a few ways to describe the structures that make up the data layer. The HelloWorld uses the IDL language to describe the data type in HelloWorldData.idl: -.. literalinclude:: ../../examples/helloworld/HelloWorldData.idl +.. literalinclude:: ../../../examples/helloworld/HelloWorldData.idl :linenos: :language: idl @@ -202,7 +202,7 @@ business logic. Subscriber.c contains the source that will wait for a *Hello World!* message and reads it when it receives one. -.. literalinclude:: ../../examples/helloworld/subscriber.c +.. literalinclude:: ../../../examples/helloworld/subscriber.c :linenos: :language: c @@ -331,7 +331,7 @@ automatically delete the topic and reader as well. Publisher.c contains the source that will write an *Hello World!* message on which the subscriber is waiting. -.. literalinclude:: ../../examples/helloworld/publisher.c +.. literalinclude:: ../../../examples/helloworld/publisher.c :linenos: :language: c diff --git a/src/docs/GettingStartedGuide/index.rst b/docs/manual/GettingStartedGuide/index.rst similarity index 100% rename from src/docs/GettingStartedGuide/index.rst rename to docs/manual/GettingStartedGuide/index.rst diff --git a/src/docs/GettingStartedGuide/installation.rst b/docs/manual/GettingStartedGuide/installation.rst similarity index 100% rename from src/docs/GettingStartedGuide/installation.rst rename to docs/manual/GettingStartedGuide/installation.rst diff --git a/src/docs/GettingStartedGuide/next_steps.rst b/docs/manual/GettingStartedGuide/next_steps.rst similarity index 100% rename from src/docs/GettingStartedGuide/next_steps.rst rename to docs/manual/GettingStartedGuide/next_steps.rst diff --git a/src/docs/GettingStartedGuide/uninstall.rst b/docs/manual/GettingStartedGuide/uninstall.rst similarity index 100% rename from src/docs/GettingStartedGuide/uninstall.rst rename to docs/manual/GettingStartedGuide/uninstall.rst diff --git a/src/docs/_static/BuildSchema.odg b/docs/manual/_static/BuildSchema.odg similarity index 100% rename from src/docs/_static/BuildSchema.odg rename to docs/manual/_static/BuildSchema.odg diff --git a/src/docs/_static/pictures/BuildSchema.png b/docs/manual/_static/pictures/BuildSchema.png similarity index 100% rename from src/docs/_static/pictures/BuildSchema.png rename to docs/manual/_static/pictures/BuildSchema.png diff --git a/src/docs/_static/pictures/HelloworldPublisherWindows.png b/docs/manual/_static/pictures/HelloworldPublisherWindows.png similarity index 100% rename from src/docs/_static/pictures/HelloworldPublisherWindows.png rename to docs/manual/_static/pictures/HelloworldPublisherWindows.png diff --git a/src/docs/_static/pictures/HelloworldSubscriberWindows.png b/docs/manual/_static/pictures/HelloworldSubscriberWindows.png similarity index 100% rename from src/docs/_static/pictures/HelloworldSubscriberWindows.png rename to docs/manual/_static/pictures/HelloworldSubscriberWindows.png diff --git a/src/docs/_static/pictures/settings-icon.png b/docs/manual/_static/pictures/settings-icon.png similarity index 100% rename from src/docs/_static/pictures/settings-icon.png rename to docs/manual/_static/pictures/settings-icon.png diff --git a/src/docs/config.rst b/docs/manual/config.rst similarity index 100% rename from src/docs/config.rst rename to docs/manual/config.rst diff --git a/src/docs/ddsc.rst b/docs/manual/ddsc.rst similarity index 95% rename from src/docs/ddsc.rst rename to docs/manual/ddsc.rst index 8df7fba..6c065fc 100644 --- a/src/docs/ddsc.rst +++ b/docs/manual/ddsc.rst @@ -13,4 +13,4 @@ Eclipse Cyclone DDS C API Reference =================================== .. doxygenindex:: - :project: ddsc_api + :project: ddsc_api_docs diff --git a/src/docs/index.rst b/docs/manual/index.rst similarity index 100% rename from src/docs/index.rst rename to docs/manual/index.rst diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..2129d74 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,29 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +set(CMAKE_INSTALL_EXAMPLESDIR "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/examples") + +add_subdirectory(helloworld) +add_subdirectory(roundtrip) +add_subdirectory(throughput) + +if (BUILD_DOCS) + find_package(Sphinx REQUIRED) + sphinx_add_docs( + examples_docs + BUILDER html + SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + install( + DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/examples_docs/" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}" + COMPONENT dev + PATTERN "_sources" EXCLUDE) +endif() diff --git a/src/examples/helloworld/CMakeLists.export b/examples/helloworld/CMakeLists.export similarity index 100% rename from src/examples/helloworld/CMakeLists.export rename to examples/helloworld/CMakeLists.export diff --git a/examples/helloworld/CMakeLists.txt b/examples/helloworld/CMakeLists.txt new file mode 100644 index 0000000..b34e174 --- /dev/null +++ b/examples/helloworld/CMakeLists.txt @@ -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 +# +idlc_generate(HelloWorldData_lib "HelloWorldData.idl") + +add_executable(HelloworldPublisher publisher.c) +add_executable(HelloworldSubscriber subscriber.c) + +target_link_libraries(HelloworldPublisher HelloWorldData_lib CycloneDDS::ddsc) +target_link_libraries(HelloworldSubscriber HelloWorldData_lib CycloneDDS::ddsc) + +install( + FILES + "HelloWorldData.idl" + "publisher.c" + "subscriber.c" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld" + COMPONENT dev) + +install( + FILES "CMakeLists.export" + RENAME "CMakeLists.txt" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld" + COMPONENT dev) + diff --git a/src/examples/helloworld/HelloWorldData.idl b/examples/helloworld/HelloWorldData.idl similarity index 100% rename from src/examples/helloworld/HelloWorldData.idl rename to examples/helloworld/HelloWorldData.idl diff --git a/src/examples/helloworld/publisher.c b/examples/helloworld/publisher.c similarity index 100% rename from src/examples/helloworld/publisher.c rename to examples/helloworld/publisher.c diff --git a/src/examples/helloworld/readme.rst b/examples/helloworld/readme.rst similarity index 100% rename from src/examples/helloworld/readme.rst rename to examples/helloworld/readme.rst diff --git a/src/examples/helloworld/subscriber.c b/examples/helloworld/subscriber.c similarity index 100% rename from src/examples/helloworld/subscriber.c rename to examples/helloworld/subscriber.c diff --git a/src/examples/examples.rst b/examples/index.rst similarity index 100% rename from src/examples/examples.rst rename to examples/index.rst diff --git a/performance/ethload b/examples/perfscript/ethload similarity index 100% rename from performance/ethload rename to examples/perfscript/ethload diff --git a/examples/perfscript/latency-test b/examples/perfscript/latency-test new file mode 100755 index 0000000..ead88ef --- /dev/null +++ b/examples/perfscript/latency-test @@ -0,0 +1,153 @@ +#!/bin/bash + +export nwif=eth0 +bandwidth=1e9 +remotedir="$PWD" +provision=false +asynclist="sync async" +modelist="listener waitset" +sizelist="0 20 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1000000" +timeout=30 +loopback=true +resultdir="latency-result" + +usage () { + cat >&2 <$cfg < + + 17 + + + $nwif + $loopback + 65500B + 4000B + + + + 500kB + + \${async:-0} + 3s + + + config + + +EOF + +if [ ! -x bin/ddsperf ] ; then + echo "bin/ddsperf not found on the local machine" >&2 + exit 1 +fi + +[ -d $resultdir ] || { echo "output directory $resultdir doesn't exist" >&2 ; exit 1 ; } + +if $provision ; then + echo "provisioning ..." + for r in $pubremote "$@" ; do + ssh $r mkdir -p $remotedir $remotedir/bin $remotedir/lib + scp lib/libddsc.so.0 $r:$remotedir/lib + scp bin/ddsperf $r:$remotedir/bin + done +fi + +topic=KS +[ -z "$sizelist" ] && topic=OU + +export CYCLONEDDS_URI=file://$PWD/$cfg +for r in "$@" ; do + scp $cfg $r:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 1 ; } +done + +for async_mode in $asynclist ; do + case "$async_mode" in + sync) async=0 ;; + async) async=1 ;; + *) echo "$async_mode: invalid setting for ASYNC" >&2 ; continue ;; + esac + export async + for sub_mode in $modelist ; do + echo "======== ASYNC $async MODE $sub_mode =========" + + + cat > run-pong.tmp < /dev/null & +echo \$! +EOF + killpongs="" + for r in "$@" ; do + scp run-pong.tmp $r:$remotedir + rpongpid=`ssh $r ". $remotedir/run-pong.tmp"` + killpongs="$killpongs ssh $r kill -9 $rpongpid &" + done + + outdir=$resultdir/$async_mode-$sub_mode + mkdir $outdir + + touch $outdir/ping.log + tail -f $outdir/ping.log & xpid=$! + for size in ${sizelist:-0} ; do + echo "size $size" + bin/ddsperf -d $nwif:$bandwidth -c -D $timeout -T $topic ping size $size $sub_mode >> $outdir/ping.log + sleep 5 + done + eval $killpongs + sleep 1 + kill $xpid + wait + done +done diff --git a/examples/perfscript/latency-test-extract b/examples/perfscript/latency-test-extract new file mode 100755 index 0000000..b665e88 --- /dev/null +++ b/examples/perfscript/latency-test-extract @@ -0,0 +1,95 @@ +#!/usr/bin/perl -w + +# Note: this is specialized for async delivery, listener mode because of the way it deals with +# thread names + +use strict; + +my %res = (); +my %meas; +while (<>) { + next unless s/^\[\d+\] \d+\.\d+\s+//; + if (s/^[^\@:]+:\d+\s+size (\d+) //) { + # size is always the first line of an output block + # ddsperf doesn't print CPU loads, RSS, bandwidth if it is zero + my %tmp = %meas; + push @{$res{$meas{size}}}, \%tmp if %meas; + %meas = (size => $1, + rawxmitbw => 0, rawrecvbw => 0, + subrss => 0, pubrss => 0, + subcpu => 0, subrecv => 0, + pubcpu => 0, pubrecv => 0); + $meas{$1} = $2 while s/^(mean|min|max|\d+%)\s+(\d+\.\d+)us\s*//; + die unless /cnt \d+$/; + } elsif (s/^(\@[^:]+:\d+\s+)?rss:(\d+\.\d+)([kM])B//) { + my $side = defined $1 ? "pub" : "sub"; + $meas{"${side}rss"} = $2 / ($3 eq "k" ? 1024.0 : 1); + $meas{"${side}cpu"} = cpuload (($side eq "pub") ? "pub" : "dq.user", $_); + $meas{"${side}recv"} = cpuload ("recvUC", $_); + } elsif (/xmit\s+(\d+)%\s+recv\s+(\d+)%/) { + $meas{rawxmitbw} = $1; + $meas{rawrecvbw} = $2; + } +} +push @{$res{$meas{size}}}, \%meas if %meas; +die "no data found" unless keys %res > 0; + +print "#size mean min 50% 90% 99% max rawxmitbw rawrecvbw pubrss subrss pubcpu pubrecv subcpu subrecv\n"; +my @sizes = sort { $a <=> $b } keys %res; +for my $sz (@sizes) { + my $ms = $res{$sz}; + my $min = min ("min", $ms); + my $max = max ("max", $ms); + my $mean = mean ("mean", $ms); # roughly same number of roundtrips, so not too far off + my $median = max ("50%", $ms); # also not quite correct ... + my $p90 = max ("90%", $ms); + my $p99 = max ("99%", $ms); + my $rawxmitbw = median ("rawxmitbw", $ms); + my $rawrecvbw = median ("rawrecvbw", $ms); + my $pubrss = max ("pubrss", $ms); + my $subrss = max ("subrss", $ms); + my $pubcpu = median ("pubcpu", $ms); + my $pubrecv = median ("pubrecv", $ms); + my $subcpu = median ("subcpu", $ms); + my $subrecv = median ("subrecv", $ms); + print "$sz $mean $min $median $p90 $p99 $max $rawxmitbw $rawrecvbw $pubrss $subrss $pubcpu $pubrecv $subcpu $subrecv\n"; +} + +sub cpuload { + my ($thread, $line) = @_; + $thread =~ s/\./\\./g; + if ($line =~ /$thread:(\d+)%\+(\d+)%/) { + return $1+$2; + } else { + return 0; + } +} + +sub max { + my $v; + for (extract (@_)) { $v = $_ unless defined $v; $v = $_ if $_ > $v; } + return $v; +} + +sub min { + my $v; + for (extract (@_)) { $v = $_ unless defined $v; $v = $_ if $_ < $v; } + return $v; +} + +sub mean { + my $v = 0; + my @xs = extract (@_); + $v += $_ for @xs; + return $v / @xs; +} + +sub median { + my @xs = sort { $a <=> $b } (extract (@_)); + return (@xs % 2) ? $xs[(@xs - 1) / 2] : ($xs[@xs/2 - 1] + $xs[@xs/2]) / 2; +} + +sub extract { + my ($key, $msref) = @_; + return map { $_->{$key} } @$msref; +} diff --git a/examples/perfscript/latency-test-plot b/examples/perfscript/latency-test-plot new file mode 100755 index 0000000..d7217a2 --- /dev/null +++ b/examples/perfscript/latency-test-plot @@ -0,0 +1,46 @@ +#!/bin/bash + +`dirname $0`/latency-test-extract "$@" > data.txt +gnuplot <<\EOF +set term pngcairo size 1024,768 +set output "latency-sync-listener.png" +set st d lp +set st li 1 lw 2 +set st li 2 lw 2 +set st li 3 lw 2 +set st li 4 lw 2 +set st li 5 lw 2 + +set multiplot +set logscale xy +set title "Latency" +set ylabel "[us]" +set grid xtics ytics mytics +set xlabel "payload size [bytes]" +p "data.txt" u 1:3 ti "min", "" u 1:4 ti "median", "" u 1:5 ti "90%", "" u 1:6 ti "99%", "" u 1:7 ti "max" +unset logscale y +unset xlabel +unset ylabel +unset title +set grid nomytics +set origin .1, .43 +set size .55, .5 +clear +p [10:1000] "data.txt" u 1:3 ti "min", "" u 1:4 ti "median", "" u 1:5 ti "90%", "" u 1:6 ti "99%", "" u 1:7 ti "max" +unset multiplot + +unset origin +unset size + +unset logscale +set logscale x +set output "latency-sync-listener-bwcpu.png" +set title "Latency: network bandwidth and CPU usage" +set y2tics +set ylabel "[Mbps]" +set y2label "CPU [%]" +set xlabel "payload size [bytes]" +set key at graph 1, 0.7 +p "data.txt" u 1:(10*$8) ti "GbE transmit bandwidth (left)", "" u 1:(10*$9) ti "GbE receive bandwidth (left)", "" u 1:13 axes x1y2 ti "ping CPU (right)", "" u 1:15 axes x1y2 ti "pong CPU (right)" + +EOF diff --git a/examples/perfscript/quick-microbenchmark b/examples/perfscript/quick-microbenchmark new file mode 100644 index 0000000..3150bcf --- /dev/null +++ b/examples/perfscript/quick-microbenchmark @@ -0,0 +1,30 @@ +export CYCLONEDDS_URI='250kB65500B65000B' +set -x +gen/ddsperf -D20 -L ping pon +for x in 16 32 64 128 1024 4096 16384 ; do + gen/ddsperf -D20 -TKS -z$x -L ping pong +done +gen/ddsperf -D20 -L pub sub +for x in 16 32 64 128 1024 4096 16384 ; do + gen/ddsperf -D20 -TKS -z$x -L pub sub +done +gen/ddsperf pong & pid=$! +gen/ddsperf -D20 ping +kill $pid +wait +gen/ddsperf -TKS pong & pid=$! +for x in 16 32 64 128 1024 4096 16384 ; do + gen/ddsperf -D20 -TKS -z$x ping +done +kill $pid +wait +gen/ddsperf sub & pid=$! +gen/ddsperf -D20 pub +kill $pid +wait +gen/ddsperf -TKS sub & pid=$! +for x in 16 32 64 128 1024 4096 16384 ; do + gen/ddsperf -D20 -TKS -z$x pub +done +kill $pid +wait diff --git a/performance/throughput-fanout-test b/examples/perfscript/throughput-fanout-test similarity index 100% rename from performance/throughput-fanout-test rename to examples/perfscript/throughput-fanout-test diff --git a/examples/perfscript/throughput-test b/examples/perfscript/throughput-test new file mode 100755 index 0000000..d654056 --- /dev/null +++ b/examples/perfscript/throughput-test @@ -0,0 +1,167 @@ +#!/bin/bash + +export nwif=eth0 +bandwidth=1e9 +remotedir="$PWD" +provision=false +asynclist="sync async" +modelist="listener polling waitset" +sizelist="0 20 50 100 200 500 1000 2000 5000 10000 20000 50000 100000 200000 500000 1000000" +timeout=30 +loopback=true +resultdir="throughput-result" + +usage () { + cat >&2 <$cfg < + + 17 + + + $nwif + $loopback + 65500B + 4000B + + + + 500kB + + \${async:-0} + 3s + + + config + + +EOF + +if [ ! -x bin/ddsperf ] ; then + echo "bin/ddsperf not found on the local machine" >&2 + exit 1 +fi + +[ -d $resultdir ] || { echo "output directory $resultdir doesn't exist" >&2 ; exit 1 ; } + +if $provision ; then + echo "provisioning ..." + for r in $pubremote "$@" ; do + ssh $r mkdir -p $remotedir $remotedir/bin $remotedir/lib + scp lib/libddsc.so.0 $r:$remotedir/lib + scp bin/ddsperf $r:$remotedir/bin + done +fi + +topic=KS +[ -z "$sizelist" ] && topic=OU + +export CYCLONEDDS_URI=file://$PWD/$cfg +for r in $pubremote "$@" ; do + scp $cfg $r:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 1 ; } +done + +for async_mode in $asynclist ; do + case "$async_mode" in + sync) async=0 ;; + async) async=1 ;; + *) echo "$async_mode: invalid setting for ASYNC" >&2 ; continue ;; + esac + export async + for sub_mode in $modelist ; do + echo "======== ASYNC $async MODE $sub_mode =========" + + cat > run-publisher.tmp < pub.log + sleep 5 +done +wait +EOF + scp run-publisher.tmp $pubremote:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 2 ; } + killremotesubs="" + if [ $# -gt 0 ] ; then + cat > run-subscriber.tmp < /dev/null & +echo \$! +EOF + for r in "$@" ; do + scp run-subscriber.tmp $r:$remotedir + rsubpid=`ssh $r ". $remotedir/run-subscriber.tmp"` + killremotesubs="$killremotesubs ssh $r kill -9 $rsubpid &" + done + fi + + outdir=$resultdir/$async_mode-$sub_mode + mkdir $outdir + + bin/ddsperf -d $nwif:$bandwidth -c -T $topic sub $sub_mode > $outdir/sub.log & spid=$! + tail -f $outdir/sub.log & xpid=$! + ssh $pubremote ". $remotedir/run-publisher.tmp" + kill $spid + eval $killremotesubs + sleep 1 + kill $xpid + wait + scp $pubremote:$remotedir/pub.log $outdir + done +done diff --git a/examples/perfscript/throughput-test-extract b/examples/perfscript/throughput-test-extract new file mode 100755 index 0000000..973f397 --- /dev/null +++ b/examples/perfscript/throughput-test-extract @@ -0,0 +1,76 @@ +#!/usr/bin/perl -w + +# Note: this is specialized for async delivery, listener mode because of the way it deals with +# thread names + +use strict; + +my %res = (); +my %meas; +while (<>) { + next unless s/^\[\d+\] \d+\.\d+\s+//; + if (/^size (\d+) .* rate (\d+\.\d+)\s*kS\/s\s+(\d+\.\d+)\s*Mb\/s/) { + # size is always the first line of an output block + # ddsperf doesn't print CPU loads, RSS, bandwidth if it is zero + my %tmp = %meas; + push @{$res{$meas{size}}}, \%tmp if %meas; + %meas = (size => $1, rate => $2, cookedbw => $3, + rawxmitbw => 0, rawrecvbw => 0, + subrss => 0, pubrss => 0, + subcpu => 0, subrecv => 0, + pubcpu => 0, pubrecv => 0); + } elsif (s/^(\@[^:]+:\d+\s+)?rss:(\d+\.\d+)([kM])B//) { + my $side = defined $1 ? "pub" : "sub"; + $meas{"${side}rss"} = $2 / ($3 eq "k" ? 1024.0 : 1); + $meas{"${side}cpu"} = cpuload (($side eq "pub") ? "pub" : "dq.user", $_); + $meas{"${side}recv"} = cpuload ("recvUC", $_); + } elsif (/xmit\s+(\d+)%\s+recv\s+(\d+)%/) { + $meas{rawxmitbw} = $1; + $meas{rawrecvbw} = $2; + } +} +push @{$res{$meas{size}}}, \%meas if %meas; +die "no data found" unless keys %res > 0; + +print "#size rate cookedbw rawxmitbw rawrecvbw pubrss subrss pubcpu pubrecv subcpu subrecv\n"; +my @sizes = sort { $a <=> $b } keys %res; +for my $sz (@sizes) { + my $ms = $res{$sz}; + my $rate = median ("rate", $ms); + my $cookedbw = median ("cookedbw", $ms); + my $rawxmitbw = median ("rawxmitbw", $ms); + my $rawrecvbw = median ("rawrecvbw", $ms); + my $pubrss = max ("pubrss", $ms); + my $subrss = max ("subrss", $ms); + my $pubcpu = median ("pubcpu", $ms); + my $pubrecv = median ("pubrecv", $ms); + my $subcpu = median ("subcpu", $ms); + my $subrecv = median ("subrecv", $ms); + print "$sz $rate $cookedbw $rawxmitbw $rawrecvbw $pubrss $subrss $pubcpu $pubrecv $subcpu $subrecv\n"; +} + +sub cpuload { + my ($thread, $line) = @_; + $thread =~ s/\./\\./g; + if ($line =~ /$thread:(\d+)%\+(\d+)%/) { + return $1+$2; + } else { + return 0; + } +} + +sub max { + my $v; + for (extract (@_)) { $v = $_ unless defined $v; $v = $_ if $_ > $v; } + return $v; +} + +sub median { + my @xs = sort { $a <=> $b } (extract (@_)); + return (@xs % 2) ? $xs[(@xs - 1) / 2] : ($xs[@xs/2 - 1] + $xs[@xs/2]) / 2; +} + +sub extract { + my ($key, $msref) = @_; + return map { $_->{$key} } @$msref; +} diff --git a/examples/perfscript/throughput-test-plot b/examples/perfscript/throughput-test-plot new file mode 100755 index 0000000..0e0157f --- /dev/null +++ b/examples/perfscript/throughput-test-plot @@ -0,0 +1,55 @@ +#!/bin/bash + +`dirname $0`/throughput-test-extract "$@" > data.txt +gnuplot <<\EOF +set term pngcairo size 1024,768 +set output "throughput-async-listener-rate.png" +set st d lp +set st li 1 lw 2 +set st li 2 lw 2 +set st li 3 lw 2 + +set multiplot +set logscale xyy2 +set title "Throughput" +set ylabel "[Mbps]" +set ytics (100,200,300,400,500,600,700,800,900,1000) +set grid xtics ytics mytics +set xlabel "payload size [bytes]" +# sample rate in data.txt is in kS/s +# GbE bandwidth in data.txt is in %, so 100% => 1000 Mbps +set key at graph 1, 0.9 +p "data.txt" u 1:3 ti "payload", "" u 1:(10*$5) ti "GbE bandwidth" +set ytics auto +set key default + +unset xlabel +unset title +set grid nomytics +set ylabel "[M sample/s]" +set origin .3, .1 +set size .6, .6 +clear +p "data.txt" u 1:($2/1e3) ti "rate" +unset multiplot + +unset origin +unset size + +unset logscale +set logscale x +set output "throughput-async-listener-memory.png" +set title "Throughput: memory" +set ylabel "RSS [MB]" +set xlabel "payload size [bytes]" +p "data.txt" u 1:6 ti "publisher", "" u 1:7 ti "subscriber" + +unset logscale +set logscale x +set output "throughput-async-listener-cpu.png" +set title "Throughput: CPU" +set ylabel "CPU [%]" +set xlabel "payload size [bytes]" +p "data.txt" u 1:8 ti "publisher (pub thread)", "" u 1:9 ti "publisher (recvUC thread)", "" u 1:10 ti "subscriber (dq.user thread)", "" u 1:11 ti "subscriber (recvUC thread)" + +EOF diff --git a/src/examples/roundtrip/CMakeLists.txt b/examples/roundtrip/CMakeLists.export similarity index 100% rename from src/examples/roundtrip/CMakeLists.txt rename to examples/roundtrip/CMakeLists.export diff --git a/examples/roundtrip/CMakeLists.txt b/examples/roundtrip/CMakeLists.txt new file mode 100644 index 0000000..9afe648 --- /dev/null +++ b/examples/roundtrip/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# 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 +# +idlc_generate(RoundTrip_lib RoundTrip.idl) + +add_executable(RoundtripPing ping.c) +add_executable(RoundtripPong pong.c) + +target_link_libraries(RoundtripPing RoundTrip_lib CycloneDDS::ddsc) +target_link_libraries(RoundtripPong RoundTrip_lib CycloneDDS::ddsc) + +install( + FILES + "RoundTrip.idl" + "ping.c" + "pong.c" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/roundtrip" + COMPONENT dev) + +install( + FILES "CMakeLists.export" + RENAME "CMakeLists.txt" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/roundtrip" + COMPONENT dev) diff --git a/src/examples/roundtrip/RoundTrip.idl b/examples/roundtrip/RoundTrip.idl similarity index 100% rename from src/examples/roundtrip/RoundTrip.idl rename to examples/roundtrip/RoundTrip.idl diff --git a/src/examples/roundtrip/ping.c b/examples/roundtrip/ping.c similarity index 99% rename from src/examples/roundtrip/ping.c rename to examples/roundtrip/ping.c index 9b09c3a..d24541e 100644 --- a/src/examples/roundtrip/ping.c +++ b/examples/roundtrip/ping.c @@ -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 diff --git a/src/examples/roundtrip/pong.c b/examples/roundtrip/pong.c similarity index 98% rename from src/examples/roundtrip/pong.c rename to examples/roundtrip/pong.c index 010c0c5..992ba75 100644 --- a/src/examples/roundtrip/pong.c +++ b/examples/roundtrip/pong.c @@ -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 diff --git a/src/examples/roundtrip/readme.rst b/examples/roundtrip/readme.rst similarity index 100% rename from src/examples/roundtrip/readme.rst rename to examples/roundtrip/readme.rst diff --git a/src/examples/throughput/CMakeLists.txt b/examples/throughput/CMakeLists.export similarity index 100% rename from src/examples/throughput/CMakeLists.txt rename to examples/throughput/CMakeLists.export diff --git a/examples/throughput/CMakeLists.txt b/examples/throughput/CMakeLists.txt new file mode 100644 index 0000000..1c917fc --- /dev/null +++ b/examples/throughput/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# 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 +# +idlc_generate(Throughput_lib Throughput.idl) + +add_executable(ThroughputPublisher publisher.c) +add_executable(ThroughputSubscriber subscriber.c) + +target_link_libraries(ThroughputPublisher Throughput_lib CycloneDDS::ddsc) +target_link_libraries(ThroughputSubscriber Throughput_lib CycloneDDS::ddsc) + +install( + FILES + "Throughput.idl" + "publisher.c" + "subscriber.c" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/throughput" + COMPONENT dev) + +install( + FILES "CMakeLists.export" + RENAME "CMakeLists.txt" + DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/throughput" + COMPONENT dev) diff --git a/src/examples/throughput/Throughput.idl b/examples/throughput/Throughput.idl similarity index 100% rename from src/examples/throughput/Throughput.idl rename to examples/throughput/Throughput.idl diff --git a/src/examples/throughput/publisher.c b/examples/throughput/publisher.c similarity index 98% rename from src/examples/throughput/publisher.c rename to examples/throughput/publisher.c index 5109d6b..4ae1203 100644 --- a/src/examples/throughput/publisher.c +++ b/examples/throughput/publisher.c @@ -147,6 +147,9 @@ static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName) if (participant < 0) DDS_FATAL("dds_create_participant: %s\n", dds_strretcode(-participant)); + /* Enable write batching */ + dds_write_set_batch (true); + /* A topic is created for our sample type on the domain participant. */ topic = dds_create_topic (participant, &ThroughputModule_DataType_desc, "Throughput", NULL, NULL); if (topic < 0) @@ -171,9 +174,6 @@ static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName) DDS_FATAL("dds_create_writer: %s\n", dds_strretcode(-*writer)); dds_delete_qos (dwQos); - /* Enable write batching */ - dds_write_set_batch (true); - return participant; } @@ -232,7 +232,7 @@ static void start_writing( if (burstCount < burstSize) { status = dds_write (writer, sample); - if (dds_err_nr(status) == DDS_RETCODE_TIMEOUT) + if (status == DDS_RETCODE_TIMEOUT) { timedOut = true; } @@ -285,7 +285,7 @@ static void start_writing( static void finalize_dds(dds_entity_t participant, dds_entity_t writer, ThroughputModule_DataType sample) { dds_return_t status = dds_dispose (writer, &sample); - if (dds_err_nr (status) != DDS_RETCODE_TIMEOUT && status < 0) + if (status != DDS_RETCODE_TIMEOUT && status < 0) DDS_FATAL("dds_dispose: %s\n", dds_strretcode(-status)); dds_free (sample.payload._buffer); diff --git a/src/examples/throughput/readme.rst b/examples/throughput/readme.rst similarity index 100% rename from src/examples/throughput/readme.rst rename to examples/throughput/readme.rst diff --git a/src/examples/throughput/subscriber.c b/examples/throughput/subscriber.c similarity index 100% rename from src/examples/throughput/subscriber.c rename to examples/throughput/subscriber.c diff --git a/performance/throughput-test b/performance/throughput-test deleted file mode 100644 index 36edaa3..0000000 --- a/performance/throughput-test +++ /dev/null @@ -1,159 +0,0 @@ -#!/bin/bash - -usage () { - cat >&2 <$cfg < - - 17 - - - - $nwif - $loopback - - - - 500kB - - ${async:-0} - 3s - - - -EOF - -if [ ! -x bin/ThroughputPublisher -o ! -x bin/ThroughputSubscriber -o ! -x $ethload ] ; then - echo "some check for existence of a file failed on the local machine" >&2 - exit 1 -fi - -[ -d $resultdir ] || { echo "output directory $resultdir doesn't exist" >&2 ; exit 1 ; } - -if $provision ; then - echo "provisioning ..." - for r in $pubremote "$@" ; do - ssh $r mkdir -p $remotedir $remotedir/bin $remotedir/lib - scp lib/libddsc.so.0 $r:$remotedir/lib - scp bin/ThroughputPublisher bin/ThroughputSubscriber $r:$remotedir/bin - done -fi - -export CYCLONEDDS_URI=file://$PWD/$cfg -for r in $pubremote "$@" ; do - scp $cfg $r:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 1 ; } -done - -for async in $asynclist ; do - export async - for mode in $modelist ; do - echo "======== ASYNC $async MODE $mode =========" - - cat > run-publisher.tmp < pub.log & ppid=\$! - top -b -d1 -p \$ppid >> pub-top.log & tpid=\$! - sleep $timeout - kill \$tpid - kill -2 \$ppid - wait \$ppid - sleep 5 -done -wait -EOF - scp run-publisher.tmp $pubremote:$remotedir || { echo "failed to copy $cfg to $remote:$PWD" >&2 ; exit 2 ; } - killremotesubs="" - if [ $# -gt 0 ] ; then - cat > run-subscriber.tmp < /dev/null & -echo \$! -EOF - for r in "$@" ; do - scp run-subscriber.tmp $r:$remotedir - rsubpid=`ssh $r ". $remotedir/run-subscriber.tmp"` - killremotesubs="$killremotesubs ssh $r kill -9 $rsubpid &" - done - fi - - outdir=$resultdir/data-async$async-mode$mode - mkdir $outdir - - rm -f sub-top.log - $ethload $nwif $bandwidth > $outdir/sub-ethload.log & lpid=$! - bin/ThroughputSubscriber 0 $mode > $outdir/sub.log & spid=$! - top -b -d1 -p $spid >> $outdir/sub-top.log & tpid=$! - tail -f $outdir/sub.log & xpid=$! - ssh $pubremote ". $remotedir/run-publisher.tmp" - kill $tpid - kill -2 $spid - eval $killremotesubs - sleep 1 - kill $lpid $xpid - wait - scp $pubremote:$remotedir/{pub-top.log,pub.log} $outdir - done -done diff --git a/performance/throughput-test-extract b/performance/throughput-test-extract deleted file mode 100755 index 9f16ff3..0000000 --- a/performance/throughput-test-extract +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -w - -use strict; - -my @dirs = ("async0-mode-1", "async0-mode0", "async0-mode1", - "async1-mode-1", "async1-mode0", "async1-mode1"); - -my $dataset = 0; -my $basedir = "throughput-result"; -$basedir = $ARGV[0] if @ARGV== 1; -my $load_threshold = 20; -for my $dir (@dirs) { - my @loads = (); - - { - open LH, "< $basedir/data-$dir/sub-ethload.log" or next; # die "can't open $basedir/data-$dir/sub-ethload.log"; - my @curload = (); - while () { - next unless /^r +([0-9.]+).*\( *(\d+)/; - push @curload, $2 if $1 > $load_threshold; - if (@curload && $1 < $load_threshold) { - push @loads, median (@curload); - @curload = (); - } - } - push @loads, median (@curload) if @curload; - close LH; - } - - open FH, "< $basedir/data-$dir/sub.log" or next; # die "can't open $basedir/data-$dir/sub.log"; - print "\n\n" if $dataset++; - print "# mode $dir\n"; - print "# payloadsize rate[samples/s] appl.bandwidth[Mb/s] raw.bandwidth[Mb/s]\n"; - my $psz; - my @rate = (); - while () { - next unless /Payload size: ([0-9]+).*Transfer rate: ([0-9.]+)/; - my $psz_cur = $1; my $rate_cur = $2; - $psz = $psz_cur unless defined $psz; - if ($psz != $psz_cur) { - my $load = shift @loads; - my $rate = median (@rate); - printf "%d %f %f %f\n", $psz, $rate, $rate * (8 + $psz) / 125e3, $load / 125e3; - @rate = (); - } - $psz = $psz_cur; - push @rate, ($rate_cur + 0.0); - } - my $load = shift @loads; - my $rate = median (@rate); - printf "%d %f %f %f\n", $psz, $rate, $rate * (8 + $psz) / 125e3, $load / 125e3; - close FH; -} - -sub median { - my @xs = sort { $a <=> $b } @_; - return (@xs % 2) ? $xs[(@xs - 1) / 2] : ($xs[@xs/2 - 1] + $xs[@xs/2]) / 2; -} - diff --git a/performance/throughput-test-plot b/performance/throughput-test-plot deleted file mode 100755 index 9840b07..0000000 --- a/performance/throughput-test-plot +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -`dirname $0`/throughput-test-extract > data.txt -gnuplot <<\EOF -set term png size 1024,768 -set output "throughput-polling.png" -set st d l -set title "Throughput (polling with 1ms sleeps)" -set ylabel "M sample/s" -set y2label "Mbps" -set y2tics -set xlabel "payload size [bytes]" -p "data.txt" i 5 u 1:($2/1e6) ti "rate [M sample/s]", "" i 5 u 1:3 axes x1y2 ti "app bandwidth [Mbps]", "" i 5 u 1:4 axes x1y2 ti "GbE bandwidth [Mbps]" -EOF diff --git a/ports/freertos-posix/CMakeLists.txt b/ports/freertos-posix/CMakeLists.txt new file mode 100644 index 0000000..005e13b --- /dev/null +++ b/ports/freertos-posix/CMakeLists.txt @@ -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 + "$" + "$" + "$" + "$") +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}") + diff --git a/ports/freertos-posix/README.md b/ports/freertos-posix/README.md new file mode 100644 index 0000000..f812374 --- /dev/null +++ b/ports/freertos-posix/README.md @@ -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. + diff --git a/ports/freertos-posix/freertos-sim.cmake.in b/ports/freertos-posix/freertos-sim.cmake.in new file mode 100644 index 0000000..73b85f2 --- /dev/null +++ b/ports/freertos-posix/freertos-sim.cmake.in @@ -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) + diff --git a/ports/freertos-posix/include/FreeRTOSConfig.h b/ports/freertos-posix/include/FreeRTOSConfig.h new file mode 100644 index 0000000..a149f88 --- /dev/null +++ b/ports/freertos-posix/include/FreeRTOSConfig.h @@ -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 */ diff --git a/ports/freertos-posix/src/loader.c b/ports/freertos-posix/src/loader.c new file mode 100644 index 0000000..baec424 --- /dev/null +++ b/ports/freertos-posix/src/loader.c @@ -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 +#include +#include +#include +#include +#include +#if _WIN32 +# define EX_OK (0) +# define EX_USAGE (64) +# define LF "\r\n" +#else +# include +# define LF "\n" +#endif + +#include +#include + +/* 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; +} diff --git a/ports/solaris2.6/README.md b/ports/solaris2.6/README.md new file mode 100644 index 0000000..058d245 --- /dev/null +++ b/ports/solaris2.6/README.md @@ -0,0 +1,40 @@ +# Solaris 2.6 / sun4m port + +Building for Solaris 2.6 / sun4m, e.g., a Sun Microsystems SPARCStation 20 running Solaris 2.6, +firstly involves getting a sufficiently modern gcc onto the machine (gcc-4.3.x with GNU binutils +certainly works, but it is very well possible that older versions and/or using the Sun assembler and +linker work fine, too) and a sufficiently new gmake (3.81 should do). + +Secondly, because the port relies on a custom makefile rather than "cmake", and that makefile +doesn't build the Java-based IDL preprocessor to avoid pulling in tons of dependencies, you will +need to do a build on a "normal" platform first. The makefile assumes that the required parts of +that build process are available in a "build" directory underneath the project root. Note that only +the CMake generate export.h and the ddsperf-related IDL preprocessor output is required (if other +applications are to be be built, they may require additional files). + +The results are stored in a directory named "gen". After a successful build, there will be +libddsc.so and ddsperf in that directory. No attempts are made at tracking header file +dependencies. It seems unlikely that anyone would want to use such a machine as a development +machine. + +The makefile expects to be run from the project root directory. + +E.g., on a regular supported platform: +``` +# mkdir build && cd build +# cmake ../src +# make +# cd .. +# git archive -o cdds.zip HEAD +# find build -name '*.[ch]' | xargs zip -9r cdds.zip +``` + +copy cdds.zip to the Solaris box, log in and: +``` +# mkdir cdds && cd cdds +# unzip .../cdds.zip +# make -f ports/solaris2.6/makefile -j4 +# gen/ddsperf -D20 sub & gen/ddsperf -D20 pub & +``` + +It takes about 10 minutes to do the build on a quad 100MHz HyperSPARC. diff --git a/ports/solaris2.6/config.mk b/ports/solaris2.6/config.mk new file mode 100644 index 0000000..ded9531 --- /dev/null +++ b/ports/solaris2.6/config.mk @@ -0,0 +1,264 @@ +ifeq "$(CONFIG)" "" + override CONFIG := $(shell $(dir $(lastword $(MAKEFILE_LIST)))/guess-config) + ifeq "$(CONFIG)" "" + $(error "Failed to guess config") + endif +endif + +OS := $(shell echo $(CONFIG) | sed -e 's/^[^.]*\.//' -e 's/^\([^-_]*\)[-_].*/\1/') +PROC := $(shell echo $(CONFIG) | sed -e 's/^\([^.]*\)\..*/\1/') + +ifeq "$(OS)" "darwin" + DDSRT = $(OS) posix + RULES = darwin + CC = clang + LD = $(CC) + OPT = -fsanitize=address #-O3 -DNDEBUG + PROF = + CPPFLAGS += -Wall -g $(OPT) $(PROF) + CFLAGS += $(CPPFLAGS) #-fno-inline + LDFLAGS += -g $(OPT) $(PROF) + X = + O = .o + A = .a + SO = .dylib + LIBPRE = lib +endif +ifeq "$(OS)" "solaris2.6" + DDSRT = $(OS) posix + RULES = unix + CC = gcc -std=gnu99 -mcpu=v8 + LD = $(CC) + OPT = -O2 -DNDEBUG + PROF = + CPPFLAGS += -Wall -g $(OPT) $(PROF) -D_REENTRANT -D__EXTENSIONS__ -D__SunOS_5_6 -I$(PWD)/ports/solaris2.6/include + CFLAGS += $(CPPFLAGS) + LDFLAGS += -g $(OPT) $(PROF) + LDLIBS += -lposix4 -lsocket -lnsl -lc + X = + O = .o + A = .a + SO = .so + LIBPRE = lib +endif +ifeq "$(OS)" "linux" + DDSRT = posix + RULES = unix + CC = gcc-6.2 -std=gnu99 -fpic -mcx16 + OPT = #-fsanitize=address + # CC = gcc-6.2 -std=gnu99 -fpic -mcx16 + # OPT = -O3 -DNDEBUG -flto + LD = $(CC) + PROF = + CPPFLAGS += -Wall -g $(OPT) $(PROF) + CFLAGS += $(CPPFLAGS) #-fno-inline + LDFLAGS += -g $(OPT) $(PROF) + X = + O = .o + A = .a + SO = .so + LIBPRE = lib +endif +ifeq "$(OS)" "win32" + DDSRT = windows + RULES = windows + CC = cl + LD = link + # OPT = -O2 -DNDEBUG + OPT = -MDd + PROF = + CPPFLAGS = -Zi -W3 $(OPT) $(PROF) -TC # -bigobj + CFLAGS += $(CPPFLAGS) + LDFLAGS += -nologo -incremental:no -subsystem:console -debug + X = .exe + O = .obj + A = .lib + SO = .dll + LIBPRE = +# VS_VERSION=12.0 +# ifeq "$(VS_VERSION)" "12.0" # This works for VS2013 + Windows 10 +# VS_HOME=/cygdrive/c/Program Files (x86)/Microsoft Visual Studio 12.0 +# WINDOWSSDKDIR=/cygdrive/c/Program Files (x86)/Windows Kits/8.1 +# else # This works for VS2010 + Windows 7 +# VS_HOME=/cygdrive/C/Program Files (x86)/Microsoft Visual Studio 10.0 +# WINDOWSSDKDIR=/cygdrive/C/Program Files (x86)/Microsoft SDKs/Windows/v7.0A +# endif +endif +ifeq "$(OS)" "wine" + export WINEDEBUG=-all + DDSRT = windows + RULES = wine + GEN = gen.wine + CC = wine cl + LD = wine link + CPPFLAGS = -nologo -W3 -TC -analyze -D_WINNT=0x0604 -Drestrict= + CFLAGS += $(CPPFLAGS) + LDFLAGS += -nologo -incremental:no -subsystem:console -debug + X = .exe + O = .obj + A = .lib + SO = .dll + LIBPRE = +endif + +# use $(DDSRT) as a proxy for $(CONFIG) not matching anything +ifeq "$(DDSRT)" "" + $(error "$(CONFIG): unsupported config") +endif + +# We're assuming use of cygwin, which means Windows path names can be +# obtained using "cygpath". With "-m" we get slashes (rather than +# backslashes), which all of MS' tools accept and which are far less +# troublesome in make. +ifeq "$(CC)" "cl" + N_PWD := $(shell cygpath -m '$(PWD)') + #N_VS_HOME := $(shell cygpath -m '$(VS_HOME)') + #N_WINDOWSSDKDIR := $(shell cygpath -m '$(WINDOWSSDKDIR)') +else # not Windows + N_PWD := $(PWD) +endif + +# More machine- and platform-specific matters. +ifeq "$(CC)" "cl" # Windows + ifeq "$(PROC)" "x86_64" + MACHINE = -machine:X64 + endif + LDFLAGS += $(MACHINE) + OBJ_OFLAG = -Fo + EXE_OFLAG = -out: + SHLIB_OFLAG = -out: + CPPFLAGS += -D_CRT_SECURE_NO_WARNINGS +# ifeq "$(VS_VERSION)" "12.0" # This works for VS2013 + Windows 10 +# CPPFLAGS += '-I$(N_VS_HOME)/VC/include' '-I$(N_WINDOWSSDKDIR)/Include/um' '-I$(N_WINDOWSSDKDIR)/Include/shared' +# ifeq "$(PROC)" "x86_64" +# LDFLAGS += '-libpath:$(N_VS_HOME)/VC/lib/amd64' '-libpath:$(N_WINDOWSSDKDIR)/lib/winv6.3/um/x64' +# else +# LDFLAGS += '-libpath:$(N_VS_HOME)/VC/lib' '-libpath:$(N_WINDOWSSDKDIR)/lib/winv6.3/um/x86' +# endif +# else # This works for VS2010 + Windows 7 +# CPPFLAGS += '-I$(N_VS_HOME)/VC/include' '-I$(N_WINDOWSSDKDIR)/Include' +# ifeq "$(PROC)" "x86_64" +# LDFLAGS += '-libpath:$(N_VS_HOME)/VC/lib/amd64' '-libpath:$(N_WINDOWSSDKDIR)/lib/x64' +# else +# LDFLAGS += '-libpath:$(N_VS_HOME)/VC/lib' '-libpath:$(N_WINDOWSSDKDIR)/lib' +# endif +# endif +else + ifeq "$(CC)" "wine cl" + OBJ_OFLAG =-Fo + EXE_OFLAG = -out: + SHLIB_OFLAG = -out: + CPPFLAGS += -D_CRT_SECURE_NO_WARNINGS + else # not Windows (-like) + OBJ_OFLAG = -o + EXE_OFLAG = -o + SHLIB_OFLAG = -o + ifeq "$(PROC)" "x86" + CFLAGS += -m32 + LDFLAGS += -m32 + endif + ifeq "$(PROC)" "x86_64" + CFLAGS += -m64 + LDFLAGS += -m64 + endif + endif +endif + +ifeq "$(CC)" "cl" + LDFLAGS += -libpath:$(N_PWD)/gen + LIBDEP_SYS = kernel32 ws2_32 +else + ifeq "$(CC)" "wine cl" + else + LDFLAGS += -L$(N_PWD)/gen + LIBDEP_SYS = kernel32 ws2_32 + endif +endif + +getabspath=$(abspath $1) +ifeq "$(RULES)" "darwin" + ifneq "$(findstring clang, $(CC))" "" + define make_exe + $(LD) $(LDFLAGS) $(patsubst -L%, -rpath %, $(filter -L%, $(LDFLAGS))) $(EXE_OFLAG)$@ $^ $(LDLIBS) + endef + define make_shlib + $(LD) $(LDFLAGS) $(patsubst -L%, -rpath %, $(filter -L%, $(LDFLAGS))) -dynamiclib -install_name @rpath/$(notdir $@) $(SHLIB_OFLAG)$@ $^ $(LDLIBS) + endef + else # assume gcc + comma=, + define make_exe + $(LD) $(LDFLAGS) $(patsubst -L%, -Wl$(comma)-rpath$(comma)%, $(filter -L%, $(LDFLAGS))) $(EXE_OFLAG)$@ $^ $(LDLIBS) + endef + define make_shlib + $(LD) $(LDFLAGS) $(patsubst -L%, -Wl$(comma)-rpath$(comma)%, $(filter -L%, $(LDFLAGS))) -dynamiclib -Wl,-install_name,@rpath/$(notdir $@) $(SHLIB_OFLAG)$@ $^ $(LDLIBS) + endef + endif + define make_archive + ar -ru $@ $? + endef + define make_dep + $(CC) -M $(CPPFLAGS) $< | sed 's|[a-zA-Z0-9_-]*\.o|gen/&|' > $@ || { rm $@ ; exit 1 ; } + endef +else + ifeq "$(RULES)" "unix" + LDLIBS += -lpthread + comma=, + define make_exe + $(LD) $(LDFLAGS) $(patsubst -L%,-Wl$(comma)-rpath$(comma)%, $(filter -L%, $(LDFLAGS))) $(EXE_OFLAG)$@ $^ $(LDLIBS) + endef + define make_shlib + $(LD) $(LDFLAGS) -Wl$(comma)--no-allow-shlib-undefined $(patsubst -L%,-Wl$(comma)-rpath$(comma)%, $(filter -L%, $(LDFLAGS))) -shared $(SHLIB_OFLAG)$@ $^ $(LDLIBS) + endef + define make_archive + ar -ru $@ $? + endef + define make_dep + $(CC) -M $(CPPFLAGS) $< | sed 's|[a-zA-Z0-9_-]*\.o|gen/&|' > $@ || { rm $@ ; exit 1 ; } + endef + else + ifeq "$(RULES)" "windows" + define make_exe + $(LD) $(LDFLAGS) $(EXE_OFLAG)$@ $^ $(LDLIBS) + endef + define make_shlib + $(LD) $(LDFLAGS) $(SHLIB_OFLAG)$@ $^ $(LDLIBS) + endef + define make_archive + lib $(MACHINE) /out:$@ $^ + endef + define make_dep + $(CC) -E $(CPPFLAGS) $(CPPFLAGS) $< | grep "^#line.*\\\\vdds\\\\" | cut -d '"' -f 2 | sort -u | sed -e 's@\([A-Za-z]\)\:@ /cygdrive/\1@' -e 's@\\\\@/@g' -e '$$!s@$$@ \\@' -e '1s@^@$*$O: @' >$@ + endef + else + ifeq "$(RULES)" "wine" + COMPILE_MANY_ATONCE=true + getabspath=$1 + lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1)))))))))))))))))))))))))) + FAKEPWD = $(call lc,z:$(subst /,\\\\,$(PWD))) + define make_exe + $(LD) $(LDFLAGS) $(EXE_OFLAG)$@ $^ $(LDLIBS) + endef + define make_shlib + $(LD) $(LDFLAGS) $(SHLIB_OFLAG)$@ $^ $(LDLIBS) + endef + define make_archive + lib $(MACHINE) /out:$@ $^ + endef + define make_dep + $(CC) -E $(CPPFLAGS) $(CPPFLAGS) $< | grep "^#line.*\\\\vdds\\\\" | cut -d '"' -f 2 | sort -u | sed -e 's@$(FAKEPWD)\(\\\\\)*@ @' -e 's@\\\\@/@g' -e '$$!s@$$@ \\@' -e '1s@^@$*$O: @' >$@ + endef + else + $(error "$(OS) not covered by build macros for") + endif + endif + endif +endif + +ifeq "$(GEN)" "" + GEN = gen +endif + +%$O: +%$X: +%$(SO): +%.d: diff --git a/ports/solaris2.6/guess-config b/ports/solaris2.6/guess-config new file mode 100755 index 0000000..845b587 --- /dev/null +++ b/ports/solaris2.6/guess-config @@ -0,0 +1,52 @@ +#!/bin/sh + +s=`uname -s` +case "$s" in + [Dd]arwin) + # default to G4 for now + m=`uname -m` + case "$m" in + x86_64) + cfg="x86_64.darwin" + ;; + *) + echo "guess-config: darwin: didn't recognize machine type $m - please fix" 2>&1 + ;; + esac + ;; + [Ll]inux) + m=`uname -m` + case "$m" in + arm*) + cfg=arm.linux.6 + ;; + x86_64) + cfg=x86_64.linux.6 + ;; + *) + cfg=x86.linux.6 + ;; + esac + ;; + [Ss]un[Oo][Ss]|[Ss]olaris) + m=`uname -m`:`uname -r` + #should check OS rev + case "$m" in + sun4m:5.6) + cfg="sparc.solaris2.6" + ;; + sun4u:*) + cfg="sparcv9.solaris" + ;; + *) + cfg="x86_64.solaris" + ;; + esac + ;; + *) + echo "guess-config: didn't recognize system type $s - please fix" 2>&1 + ;; +esac + +[ -z "$cfg" ] && cfg="asjemenou" +echo $cfg diff --git a/ports/solaris2.6/include/inttypes.h b/ports/solaris2.6/include/inttypes.h new file mode 100644 index 0000000..9db935f --- /dev/null +++ b/ports/solaris2.6/include/inttypes.h @@ -0,0 +1,8 @@ +#ifndef DDSRT_FIXUP_INTTYPES_H +#define DDSRT_FIXUP_INTTYPES_H + +#include_next "inttypes.h" +#define PRIuPTR "lu" +#define PRIxPTR "lx" + +#endif /* DDSRT_FIXUP_INTTYPES_H */ diff --git a/ports/solaris2.6/include/math.h b/ports/solaris2.6/include/math.h new file mode 100644 index 0000000..21339b1 --- /dev/null +++ b/ports/solaris2.6/include/math.h @@ -0,0 +1,22 @@ +#ifndef DDSRT_FIXUP_MATH_H +#define DDSRT_FIXUP_MATH_H + +#include_next "math.h" + +/* INFINITY, HUGE_VALF, HUGE_VALL are all standard C99, but Solaris 2.6 + antedates that by a good margin and GCC's fixed-up headers don't + define it, so we do it here */ +#undef HUGE_VAL +#ifdef __GNUC__ +# define INFINITY (__builtin_inff ()) +# define HUGE_VAL (__builtin_huge_val ()) +# define HUGE_VALF (__builtin_huge_valf ()) +# define HUGE_VALL (__builtin_huge_vall ()) +#else +# define INFINITY 1e10000 +# define HUGE_VAL 1e10000 +# define HUGE_VALF 1e10000f +# define HUGE_VALL 1e10000L +#endif + +#endif /* DDSRT_FIXUP_MATH_H */ diff --git a/ports/solaris2.6/include/netinet/in.h b/ports/solaris2.6/include/netinet/in.h new file mode 100644 index 0000000..fa608eb --- /dev/null +++ b/ports/solaris2.6/include/netinet/in.h @@ -0,0 +1,10 @@ +#ifndef DDSRT_FIXUP_NETINET_IN_H +#define DDSRT_FIXUP_NETINET_IN_H + +#include_next "netinet/in.h" + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif + +#endif /* DDSRT_FIXUP_NETINET_IN_H */ diff --git a/ports/solaris2.6/include/stdint.h b/ports/solaris2.6/include/stdint.h new file mode 100644 index 0000000..490a41e --- /dev/null +++ b/ports/solaris2.6/include/stdint.h @@ -0,0 +1,11 @@ +#ifndef DDSRT_FIXUP_STDINT_H +#define DDSRT_FIXUP_STDINT_H + +#include +#include + +#ifndef UINT32_C +#define UINT32_C(v) (v ## U) +#endif + +#endif /* DDSRT_FIXUP_STDINT_H */ diff --git a/ports/solaris2.6/include/sys/socket.h b/ports/solaris2.6/include/sys/socket.h new file mode 100644 index 0000000..1160e15 --- /dev/null +++ b/ports/solaris2.6/include/sys/socket.h @@ -0,0 +1,14 @@ +#ifndef DDSRT_FIXUP_SYS_SOCKET_H +#define DDSRT_FIXUP_SYS_SOCKET_H + +#include "netinet/in.h" +#include_next "sys/socket.h" + +typedef size_t socklen_t; + +struct sockaddr_storage { + sa_family_t ss_family; + struct sockaddr_in stuff; +}; + +#endif /* DDSRT_FIXUP_SYS_SOCKET_H */ diff --git a/ports/solaris2.6/makefile b/ports/solaris2.6/makefile new file mode 100644 index 0000000..55b85ec --- /dev/null +++ b/ports/solaris2.6/makefile @@ -0,0 +1,59 @@ +.PHONY: all clean + +include $(dir $(lastword $(MAKEFILE_LIST)))/config.mk + +CPPFLAGS += -Isrc/core/ddsc/src -Isrc/core/ddsc/include -Isrc/core/ddsi/include -Isrc/ddsrt/include +CPPFLAGS += $(addprefix -I, $(wildcard src/ddsrt/src/*/include)) +CPPFLAGS += -Ibuild/src/core/include -Ibuild/src/ddsrt/include +CPPFLAGS += -DDDSI_INCLUDE_NETWORK_PARTITIONS # -DDDSI_INCLUDE_BANDWIDTH_LIMITING -DDDSI_INCLUDE_NETWORK_CHANNELS + +SHLIBS = ddsc +EXES = ddsperf + +all: $(SHLIBS:%=$(GEN)/$(LIBPRE)%$(SO)) $(EXES:%=$(GEN)/%$X) +lib: $(SHLIBS:%=$(GEN)/$(LIBPRE)%$(SO)) + +clean: + rm -rf $(GEN)/* + +LIBCDDS_SRCDIRS := src/core/ddsi/src src/core/ddsc/src src/ddsrt/src $(DDSRT:%=src/ddsrt/src/*/%) +LIBCDDS_SRC := $(filter-out %/getopt.c, $(wildcard $(LIBCDDS_SRCDIRS:%=%/*.c))) +ifeq "$(words $(DDSRT))" "2" # max = 2 ... + pct=% + XX=$(filter src/ddsrt/src/%/$(word 1, $(DDSRT))/, $(dir $(LIBCDDS_SRC))) + YY=$(patsubst %/$(word 1, $(DDSRT))/, %/$(word 2, $(DDSRT))/, $(XX)) + LIBCDDS_SRC := $(filter-out $(YY:%=%$(pct)), $(LIBCDDS_SRC)) +endif + +$(GEN)/$(LIBPRE)ddsc$(SO): CPPFLAGS += -Dddsc_EXPORTS +$(GEN)/$(LIBPRE)ddsc$(SO): CPPFLAGS += -fPIC + +ifneq "$(COMPILE_MANY_ATONCE)" "true" +$(GEN)/$(LIBPRE)ddsc$(SO): $(LIBCDDS_SRC:%.c=$(GEN)/%$O) + $(make_shlib) +else # /Fo bit is MSVC specific +$(GEN)/$(LIBPRE)ddsc$(SO): $(LIBCDDS_SRC) + xs="" ;\ + for x in $(foreach x, $^, $(call getabspath, $x)) ; do \ + [ $$x -nt $(GEN)/`basename $$x .c`$O ] && xs="$$xs $$x" ; \ + done ; \ + echo "compile: $$xs" ; \ + [ -z "$$xs" ] || $(CC) $(CPPFLAGS) -MP8 -Fo.\\$(GEN)\\ -c $$xs + $(LD) $(LDFLAGS) $(SHLIB_OFLAG)$@ $(LIBCDDS_SC:%=$(GEN)/%$O) $(LDLIBS) +endif + +DDSPERF_SRCDIRS := src/tools/ddsperf build/src/tools/ddsperf +DDSPERF_SRC := $(wildcard $(DDSPERF_SRCDIRS:%=%/*.c)) + +$(GEN)/ddsperf$X: LDLIBS += -L. -lddsc +$(GEN)/ddsperf$X: CPPFLAGS += -Ibuild/src/tools/ddsperf +$(GEN)/ddsperf$X: $(DDSPERF_SRC:%.c=%.o) | $(GEN)/$(LIBPRE)ddsc$(SO) + $(make_exe) + +$(GEN)/%.STAMP: ; @[ -d $(dir $@) ] || { mkdir -p $(dir $@) ; touch $@ ; } + +$(GEN)/%$O: %.c $(GEN)/%.STAMP + $(CC) $(CPPFLAGS) $(OBJ_OFLAG)$@ -c $< + +$(GEN)/%.d: %.c + $(make_dep) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 48daaa2..16179d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# Copyright(c) 2019 ADLINK Technology Limited and others # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0 which is available at @@ -11,192 +11,21 @@ # cmake_minimum_required(VERSION 3.7) -# Set a default build type if none was specified -set(default_build_type "RelWithDebInfo") -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE - STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +if(NOT ${PROJECT_NAME} STREQUAL "CycloneDDS") + get_filename_component(dir ${CMAKE_CURRENT_LIST_DIR} DIRECTORY) + message(FATAL_ERROR "Top-level CMakeLists.txt was moved to the top-level directory. Please run cmake on ${dir} instead of ${CMAKE_CURRENT_LIST_DIR}") endif() -FUNCTION(PREPEND var prefix) - SET(listVar "") - FOREACH(f ${ARGN}) - LIST(APPEND listVar "${prefix}/${f}") - ENDFOREACH(f) - SET(${var} "${listVar}" PARENT_SCOPE) -ENDFUNCTION(PREPEND) - -# Update the git submodules -execute_process(COMMAND git submodule init - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -execute_process(COMMAND git submodule update - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - -# Set module path before defining project so platform files will work. -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules") -set(CMAKE_PROJECT_NAME_FULL "Eclipse Cyclone DDS") -set(PROJECT_NAME "CycloneDDS") -project(${PROJECT_NAME} VERSION 0.1.0) - -# Set some convenience variants of the project-name -string(REPLACE " " "-" CMAKE_PROJECT_NAME_DASHED "${CMAKE_PROJECT_NAME_FULL}") -string(TOUPPER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_CAPS) -string(TOLOWER ${CMAKE_PROJECT_NAME} CMAKE_PROJECT_NAME_SMALL) - -set(CMAKE_C_STANDARD 99) -if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks") - add_definitions(-std=c99) -endif() - -if(${CMAKE_C_COMPILER_ID} STREQUAL "SunPro") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -xc99 -D__restrict=restrict -D__deprecated__=") - set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -m64") -endif() - -# Conan -if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") - include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) - if(APPLE) - # By default Conan strips all RPATHs (see conanbuildinfo.cmake), which - # causes tests to fail as the executables cannot find the library target. - # By setting KEEP_RPATHS, Conan does not set CMAKE_SKIP_RPATH and the - # resulting binaries still have the RPATH information. This is fine because - # CMake will strip the build RPATH information in the install step. - # - # NOTE: - # Conan's default approach is to use the "imports" feature, which copies - # all the dependencies into the bin directory. Of course, this doesn't work - # quite that well for libraries generated in this Project (see Conan - # documentation). - # - # See the links below for more information. - # https://github.com/conan-io/conan/issues/337 - # https://docs.conan.io/en/latest/howtos/manage_shared_libraries/rpaths.html - # https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling - conan_basic_setup(KEEP_RPATHS) - else() - conan_basic_setup() - endif() - conan_define_targets() -endif() - -# Set reasonably strict warning options for clang, gcc, msvc -# Enable coloured ouput if Ninja is used for building -if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang") - add_definitions(-Wall -Wextra -Wconversion -Wunused) - if(${CMAKE_GENERATOR} STREQUAL "Ninja") - add_definitions(-Xclang -fcolor-diagnostics) - endif() -elseif(${CMAKE_C_COMPILER_ID} STREQUAL "GNU") - add_definitions(-Wall -Wextra -Wconversion) - if(${CMAKE_GENERATOR} STREQUAL "Ninja") - add_definitions(-fdiagnostics-color=always) - endif() -elseif(${CMAKE_C_COMPILER_ID} STREQUAL "MSVC") - add_definitions(/W3) -endif() - -# I don't know how to enable warnings properly so that it ends up in Xcode projects as well -if(${CMAKE_GENERATOR} STREQUAL "Xcode") - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_EMPTY_BODY YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_SHADOW YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_BOOL_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_CONSTANT_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_ENUM_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_FLOAT_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INT_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_NON_LITERAL_NULL_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_IMPLICIT_SIGN_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_INFINITE_RECURSION YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_RETURN_TYPE YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_MISSING_PARENTHESES YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_NEWLINE YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_ASSIGN_ENUM YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_SIGN_COMPARE YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_STRICT_PROTOTYPES YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_COMMA YES) - set (CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNINITIALIZED_AUTOS YES_AGGRESSIVE) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_FUNCTION YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_LABEL YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_PARAMETER YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_VALUE YES) - set (CMAKE_XCODE_ATTRIBUTE_GCC_WARN_UNUSED_VARIABLE YES) -endif() - -# Make it easy to enable one of Clang's/gcc's analyzers, and default to using -# the address sanitizer for ordinary debug builds; gcc is giving some grief on -# Travis, so don't enable it for gcc by default -if(NOT USE_SANITIZER) - if(${CMAKE_BUILD_TYPE} STREQUAL "Debug" AND - NOT (${CMAKE_GENERATOR} STREQUAL "Xcode") AND - (${CMAKE_C_COMPILER_ID} STREQUAL "Clang" - OR ${CMAKE_C_COMPILER_ID} STREQUAL "AppleClang")) - message(STATUS "Enabling address sanitizer; set USE_SANITIZER=none to prevent this") - set(USE_SANITIZER address) - else() - set(USE_SANITIZER none) - endif() -endif() -if(NOT (${USE_SANITIZER} STREQUAL "none")) - message(STATUS "Sanitizer set to ${USE_SANITIZER}") - add_compile_options(-fno-omit-frame-pointer -fsanitize=${USE_SANITIZER}) - link_libraries(-fno-omit-frame-pointer -fsanitize=${USE_SANITIZER}) -endif() - -include(GNUInstallDirs) -include(AnalyzeBuild) -if(APPLE) - set(CMAKE_INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR}") -else() - set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") -endif() -# Include Coverage before CTest so that COVERAGE_COMMAND can be modified -# in the Coverage module should that ever be necessary. -include(Coverage) -set(MEMORYCHECK_COMMAND_OPTIONS "--track-origins=yes --leak-check=full --trace-children=yes --child-silent-after-fork=yes --xml=yes --xml-file=TestResultValgrind_%p.xml --tool=memcheck --show-reachable=yes --leak-resolution=high") - -# By default building the testing tree is enabled by including CTest, but -# since not everybody has CUnit, and because it is not strictly required to -# build the product itself, switch to off by default. -option(BUILD_TESTING "Build the testing tree." OFF) -include(CTest) - -# Build all executables and libraries into the top-level /bin and /lib folders. -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") - -add_subdirectory(idlc) add_subdirectory(ddsrt) -add_subdirectory(etc) + +# some of the tests in the core rely on preprocessing IDL, so idlc has to +# come first +if(BUILD_IDLC) + add_subdirectory(idlc) +endif() add_subdirectory(security/api) add_subdirectory(core) add_subdirectory(tools) -add_subdirectory(scripts) - -option(USE_DOCS "Enable documentation." OFF) -if(USE_DOCS) - add_subdirectory(docs) -else() - message(STATUS "${CMAKE_PROJECT_NAME} documentation: disabled (-DUSE_DOCS=1 to enable)") -endif() - -add_subdirectory(examples) - -if (BUILD_TESTING) - # Multi Process Tests +if(BUILD_TESTING AND HAVE_MULTI_PROCESS AND BUILD_IDLC) add_subdirectory(mpt) endif() - - -# Pull-in CPack and support for generating Config.cmake and packages. -include(Packaging) diff --git a/src/cmake/CoverageSettings.cmake.in b/src/cmake/CoverageSettings.cmake.in deleted file mode 100644 index 818584e..0000000 --- a/src/cmake/CoverageSettings.cmake.in +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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) - -set(COVERAGE_SOURCE_DIR "@PROJECT_SOURCE_DIR@") -set(COVERAGE_RUN_DIR "@CMAKE_BINARY_DIR@") -set(COVERAGE_OUTPUT_DIR "@CMAKE_BINARY_DIR@/coverage") - -# TODO: Make this a list instead of separate variables when more directories -# need to be excluded. Currently there's actually only one directory to -# be excluded, but when the test(s) are moved, more directories will be -# added. I just added two directories to indicate how the coverage -# generators handle multiple exclusion directories. -# -# Do not include the various test directories. -set(COVERAGE_EXCLUDE_TESTS "tests") -set(COVERAGE_EXCLUDE_EXAMPLES "examples") -set(COVERAGE_EXCLUDE_BUILD_SUPPORT "cmake") - -# Add this flag when you want to suppress LCOV and ctest outputs during coverage collecting. -#set(COVERAGE_QUIET_FLAG "--quiet") - diff --git a/src/cmake/launch-c.bat.in b/src/cmake/launch-c.bat.in deleted file mode 100644 index 8f771d9..0000000 --- a/src/cmake/launch-c.bat.in +++ /dev/null @@ -1,26 +0,0 @@ -@echo off -REM Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -REM -REM This program and the accompanying materials are made available under the -REM terms of the Eclipse Public License v. 2.0 which is available at -REM http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -REM v. 1.0 which is available at -REM http://www.eclipse.org/org/documents/edl-v10.php. -REM -REM SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -REM VxWorks toolchain requires WIND_BASE to be exported, should the user be -REM compiling for VxWorks and not have WIND_BASE exported, do that here before -REM invoking the compiler. -if "%WIND_BASE%" == "" ( - set WIND_BASE="@WIND_BASE@" -) - -REM Strip C compiler from command line arguments for compatibility because -REM this launcher may also be used from an integrated development environment -REM at some point. -if "%1" == "@CMAKE_C_COMPILER@" ( - shift -) - -"@CMAKE_C_COMPILER@" %* diff --git a/src/cmake/launch-c.in b/src/cmake/launch-c.in deleted file mode 100644 index 27a64da..0000000 --- a/src/cmake/launch-c.in +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# -# 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 -# - -# VxWorks toolchain requires WIND_BASE to be exported, should the user be -# compiling for VxWorks and not have WIND_BASE exported, to that here before -# invoking the compiler. -if [ -z "${WIND_BASE}" ] && [ -n "@WIND_BASE@" ]; then - WIND_BASE="@WIND_BASE@" - export WIND_BASE -fi - -if [ -n "@WIND_LMAPI@" ]; then - if [ -z "${LD_LIBRARY_PATH}" ]; then - LD_LIBRARY_PATH="@WIND_LMAPI@" - export LD_LIBRARY_PATH - elif [[ "${LD_LIBRARY_PATH}" == ?(*:)"@WIND_LMAPI@"?(:*) ]]; then - LD_LIBRARY_PATH="@WIND_LMAPI@:${LD_LIBRARY_PATH}" - export LD_LIBRARY_PATH - fi -fi - -# Strip C compiler from command line arguments for compatibility because this -# launcher may also be used from an integrated development environment at some -# point. -if [ "$1" = "@CMAKE_C_COMPILER@" ]; then - shift -fi - -exec "@CMAKE_C_COMPILER@" "$@" - diff --git a/src/cmake/launch-cxx.bat.in b/src/cmake/launch-cxx.bat.in deleted file mode 100644 index 5d38b3d..0000000 --- a/src/cmake/launch-cxx.bat.in +++ /dev/null @@ -1,26 +0,0 @@ -@echo off -REM Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -REM -REM This program and the accompanying materials are made available under the -REM terms of the Eclipse Public License v. 2.0 which is available at -REM http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -REM v. 1.0 which is available at -REM http://www.eclipse.org/org/documents/edl-v10.php. -REM -REM SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -REM VxWorks toolchain requires WIND_BASE to be exported, should the user be -REM compiling for VxWorks and not have WIND_BASE exported, do that here before -REM invoking the compiler. -if "%WIND_BASE%" == "" ( - set WIND_BASE="@WIND_BASE@" -) - -REM Strip C compiler from command line arguments for compatibility because -REM this launcher may also be used from an integrated development environment -REM at some point. -if "%1" == "@CMAKE_CXX_COMPILER@" ( - shift -) - -"@CMAKE_CXX_COMPILER@" %* diff --git a/src/cmake/launch-cxx.in b/src/cmake/launch-cxx.in deleted file mode 100644 index 0d3bd19..0000000 --- a/src/cmake/launch-cxx.in +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# -# 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 -# - -# VxWorks toolchain requires WIND_BASE to be exported, should the user be -# compiling for VxWorks and not have WIND_BASE exported, to that here before -# invoking the compiler. -if [ -z "${WIND_BASE}" ] && [ -n "@WIND_BASE@" ]; then - WIND_BASE="@WIND_BASE@" - export WIND_BASE -fi - -if [ -n "@WIND_LMAPI@" ]; then - if [ -z "${LD_LIBRARY_PATH}" ]; then - LD_LIBRARY_PATH="@WIND_LMAPI@" - export LD_LIBRARY_PATH - elif [[ "${LD_LIBRARY_PATH}" == ?(*:)"@WIND_LMAPI@"?(:*) ]]; then - LD_LIBRARY_PATH="@WIND_LMAPI@:${LD_LIBRARY_PATH}" - export LD_LIBRARY_PATH - fi -fi - -# Strip C compiler from command line arguments for compatibility because this -# launcher may also be used from an integrated development environment at some -# point. -if [ "$1" = "@CMAKE_CXX_COMPILER@" ]; then - shift -fi - -exec "@CMAKE_CXX_COMPILER@" "$@" - diff --git a/src/cmake/modules/Coverage.cmake b/src/cmake/modules/Coverage.cmake deleted file mode 100644 index 5e6fc6d..0000000 --- a/src/cmake/modules/Coverage.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# -# 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 -# -if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") - set(BUILD_TYPE_SUPPORTED False) - mark_as_advanced(BUILD_TYPE_SUPPORTED) - if(CMAKE_COMPILER_IS_GNUCXX) - set(BUILD_TYPE_SUPPORTED True) - elseif(("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") AND - ("${CMAKE_C_COMPILER_VERSION}" VERSION_GREATER "3.0.0")) - set(BUILD_TYPE_SUPPORTED True) - endif() - - if(NOT BUILD_TYPE_SUPPORTED) - message(FATAL_ERROR "Coverage build type not supported. (GCC or Clang " - ">3.0.0 required)") - endif() - - # NOTE: Since either GCC or Clang is required for now, and the coverage - # flags are the same for both, there is no need for seperate branches - # to set compiler flags. That might change in the future. - - # CMake has per build type compiler and linker flags. If 'Coverage' is - # chosen, the flags below are automatically inserted into CMAKE_C_FLAGS. - # - # Any optimizations are disabled to ensure coverage results are correct. - # See https://gcc.gnu.org/onlinedocs/gcc/Gcov-and-Optimization.html. - set(CMAKE_C_FLAGS_COVERAGE - "-DNDEBUG -g -O0 --coverage -fprofile-arcs -ftest-coverage") - set(CMAKE_CXX_FLAGS_COVERAGE - "-DNDEBUG -g -O0 --coverage -fprofile-arcs -ftest-coverage") - mark_as_advanced( - CMAKE_C_FLAGS_COVERAGE - CMAKE_CXX_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE) - - configure_file(${CMAKE_MODULE_PATH}/../CoverageSettings.cmake.in CoverageSettings.cmake @ONLY) - - message(STATUS "Coverage build type available") -endif() - diff --git a/src/cmake/modules/Packaging/banner.bmp b/src/cmake/modules/Packaging/banner.bmp deleted file mode 100644 index e795038..0000000 Binary files a/src/cmake/modules/Packaging/banner.bmp and /dev/null differ diff --git a/src/cmake/modules/Packaging/dialog.png b/src/cmake/modules/Packaging/dialog.png deleted file mode 100644 index fd8e3ae..0000000 Binary files a/src/cmake/modules/Packaging/dialog.png and /dev/null differ diff --git a/src/cmake/modules/Packaging/examples.xml b/src/cmake/modules/Packaging/examples.xml deleted file mode 100644 index 4ca2dc8..0000000 --- a/src/cmake/modules/Packaging/examples.xml +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed - - - - - - - - - - - - - - - - - - - diff --git a/src/cmake/modules/Packaging/vortex.ico b/src/cmake/modules/Packaging/vortex.ico deleted file mode 100644 index 65d2a45..0000000 Binary files a/src/cmake/modules/Packaging/vortex.ico and /dev/null differ diff --git a/src/cmake/modules/Platform/VxWorks6.cmake b/src/cmake/modules/Platform/VxWorks6.cmake deleted file mode 100644 index 85de58c..0000000 --- a/src/cmake/modules/Platform/VxWorks6.cmake +++ /dev/null @@ -1,213 +0,0 @@ -# -# 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 Platform file for VxWorks -# -# This file will be used as platform file if CMAKE_SYSTEM_NAME is defined -# as VxWorks in the toolchain file. -# -# Most information is resolved by analyzing the absolute location of the -# compiler on the file system, but can be overridden if required. -# -# Setting CMAKE_SYSTEM_PROCESSOR is mandatory. The variable should be set to -# e.g. ARMARCH* if the target architecture is arm. -# -# NOTES: -# * For now support for VxWorks Diab compiler will NOT be implemented. -# * If certain settings are not explicitly defined, this platform file will -# try to deduce it from the installation path. It will, however, not go out -# of it's way to validate and cross-reference settings. -# -# https://cmake.org/Wiki/CMake_Cross_Compiling -# - -if((NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles") AND - (NOT "${CMAKE_GENERATOR}" MATCHES "Ninja")) - message(FATAL_ERROR "Cross compilation for VxWorks is not supported for " - "${CMAKE_GENERATOR}") -endif() - -set(WIND_PROCESSOR_TYPE_PATTERN ".*(cc|c\\+\\+)(arm|mips|pentium|ppc).*") -set(WIND_HOST_TYPE_PATTERN "^x86-(linux2|win32)$") -set(WIND_PLATFORM_PATTERN "^[0-9\.]+-vxworks-([0-9\.]+)$") - -# Try to deduce the system architecture from either CMAKE_C_COMPILER or -# CMAKE_CXX_COMPILER (one of which must be specified). -# -# Path examples: -# /gnu/4.3.3-vxworks-6.9/x86-linux2/bin -# /gnu/4.1.2-vxworks-6.8/x86-win32/bin -foreach(COMPILER CMAKE_C_COMPILER CMAKE_CXX_COMPILER) - if("${${COMPILER}}" MATCHES "${WIND_PROCESSOR_TYPE_PATTERN}") - string( - REGEX REPLACE - "${WIND_PROCESSOR_TYPE_PATTERN}" "\\2" - PROCESSOR_TYPE - ${${COMPILER}}) - if(NOT WIND_PROCESSOR_TYPE) - set(WIND_PROCESSOR_TYPE ${PROCESSOR_TYPE}) - endif() - - get_filename_component(COMPILER_NAME "${${COMPILER}}" NAME) - if((NOT "${COMPILER_NAME}" STREQUAL "${${COMPILER}}") AND - (NOT "${COMPILER_DIRECTORY}")) - get_filename_component( - COMPILER_PATH "${${COMPILER}}" REALPATH) - get_filename_component( - COMPILER_DIRECTORY "${COMPILER_PATH}" DIRECTORY) - endif() - else() - message(FATAL_ERROR "${COMPILER} did not conform to the expected " - "executable format. i.e. it did not end with " - "arm, mips, pentium, or ppc.") - endif() -endforeach() - - -get_filename_component(C_COMPILER_NAME "${CMAKE_C_COMPILER}" NAME) -get_filename_component(CXX_COMPILER_NAME "${CMAKE_CXX_COMPILER}" NAME) - -# Ideally the location of the compiler should be resolved at this, but invoke -# find_program as a last resort. -if(NOT COMPILER_DIRECTORY) - find_program( - COMPILER_PATH NAMES "${C_COMPILER_NAME}" "${CXX_COMPILER_NAME}") - if(COMPILER_PATH) - get_filename_component( - COMPILER_DIRECTORY "${COMPILER_PATH}" COMPILER_PATH) - else() - # The compiler must be successfully be detected by now. - message(FATAL_ERROR "Could not determine location of compiler path.") - endif() -endif() - - -get_filename_component(basename "${COMPILER_DIRECTORY}" NAME) -get_filename_component(basedir "${COMPILER_DIRECTORY}" DIRECTORY) -while(basename) - if("${basename}" MATCHES "${WIND_PLATFORM_PATTERN}") - string( - REGEX REPLACE "${WIND_PLATFORM_PATTERN}" "\\1" version ${basename}) - if(NOT CMAKE_SYSTEM_VERSION) - set(CMAKE_SYSTEM_VERSION ${version}) - endif() - - # The current base directory may be the WindRiver directory depending - # on wether a "gnu" directory exists or not, but that is evaluated in - # the next iteration. - set(WIND_HOME "${basedir}") - set(WIND_PLATFORM "${basename}") - elseif(CMAKE_SYSTEM_VERSION AND WIND_HOME AND WIND_HOST_TYPE) - # The "gnu" directory may not be part of the path. If it is, strip it. - if("${basename}" STREQUAL "gnu") - set(WIND_HOME "${basedir}") - endif() - break() - elseif("${basename}" MATCHES "${WIND_HOST_TYPE_PATTERN}") - set(WIND_HOST_TYPE "${basename}") - endif() - - get_filename_component(basename ${basedir} NAME) - get_filename_component(basedir ${basedir} DIRECTORY) -endwhile() - - -# VxWorks commands require the WIND_BASE environment variable, so this script -# will support it too. If the environment variable is not set, the necessary -# path information is deduced from the compiler path. -if(NOT WIND_BASE) - set(WIND_BASE $ENV{WIND_BASE}) -endif() - -if(NOT WIND_BASE) - set(WIND_BASE "${WIND_HOME}/vxworks-${CMAKE_SYSTEM_VERSION}") -endif() - -# Verify the location WIND_BASE references actually exists. -if(NOT EXISTS ${WIND_BASE}) - message(FATAL_ERROR "VxWorks base directory ${WIND_BASE} does not exist, " - "please ensure the toolchain information is correct.") -elseif(NOT ENV{WIND_BASE}) - # WIND_BASE environment variable must be exported during generation - # otherwise compiler tests will fail. - set(ENV{WIND_BASE} "${WIND_BASE}") -endif() - - -if(NOT CMAKE_C_COMPILER_VERSION) - execute_process( - COMMAND "${CMAKE_C_COMPILER}" -dumpversion - OUTPUT_VARIABLE CMAKE_C_COMPILER_VERSION) - string(STRIP "${CMAKE_C_COMPILER_VERSION}" CMAKE_C_COMPILER_VERSION) - message(STATUS "VxWorks C compiler version ${CMAKE_C_COMPILER_VERSION}") -endif() - -if(NOT CMAKE_CXX_COMPILER_VERSION) - execute_process( - COMMAND "${CMAKE_CXX_COMPILER}" -dumpversion - OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION) - string(STRIP "${CMAKE_CXX_COMPILER_VERSION}" CMAKE_CXX_COMPILER_VERSION) - message(STATUS "VxWorks CXX compiler version ${CMAKE_C_COMPILER_VERSION}") -endif() - -set(CMAKE_C_COMPILER_ID GNU) -set(CMAKE_CXX_COMPILER_ID GNU) - - -# CMAKE_SOURCE_DIR does not resolve to the actual source directory because -# platform files are processed to early on in the process. -set(ROOT "${CMAKE_MODULE_PATH}/../") - -if(WIN32) - set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-c.bat") - set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-cxx.bat") - configure_file( - "${ROOT}/launch-c.bat.in" "${CMAKE_C_COMPILER_LAUNCHER}" @ONLY) - configure_file( - "${ROOT}/launch-cxx.bat.in" "${CMAKE_CXX_COMPILER_LAUNCHER}" @ONLY) -else() - # Check if a directory like lmapi-* exists (VxWorks 6.9) and append it to - # LD_LIBRARY_PATH. - file(GLOB WIND_LMAPI LIST_DIRECTORIES true "${WIND_HOME}/lmapi-*") - if(WIND_LMAPI) - set(WIND_LMAPI "${WIND_LMAPI}/${WIND_HOST_TYPE}/lib") - endif() - - set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-c") - set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_BINARY_DIR}/launch-cxx") - configure_file( - "${ROOT}/launch-c.in" "${CMAKE_C_COMPILER_LAUNCHER}" @ONLY) - configure_file( - "${ROOT}/launch-cxx.in" "${CMAKE_CXX_COMPILER_LAUNCHER}" @ONLY) - execute_process(COMMAND chmod a+rx "${CMAKE_C_COMPILER_LAUNCHER}") - execute_process(COMMAND chmod a+rx "${CMAKE_CXX_COMPILER_LAUNCHER}") -endif() - - -set(WIND_INCLUDE_DIRECTORY "${WIND_BASE}/target/h") - -# Versions before 6.8 have a different path for common libs. -if("${CMAKE_SYSTEM_VERSION}" VERSION_GREATER "6.8") - set(WIND_LIBRARY_DIRECTORY "${WIND_BASE}/target/lib/usr/lib/${WIND_PROCESSOR_TYPE}/${CMAKE_SYSTEM_PROCESSOR}/common") -else() - set(WIND_LIBRARY_DIRECTORY "${WIND_BASE}/target/usr/lib/${WIND_PROCESSOR_TYPE}/${CMAKE_SYSTEM_PROCESSOR}/common") -endif() - -if(NOT EXISTS "${WIND_LIBRARY_DIRECTORY}") - message(FATAL_ERROR "${CMAKE_SYSTEM_PROCESSOR} is not part of the " - "${WIND_PROCESSOR_TYPE} processor family.") -endif() - -include_directories(BEFORE SYSTEM "${WIND_INCLUDE_DIRECTORY}") -link_directories("${WIND_LIBRARY_DIRECTORY}") - diff --git a/src/cmake/scripts/CoverageConvenience.cmake b/src/cmake/scripts/CoverageConvenience.cmake deleted file mode 100644 index 6a952b8..0000000 --- a/src/cmake/scripts/CoverageConvenience.cmake +++ /dev/null @@ -1,134 +0,0 @@ -# -# 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 -# - -# -# This script will run all tests and generates various coverage reports. -# -# Example usage: -# $ cmake -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoverageConvenience.cmake -# If you start the scripts while in then you don't have to provide the COVERAGE_SETTINGS file. -# -cmake_minimum_required(VERSION 3.5) - -# Get Coverage configuration file -if(NOT COVERAGE_SETTINGS) - set(COVERAGE_SETTINGS ${CMAKE_CURRENT_BINARY_DIR}/CoverageSettings.cmake) -endif() -include(${COVERAGE_SETTINGS}) - -message(STATUS "Config file: ${COVERAGE_SETTINGS}") -message(STATUS "Source directory: ${COVERAGE_SOURCE_DIR}") -message(STATUS "Test directory: ${COVERAGE_RUN_DIR}") -message(STATUS "Output directory: ${COVERAGE_OUTPUT_DIR}") - -set(COVERAGE_SCRIPTS_DIR "${COVERAGE_SOURCE_DIR}/cmake/scripts") - -############################################################################### -# -# Detect generators -# -############################################################################### -set(GENERATE_COVERAGE TRUE) -if(GENERATE_COVERAGE) - find_program(GCOV_PATH gcov PARENT_SCOPE) - if(NOT GCOV_PATH) - set(GENERATE_COVERAGE FALSE) - message(STATUS "[SKIP] Coverage generators - gcov (could not find gcov)") - endif() -endif() -if(GENERATE_COVERAGE) - message(STATUS "[ OK ] Coverage generators - gcov") -endif() - -set(GENERATE_COVERAGE_HTML TRUE) -if(GENERATE_COVERAGE_HTML) - find_program(LCOV_PATH lcov PARENT_SCOPE) - if(NOT LCOV_PATH) - set(GENERATE_COVERAGE_HTML FALSE) - message(STATUS "[SKIP] Coverage generators - HTML (could not find lcov)") - endif() -endif() -if(GENERATE_COVERAGE_HTML) - find_program(GENHTML_PATH genhtml PARENT_SCOPE) - if(NOT GENHTML_PATH) - set(GENERATE_COVERAGE_HTML FALSE) - message(STATUS "[SKIP] Coverage generators - HTML (could not find genhtml)") - endif() -endif() -if(GENERATE_COVERAGE_HTML) - message(STATUS "[ OK ] Coverage generators - HTML (lcov and genhtml)") -endif() - -set(GENERATE_COVERAGE_COBERTURA TRUE) -if(GENERATE_COVERAGE_COBERTURA) - find_program(GCOVR_PATH gcovr PARENT_SCOPE) - if(NOT GCOVR_PATH) - set(GENERATE_COVERAGE_COBERTURA FALSE) - message(STATUS "[SKIP] Coverage generators - Cobertura (could not find gcovr)") - endif() -endif() -if(GENERATE_COVERAGE_COBERTURA) - message(STATUS "[ OK ] Coverage generators - Cobertura (gcovr)") -endif() - -if(NOT GENERATE_COVERAGE) - message(FATAL_ERROR "Could not find the main coverage generator 'gcov'") -elseif(NOT GENERATE_COVERAGE_HTML AND NOT GENERATE_COVERAGE_COBERTURA) - message(FATAL_ERROR "Could not find either of the two coverage report generators") -endif() - - - -############################################################################### -# -# Setup environment -# -############################################################################### -message(STATUS "Setup environment") -if(GENERATE_COVERAGE_HTML) - execute_process(COMMAND ${CMAKE_COMMAND} -DCOVERAGE_SETTINGS=${COVERAGE_SETTINGS} -P ${COVERAGE_SCRIPTS_DIR}/CoveragePreHtml.cmake - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -endif() -if(GENERATE_COVERAGE_COBERTURA) - execute_process(COMMAND ${CMAKE_COMMAND} -DCOVERAGE_SETTINGS=${COVERAGE_SETTINGS} -P ${COVERAGE_SCRIPTS_DIR}/CoveragePreCobertura.cmake - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -endif() - - - -############################################################################### -# -# Generate coverage results by running all the tests -# -############################################################################### -message(STATUS "Run all test to get coverage") -execute_process(COMMAND ctest ${COVERAGE_QUIET_FLAG} -T test - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -execute_process(COMMAND ctest ${COVERAGE_QUIET_FLAG} -T coverage - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) - - - -############################################################################### -# -# Generate coverage reports -# -############################################################################### -if(GENERATE_COVERAGE_HTML) - execute_process(COMMAND ${CMAKE_COMMAND} -DCOVERAGE_SETTINGS=${COVERAGE_SETTINGS} -P ${COVERAGE_SCRIPTS_DIR}/CoveragePostHtml.cmake - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -endif() -if(GENERATE_COVERAGE_COBERTURA) - execute_process(COMMAND ${CMAKE_COMMAND} -DCOVERAGE_SETTINGS=${COVERAGE_SETTINGS} -P ${COVERAGE_SCRIPTS_DIR}/CoveragePostCobertura.cmake - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -endif() - diff --git a/src/cmake/scripts/CoveragePostCobertura.cmake b/src/cmake/scripts/CoveragePostCobertura.cmake deleted file mode 100644 index c28a1c8..0000000 --- a/src/cmake/scripts/CoveragePostCobertura.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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 -# - -# -# This script assumes that all test have been run and gcov results are available. -# It will generate the Cobertura output from the gcov results. -# -# Example usage: -# $ cmake -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePreCobertura.cmake -# $ ctest -T test -# $ ctest -T coverage -# $ ctest -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePostCobertura.cmake -# If you start the scripts while in then you don't have to provide the COVERAGE_SETTINGS file. -# -cmake_minimum_required(VERSION 3.5) - -# Get Coverage configuration file -if(NOT COVERAGE_SETTINGS) - set(COVERAGE_SETTINGS ${CMAKE_CURRENT_BINARY_DIR}/CoverageSettings.cmake) -endif() -include(${COVERAGE_SETTINGS}) - -# Some debug -#message(STATUS "Config file: ${COVERAGE_SETTINGS}") -#message(STATUS "Source directory: ${COVERAGE_SOURCE_DIR}") -#message(STATUS "Test directory: ${COVERAGE_RUN_DIR}") -#message(STATUS "Output directory: ${COVERAGE_OUTPUT_DIR}") - -# Find gcovr to generate Cobertura results -find_program(GCOVR_PATH gcovr PARENT_SCOPE) -if(NOT GCOVR_PATH) - message(FATAL_ERROR "Could not find gcovr to generate Cobertura coverage.") -endif() - -# Create location to put the result file. -file(MAKE_DIRECTORY ${COVERAGE_OUTPUT_DIR}) - -execute_process(COMMAND ${GCOVR_PATH} -x -r ${COVERAGE_SOURCE_DIR} -e ".*/${COVERAGE_EXCLUDE_TESTS}/.*" -e ".*/${COVERAGE_EXCLUDE_EXAMPLES}/.*" -e ".*/${COVERAGE_EXCLUDE_BUILD_SUPPORT}/.*" -o ${COVERAGE_OUTPUT_DIR}/cobertura.xml - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) - - -message(STATUS "The Cobertura report can be found here: ${COVERAGE_OUTPUT_DIR}/cobertura.xml") - diff --git a/src/cmake/scripts/CoveragePostHtml.cmake b/src/cmake/scripts/CoveragePostHtml.cmake deleted file mode 100644 index f8a5739..0000000 --- a/src/cmake/scripts/CoveragePostHtml.cmake +++ /dev/null @@ -1,71 +0,0 @@ -# -# 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 -# - -# -# This script assumes that all test have been run and gcov results are available. -# It will generate the HTML output from the gcov results. -# -# Example usage: -# $ cmake -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePreHtml.cmake -# $ ctest -T test -# $ ctest -T coverage -# $ ctest -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePostHtml.cmake -# If you start the scripts while in then you don't have to provide the COVERAGE_SETTINGS file. -# -cmake_minimum_required(VERSION 3.5) - -# Get Coverage configuration file -if(NOT COVERAGE_SETTINGS) - set(COVERAGE_SETTINGS ${CMAKE_CURRENT_BINARY_DIR}/CoverageSettings.cmake) -endif() -include(${COVERAGE_SETTINGS}) - -# Some debug -#message(STATUS "Config file: ${COVERAGE_SETTINGS}") -#message(STATUS "Source directory: ${COVERAGE_SOURCE_DIR}") -#message(STATUS "Test directory: ${COVERAGE_RUN_DIR}") -#message(STATUS "Output directory: ${COVERAGE_OUTPUT_DIR}") - -# Find tools to generate HTML coverage results -find_program(LCOV_PATH lcov PARENT_SCOPE) -if(NOT LCOV_PATH) - message(FATAL_ERROR "Could not find lcov to generate HTML coverage.") -endif() -find_program(GENHTML_PATH genhtml PARENT_SCOPE) -if(NOT GENHTML_PATH) - message(FATAL_ERROR "Could not find genhtml to generate HTML coverage.") -endif() - -# Create location to put the result file. -file(MAKE_DIRECTORY ${COVERAGE_OUTPUT_DIR}) -set(COVERAGE_HTML_OUTPUT "${COVERAGE_OUTPUT_DIR}/html") -file(MAKE_DIRECTORY ${COVERAGE_HTML_OUTPUT}) - -# Setup tmp analysis files -set(COVERAGE_INFO "${COVERAGE_HTML_OUTPUT}/coverage_html.info") -set(COVERAGE_CLEANED "${COVERAGE_INFO}.cleaned") - -# Execute lcov and genhtml commands to get HTML results -execute_process(COMMAND ${LCOV_PATH} ${COVERAGE_QUIET_FLAG} --directory . --capture --output-file ${COVERAGE_INFO} - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -execute_process(COMMAND ${LCOV_PATH} ${COVERAGE_QUIET_FLAG} --remove ${COVERAGE_INFO} "${COVERAGE_EXCLUDE_TESTS}/*" "${COVERAGE_EXCLUDE_EXAMPLES}/*" "${COVERAGE_EXCLUDE_BUILD_SUPPORT}/*" "/usr/*" --output-file ${COVERAGE_CLEANED} - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) -execute_process(COMMAND ${GENHTML_PATH} ${COVERAGE_QUIET_FLAG} -o ${COVERAGE_HTML_OUTPUT} ${COVERAGE_CLEANED} - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) - -# Remove tmp analysis files -execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${COVERAGE_INFO} ${COVERAGE_CLEANED} - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) - - -message(STATUS "The HTML coverage report can be found here: ${COVERAGE_HTML_OUTPUT}/index.html") - diff --git a/src/cmake/scripts/CoveragePreCobertura.cmake b/src/cmake/scripts/CoveragePreCobertura.cmake deleted file mode 100644 index f774d3d..0000000 --- a/src/cmake/scripts/CoveragePreCobertura.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 -# - -# -# This script assumes that it is called before all tests are run and gcov results are available. -# It can be used to setup the environment needed to get proper Cobertura coverage results. -# -# Example usage: -# $ cmake -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePreCobertura.cmake -# $ ctest -T test -# $ ctest -T coverage -# $ ctest -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePostCobertura.cmake -# If you start the scripts while in then you don't have to provide the COVERAGE_SETTINGS file. -# -cmake_minimum_required(VERSION 3.5) - -# -# Nothing to do really. -# This is just added to provide consistency between Coverage scripts. -# - diff --git a/src/cmake/scripts/CoveragePreHtml.cmake b/src/cmake/scripts/CoveragePreHtml.cmake deleted file mode 100644 index a6deaa7..0000000 --- a/src/cmake/scripts/CoveragePreHtml.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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 -# - -# -# This script assumes that it is called before all tests are run and gcov results are available. -# It can be used to setup the environment needed to get proper HTML coverage results. -# -# Example usage: -# $ cmake -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePreHtml.cmake -# $ ctest -T test -# $ ctest -T coverage -# $ ctest -DCOVERAGE_SETTINGS=/CoverageSettings.cmake -P /cmake/scripts/CoveragePostHtml.cmake -# If you start the scripts while in then you don't have to provide the COVERAGE_SETTINGS file. -# -cmake_minimum_required(VERSION 3.5) - -# Get Coverage configuration file -if(NOT COVERAGE_SETTINGS) - set(COVERAGE_SETTINGS ${CMAKE_CURRENT_BINARY_DIR}/CoverageSettings.cmake) -endif() -include(${COVERAGE_SETTINGS}) - -# Some debug -#message(STATUS "Config file: ${COVERAGE_SETTINGS}") -#message(STATUS "Source directory: ${COVERAGE_SOURCE_DIR}") -#message(STATUS "Test directory: ${COVERAGE_RUN_DIR}") -#message(STATUS "Output directory: ${COVERAGE_OUTPUT_DIR}") - -# Find tools to generate HTML coverage results -find_program(LCOV_PATH lcov PARENT_SCOPE) -if(NOT LCOV_PATH) - message(FATAL_ERROR "Could not find lcov to generate HTML coverage.") -endif() -find_program(GENHTML_PATH genhtml PARENT_SCOPE) -if(NOT GENHTML_PATH) - message(FATAL_ERROR "Could not find genhtml to generate HTML coverage.") -endif() - -# Reset LCOV environment -execute_process(COMMAND ${LCOV_PATH} ${COVERAGE_QUIET_FLAG} --directory . --zerocounters - WORKING_DIRECTORY ${COVERAGE_RUN_DIR}) - - diff --git a/src/cmake/vxworks.example.cmake b/src/cmake/vxworks.example.cmake deleted file mode 100644 index 9af56e8..0000000 --- a/src/cmake/vxworks.example.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# -# 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 -# -set(CMAKE_SYSTEM_NAME VxWorks) -set(CMAKE_SYSTEM_PROCESSOR PENTIUM4) - -set(WIND_HOME "/path/to/WindRiver") -set(WIND_PROCESSOR_TYPE "pentium") - -# Binaries are named e.g. ccpentium or ccarm -set(CMAKE_C_COMPILER ${WIND_HOME}/gnu/4.3.3-vxworks-6.9/x86-linux2/bin/cc${WIND_PROCESSOR_TYPE}) -set(CMAKE_CXX_COMPILER ${WIND_HOME}/gnu/4.3.3-vxworks-6.9/x86-linux2/bin/c++${WIND_PROCESSOR_TYPE}) -set(CMAKE_AR ${WIND_HOME}/gnu/4.3.3-vxworks-6.9/x86-linux2/bin/ar${WIND_PROCESSOR_TYPE}) - -set(WIND_PROGRAM_PATH ${WIND_HOME}/vxworks-6.9/host/x86-linux2/bin;${WIND_BASE}/gnu/4.3.3-vxworks-6.9/x86-linux2/bin) -set(WIND_LIBRARY_PATH ${WIND_HOME}/target/lib/${WIND_PROCESSOR_TYPE}/${CMAKE_SYSTEM_PROCESSOR}/common) -set(WIND_INCLUDE_PATH ${WIND_HOME}/vxworks-6.9/target/h) - -set(CMAKE_FIND_ROOT_PATH ${WIND_PROGRAM_PATH};${WIND_LIBRARY_PATH};${WIND_INCLUDE_PATH}) - -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) - diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c97b8a4..255ee90 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -19,22 +19,27 @@ 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) -option(DDSC_ENABLE_OPENSSL "Enable openssl support" ON) -if(DDSC_ENABLE_OPENSSL) +# OpenSSL is huge, raising the RSS by 1MB or so, and moreover find_package(OpenSSL) causes +# trouble on some older CMake versions that otherwise work fine, so provide an option to avoid +# all OpenSSL related things. +# +# Historically the option was DDSC_ENABLE_OPENSSL so make some allowance for those who are +# currently relying on it. +option(ENABLE_SSL "Enable openssl support" ON) +option(DDSC_ENABLE_OPENSSL "Deprecated: please use ENABLE_SSL instead" ON) +if(NOT DDSC_ENABLE_OPENSSL) + message(ERROR "DDSC_ENABLE_OPENSSL is deprecated, please use ENABLE_SSL instead") + set(ENABLE_SSL OFF) +endif() +if(ENABLE_SSL) find_package(OpenSSL) if(OPENSSL_FOUND) add_definitions(-DDDSI_INCLUDE_SSL) @@ -42,8 +47,9 @@ if(DDSC_ENABLE_OPENSSL) if(CMAKE_GENERATOR MATCHES "Visual Studio") set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099") endif() + message(STATUS "Building with OpenSSL support") else() - message(FATAL_ERROR "To build without openssl support, set DDSC_ENABLE_OPENSSL to OFF") + message(STATUS "Building without OpenSSL support") endif() endif() @@ -51,7 +57,6 @@ include(ddsi/CMakeLists.txt) include(ddsc/CMakeLists.txt) target_link_libraries(ddsc PRIVATE ddsrt security_api) - target_compile_definitions( ddsc PUBLIC $>) @@ -76,4 +81,21 @@ install( ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib ) -add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/xtests") +if(BUILD_IDLC) + add_subdirectory(xtests) +endif() + +if(BUILD_DOCS) + set(DOXYGEN_GENERATE_HTML NO) + set(DOXYGEN_GENERATE_XML YES) + set(DOXYGEN_EXCLUDE_PATTERNS "*/tests/*") + set(DOXYGEN_MACRO_EXPANSION YES) + set(DOXYGEN_PREDEFINED + "__restrict=" + "__attribute__=" + "__declspec(x)=" + "DDS_EXPORT=" + "DDS_DEPRECATED_EXPORT=") + find_package(Doxygen REQUIRED) + doxygen_add_docs(ddsc_api_docs "ddsc/include") +endif() diff --git a/src/core/ddsc/CMakeLists.txt b/src/core/ddsc/CMakeLists.txt index a97ccda..3865765 100644 --- a/src/core/ddsc/CMakeLists.txt +++ b/src/core/ddsc/CMakeLists.txt @@ -19,12 +19,13 @@ PREPEND(srcs_ddsc "${CMAKE_CURRENT_LIST_DIR}/src" dds_init.c dds_publisher.c dds_rhc.c + dds_rhc_default.c dds_domain.c dds_instance.c dds_qos.c dds_handles.c dds_entity.c - dds_key.c + dds_matched.c dds_querycond.c dds_topic.c dds_listener.c @@ -47,8 +48,8 @@ PREPEND(hdrs_public_ddsc "$=0 + * The number of matching readers. + * @retval DDS_RETCODE_BAD_PARAMETER + * The entity parameter is not valid or rds = NULL and + * nrds > 0. + * @retval DDS_RETCODE_ILLEGAL_OPERATION + * The operation is invoked on an inappropriate object. + */ +DDS_EXPORT dds_return_t +dds_get_matched_subscriptions ( + dds_entity_t writer, + dds_instance_handle_t *rds, + size_t nrds); + +/** + * @brief Get a description of a reader matched with the provided + * writer + * + * This operation looks up the reader instance handle in the set of + * readers matched with the specified writer, returning a freshly + * allocated sample of the DCPSSubscription built-in topic if found, + * and NULL if not. The caller is responsible for freeing the + * memory allocated. + * + * This operation is similar to performing a read of the given + * instance handle on a reader of the DCPSSubscription built-in + * topic, but this operation additionally filters on whether the + * reader is matched by the provided writer. + * + * @param[in] writer The writer. + * @param[in] ih The instance handle of a reader. + * + * @returns A newly allocated sample containing the information on the + * reader, or a NULL pointer for any kind of failure. + * + * @retval != NULL + * The requested data + * @retval NULL + * The writer is not valid or ih is not an instance handle + * of a matched reader. + */ +DDS_EXPORT dds_builtintopic_endpoint_t * +dds_get_matched_subscription_data ( + dds_entity_t writer, + dds_instance_handle_t ih); + +/** + * @brief Get instance handles of the data writers matching a reader + * + * This operation fills the provided array with the instance handles + * of the data writers that match the reader. On successful output, + * the number of entries of "wrs" set is the minimum of the return + * value and the value of "nwrs". + * + * @param[in] reader The reader. + * @param[in] wrs The array to be filled. + * @param[in] nwrs The size of the wrs array, at most the first + * nwrs entries will be filled. wrs = NULL and wrds = 0 + * is a valid way of determining the number of matched + * readers, but inefficient compared to relying on the + * matched publication status. + * + * @returns A dds_return_t indicating the number of matched writers + * or failure. The return value may be larger than nwrs + * if there are more matching writers than the array can + * hold. + * + * @retval >=0 + * The number of matching writers. + * @retval DDS_RETCODE_BAD_PARAMETER + * The entity parameter is not valid or wrs = NULL and + * nwrs > 0. + * @retval DDS_RETCODE_ILLEGAL_OPERATION + * The operation is invoked on an inappropriate object. + */ +DDS_EXPORT dds_return_t +dds_get_matched_publications ( + dds_entity_t reader, + dds_instance_handle_t *wrs, + size_t nwrs); + +/** + * @brief Get a description of a writer matched with the provided + * reader + * + * This operation looks up the writer instance handle in the set of + * writers matched with the specified reader, returning a freshly + * allocated sample of the DCPSPublication built-in topic if found, + * and NULL if not. The caller is responsible for freeing the + * memory allocated. + * + * This operation is similar to performing a read of the given + * instance handle on a reader of the DCPSPublication built-in + * topic, but this operation additionally filters on whether the + * writer is matched by the provided reader. + * + * @param[in] reader The reader. + * @param[in] ih The instance handle of a writer. + * + * @returns A newly allocated sample containing the information on the + * writer, or a NULL pointer for any kind of failure. + * + * @retval != NULL + * The requested data + * @retval NULL + * The reader is not valid or ih is not an instance handle + * of a matched writer. + */ +DDS_EXPORT dds_builtintopic_endpoint_t * +dds_get_matched_publication_data ( + dds_entity_t reader, + dds_instance_handle_t ih); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_alloc.h b/src/core/ddsc/include/dds/ddsc/dds_public_alloc.h index 9e66a11..918a4bb 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_alloc.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_alloc.h @@ -54,20 +54,6 @@ typedef struct dds_allocator } dds_allocator_t; -DDS_EXPORT void dds_set_allocator (const dds_allocator_t * __restrict n, dds_allocator_t * __restrict o); - -typedef struct dds_aligned_allocator -{ - /* size is a multiple of align, align is a power of 2 no less than - the machine's page size, returned pointer MUST be aligned to at - least align. */ - void * (*alloc) (size_t size, size_t align); - void (*free) (size_t size, void *ptr); -} -dds_aligned_allocator_t; - -DDS_EXPORT void dds_set_aligned_allocator (const dds_aligned_allocator_t * __restrict n, dds_aligned_allocator_t * __restrict o); - DDS_EXPORT void * dds_alloc (size_t size); DDS_EXPORT void * dds_realloc (void * ptr, size_t size); DDS_EXPORT void * dds_realloc_zero (void * ptr, size_t size); diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_error.h b/src/core/ddsc/include/dds/ddsc/dds_public_error.h index b574371..ef356b4 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_error.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_error.h @@ -28,6 +28,8 @@ extern "C" { #endif +/* ** DEPRECATED ** */ + /* Error masks for returned status values */ #define DDS_ERR_NR_MASK 0x000000ff @@ -37,13 +39,13 @@ extern "C" { /* Error code handling functions */ /** Macro to extract error number */ -#define dds_err_nr(e) ((-(e)) & DDS_ERR_NR_MASK) +#define dds_err_nr(e) (e) /** Macro to extract line number */ -#define dds_err_line(e) (((-(e)) & DDS_ERR_LINE_MASK) >> 8) +#define dds_err_line(e) (0) /** Macro to extract file identifier */ -#define dds_err_file_id(e) (((-(e)) & DDS_ERR_FILE_ID_MASK) >> 22) +#define dds_err_file_id(e) (0) #if defined (__cplusplus) } diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_impl.h b/src/core/ddsc/include/dds/ddsc/dds_public_impl.h index d031570..31d834f 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_impl.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_impl.h @@ -21,9 +21,10 @@ #ifndef DDS_IMPL_H #define DDS_IMPL_H +#include +#include #include "dds/export.h" #include "dds/ddsc/dds_public_alloc.h" -#include "dds/ddsc/dds_public_stream.h" #if defined (__cplusplus) extern "C" { @@ -38,8 +39,6 @@ typedef struct dds_sequence } dds_sequence_t; -#define DDS_LENGTH_UNLIMITED -1 - typedef struct dds_key_descriptor { const char * m_name; @@ -71,6 +70,7 @@ dds_topic_descriptor_t; #define DDS_TOPIC_NO_OPTIMIZE 0x0001 #define DDS_TOPIC_FIXED_KEY 0x0002 +#define DDS_TOPIC_CONTAINS_UNION 0x0004 /* Masks for read condition, read, take: there is only one mask here, @@ -92,116 +92,145 @@ dds_topic_descriptor_t; #define DDS_ANY_STATE (DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE) -#define DDS_DOMAIN_DEFAULT -1 +#define DDS_DOMAIN_DEFAULT ((uint32_t) 0xffffffffu) #define DDS_HANDLE_NIL 0 #define DDS_ENTITY_NIL 0 typedef enum dds_entity_kind { - DDS_KIND_DONTCARE = 0x00000000, - DDS_KIND_TOPIC = 0x01000000, - DDS_KIND_PARTICIPANT = 0x02000000, - DDS_KIND_READER = 0x03000000, - DDS_KIND_WRITER = 0x04000000, - DDS_KIND_SUBSCRIBER = 0x05000000, - DDS_KIND_PUBLISHER = 0x06000000, - DDS_KIND_COND_READ = 0x07000000, - DDS_KIND_COND_QUERY = 0x08000000, - DDS_KIND_COND_GUARD = 0x09000000, - DDS_KIND_WAITSET = 0x0A000000 -} -dds_entity_kind_t; + DDS_KIND_DONTCARE, + DDS_KIND_TOPIC, + DDS_KIND_PARTICIPANT, + DDS_KIND_READER, + DDS_KIND_WRITER, + DDS_KIND_SUBSCRIBER, + DDS_KIND_PUBLISHER, + DDS_KIND_COND_READ, + DDS_KIND_COND_QUERY, + DDS_KIND_COND_GUARD, + DDS_KIND_WAITSET +} dds_entity_kind_t; /* Handles are opaque pointers to implementation types */ typedef uint64_t dds_instance_handle_t; -typedef int32_t dds_domainid_t; +typedef uint32_t dds_domainid_t; /* Topic encoding instruction types */ -#define DDS_OP_RTS 0x00000000 -#define DDS_OP_ADR 0x01000000 -#define DDS_OP_JSR 0x02000000 -#define DDS_OP_JEQ 0x03000000 +enum dds_stream_opcode { + /* return from subroutine, exits top-level + [RTS, 0, 0, 0] */ + DDS_OP_RTS = 0x00 << 24, + /* data field + [ADR, nBY, 0, k] [offset] + [ADR, STR, 0, k] [offset] + [ADR, BST, 0, k] [offset] [bound] + [ADR, SEQ, nBY, 0] [offset] + [ADR, SEQ, STR, 0] [offset] + [ADR, SEQ, BST, 0] [offset] [bound] + [ADR, SEQ, s, 0] [offset] [elem-size] [next-insn, elem-insn] + where s = {SEQ,ARR,UNI,STU} + [ADR, ARR, nBY, k] [offset] [alen] + [ADR, ARR, STR, 0] [offset] [alen] + [ADR, ARR, BST, 0] [offset] [alen] [0] [bound] + [ADR, ARR, s, 0] [offset] [alen] [next-insn, elem-insn] [elem-size] + where s = {SEQ,ARR,UNI,STU} + [ADR, UNI, d, z] [offset] [alen] [next-insn, cases] + where + d = discriminant type of {1BY,2BY,4BY} + z = default present/not present (DDS_OP_FLAG_DEF) + offset = discriminant offset + followed by alen case labels: in JEQ format + note: [ADR, STU, ...] is illegal + where + s = subtype + k = key/not key (DDS_OP_FLAG_KEY) + [offset] = field offset from start of element in memory + [elem-size] = element size in memory + [bound] = string bound + 1 + [alen] = array length, number of cases + [next-insn] = (unsigned 16 bits) offset to instruction for next field, from start of insn + [elem-insn] = (unsigned 16 bits) offset to first instruction for element, from start of insn + [cases] = (unsigned 16 bits) offset to first case label, from start of insn + */ + DDS_OP_ADR = 0x01 << 24, + /* jump-to-subroutine (apparently not used at the moment) + [JSR, 0, e] + where + e = (signed 16 bits) offset to first instruction in subroutine, from start of insn + instruction sequence must end in RTS, execution resumes at instruction + following JSR */ + DDS_OP_JSR = 0x02 << 24, + /* union case + [JEQ, nBY, 0] [disc] [offset] + [JEQ, STR, 0] [disc] [offset] + [JEQ, s, e] [disc] [offset] + where + s = subtype other than {nBY,STR} + e = (unsigned 16 bits) offset to first instruction for case, from start of insn + instruction sequence must end in RTS, at which point executes continues + at the next field's instruction as specified by the union */ + DDS_OP_JEQ = 0x03 << 24 +}; -/* Core type flags - - 1BY : One byte simple type - 2BY : Two byte simple type - 4BY : Four byte simple type - 8BY : Eight byte simple type - STR : String - BST : Bounded string - SEQ : Sequence - ARR : Array - UNI : Union - STU : Struct -*/ - -#define DDS_OP_VAL_1BY 0x01 -#define DDS_OP_VAL_2BY 0x02 -#define DDS_OP_VAL_4BY 0x03 -#define DDS_OP_VAL_8BY 0x04 -#define DDS_OP_VAL_STR 0x05 -#define DDS_OP_VAL_BST 0x06 -#define DDS_OP_VAL_SEQ 0x07 -#define DDS_OP_VAL_ARR 0x08 -#define DDS_OP_VAL_UNI 0x09 -#define DDS_OP_VAL_STU 0x0a - -#define DDS_OP_TYPE_1BY (DDS_OP_VAL_1BY << 16) -#define DDS_OP_TYPE_2BY (DDS_OP_VAL_2BY << 16) -#define DDS_OP_TYPE_4BY (DDS_OP_VAL_4BY << 16) -#define DDS_OP_TYPE_8BY (DDS_OP_VAL_8BY << 16) -#define DDS_OP_TYPE_STR (DDS_OP_VAL_STR << 16) -#define DDS_OP_TYPE_SEQ (DDS_OP_VAL_SEQ << 16) -#define DDS_OP_TYPE_ARR (DDS_OP_VAL_ARR << 16) -#define DDS_OP_TYPE_UNI (DDS_OP_VAL_UNI << 16) -#define DDS_OP_TYPE_STU (DDS_OP_VAL_STU << 16) -#define DDS_OP_TYPE_BST (DDS_OP_VAL_BST << 16) +enum dds_stream_typecode { + DDS_OP_VAL_1BY = 0x01, /* one byte simple type (char, octet, boolean) */ + DDS_OP_VAL_2BY = 0x02, /* two byte simple type ((unsigned) short) */ + DDS_OP_VAL_4BY = 0x03, /* four byte simple type ((unsigned) long, enums, float) */ + DDS_OP_VAL_8BY = 0x04, /* eight byte simple type ((unsigned) long long, double) */ + DDS_OP_VAL_STR = 0x05, /* string */ + DDS_OP_VAL_BST = 0x06, /* bounded string */ + DDS_OP_VAL_SEQ = 0x07, /* sequence */ + DDS_OP_VAL_ARR = 0x08, /* array */ + DDS_OP_VAL_UNI = 0x09, /* union */ + DDS_OP_VAL_STU = 0x0a /* struct */ +}; +/* primary type code for DDS_OP_ADR, DDS_OP_JEQ */ +enum dds_stream_typecode_primary { + DDS_OP_TYPE_1BY = DDS_OP_VAL_1BY << 16, + DDS_OP_TYPE_2BY = DDS_OP_VAL_2BY << 16, + DDS_OP_TYPE_4BY = DDS_OP_VAL_4BY << 16, + DDS_OP_TYPE_8BY = DDS_OP_VAL_8BY << 16, + DDS_OP_TYPE_STR = DDS_OP_VAL_STR << 16, + DDS_OP_TYPE_BST = DDS_OP_VAL_BST << 16, + DDS_OP_TYPE_SEQ = DDS_OP_VAL_SEQ << 16, + DDS_OP_TYPE_ARR = DDS_OP_VAL_ARR << 16, + DDS_OP_TYPE_UNI = DDS_OP_VAL_UNI << 16, + DDS_OP_TYPE_STU = DDS_OP_VAL_STU << 16 +}; #define DDS_OP_TYPE_BOO DDS_OP_TYPE_1BY + +/* sub-type code: + - encodes element type for DDS_OP_TYPE_{SEQ,ARR}, + - discriminant type for DDS_OP_TYPE_UNI */ +enum dds_stream_typecode_subtype { + DDS_OP_SUBTYPE_1BY = DDS_OP_VAL_1BY << 8, + DDS_OP_SUBTYPE_2BY = DDS_OP_VAL_2BY << 8, + DDS_OP_SUBTYPE_4BY = DDS_OP_VAL_4BY << 8, + DDS_OP_SUBTYPE_8BY = DDS_OP_VAL_8BY << 8, + DDS_OP_SUBTYPE_STR = DDS_OP_VAL_STR << 8, + DDS_OP_SUBTYPE_BST = DDS_OP_VAL_BST << 8, + DDS_OP_SUBTYPE_SEQ = DDS_OP_VAL_SEQ << 8, + DDS_OP_SUBTYPE_ARR = DDS_OP_VAL_ARR << 8, + DDS_OP_SUBTYPE_UNI = DDS_OP_VAL_UNI << 8, + DDS_OP_SUBTYPE_STU = DDS_OP_VAL_STU << 8 +}; #define DDS_OP_SUBTYPE_BOO DDS_OP_SUBTYPE_1BY -#define DDS_OP_SUBTYPE_1BY (DDS_OP_VAL_1BY << 8) -#define DDS_OP_SUBTYPE_2BY (DDS_OP_VAL_2BY << 8) -#define DDS_OP_SUBTYPE_4BY (DDS_OP_VAL_4BY << 8) -#define DDS_OP_SUBTYPE_8BY (DDS_OP_VAL_8BY << 8) -#define DDS_OP_SUBTYPE_STR (DDS_OP_VAL_STR << 8) -#define DDS_OP_SUBTYPE_SEQ (DDS_OP_VAL_SEQ << 8) -#define DDS_OP_SUBTYPE_ARR (DDS_OP_VAL_ARR << 8) -#define DDS_OP_SUBTYPE_UNI (DDS_OP_VAL_UNI << 8) -#define DDS_OP_SUBTYPE_STU (DDS_OP_VAL_STU << 8) -#define DDS_OP_SUBTYPE_BST (DDS_OP_VAL_BST << 8) - -#define DDS_OP_FLAG_KEY 0x01 -#define DDS_OP_FLAG_DEF 0x02 +#define DDS_OP_FLAG_KEY 0x01 /* key field: applicable to {1,2,4,8}BY, STR, BST, ARR-of-{1,2,4,8}BY */ +#define DDS_OP_FLAG_DEF 0x02 /* union has a default case (for DDS_OP_ADR | DDS_OP_TYPE_UNI) */ /** * Description : Enable or disable write batching. Overrides default configuration - * setting for write batching (DDSI2E/Internal/WriteBatch). + * setting for write batching (Internal/WriteBatch). * * Arguments : * -# enable Enables or disables write batching for all writers. */ DDS_EXPORT void dds_write_set_batch (bool enable); -/** - * Description : Install tcp/ssl and encryption support. Depends on openssl. - * - * Arguments : - * -# None - */ -DDS_EXPORT void dds_ssl_plugin (void); - -/** - * Description : Install client durability support. Depends on OSPL server. - * - * Arguments : - * -# None - */ -DDS_EXPORT void dds_durability_plugin (void); - #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h index b8fc7fa..503a567 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h @@ -21,131 +21,12 @@ #define DDS_QOS_H #include "dds/export.h" +#include "dds/ddsc/dds_public_qosdefs.h" #if defined (__cplusplus) extern "C" { #endif -/* QoS identifiers */ -/** @name QoS identifiers - @{**/ -#define DDS_INVALID_QOS_POLICY_ID 0 -#define DDS_USERDATA_QOS_POLICY_ID 1 -#define DDS_DURABILITY_QOS_POLICY_ID 2 -#define DDS_PRESENTATION_QOS_POLICY_ID 3 -#define DDS_DEADLINE_QOS_POLICY_ID 4 -#define DDS_LATENCYBUDGET_QOS_POLICY_ID 5 -#define DDS_OWNERSHIP_QOS_POLICY_ID 6 -#define DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID 7 -#define DDS_LIVELINESS_QOS_POLICY_ID 8 -#define DDS_TIMEBASEDFILTER_QOS_POLICY_ID 9 -#define DDS_PARTITION_QOS_POLICY_ID 10 -#define DDS_RELIABILITY_QOS_POLICY_ID 11 -#define DDS_DESTINATIONORDER_QOS_POLICY_ID 12 -#define DDS_HISTORY_QOS_POLICY_ID 13 -#define DDS_RESOURCELIMITS_QOS_POLICY_ID 14 -#define DDS_ENTITYFACTORY_QOS_POLICY_ID 15 -#define DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID 16 -#define DDS_READERDATALIFECYCLE_QOS_POLICY_ID 17 -#define DDS_TOPICDATA_QOS_POLICY_ID 18 -#define DDS_GROUPDATA_QOS_POLICY_ID 19 -#define DDS_TRANSPORTPRIORITY_QOS_POLICY_ID 20 -#define DDS_LIFESPAN_QOS_POLICY_ID 21 -#define DDS_DURABILITYSERVICE_QOS_POLICY_ID 22 -/** @}*/ - - -/* QoS structure is opaque */ -/** QoS structure */ -typedef struct nn_xqos dds_qos_t; - -/** Durability QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_durability_kind -{ - DDS_DURABILITY_VOLATILE, - DDS_DURABILITY_TRANSIENT_LOCAL, - DDS_DURABILITY_TRANSIENT, - DDS_DURABILITY_PERSISTENT -} -dds_durability_kind_t; - -/** History QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_history_kind -{ - DDS_HISTORY_KEEP_LAST, - DDS_HISTORY_KEEP_ALL -} -dds_history_kind_t; - -/** Ownership QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_ownership_kind -{ - DDS_OWNERSHIP_SHARED, - DDS_OWNERSHIP_EXCLUSIVE -} -dds_ownership_kind_t; - -/** Liveliness QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_liveliness_kind -{ - DDS_LIVELINESS_AUTOMATIC, - DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, - DDS_LIVELINESS_MANUAL_BY_TOPIC -} -dds_liveliness_kind_t; - -/** Reliability QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_reliability_kind -{ - DDS_RELIABILITY_BEST_EFFORT, - DDS_RELIABILITY_RELIABLE -} -dds_reliability_kind_t; - -/** DestinationOrder QoS: Applies to Topic, DataReader, DataWriter */ -typedef enum dds_destination_order_kind -{ - DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP, - DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP -} -dds_destination_order_kind_t; - -/** History QoS: Applies to Topic, DataReader, DataWriter */ -typedef struct dds_history_qospolicy -{ - dds_history_kind_t kind; - int32_t depth; -} -dds_history_qospolicy_t; - -/** ResourceLimits QoS: Applies to Topic, DataReader, DataWriter */ -typedef struct dds_resource_limits_qospolicy -{ - int32_t max_samples; - int32_t max_instances; - int32_t max_samples_per_instance; -} -dds_resource_limits_qospolicy_t; - -/** Presentation QoS: Applies to Publisher, Subscriber */ -typedef enum dds_presentation_access_scope_kind -{ - DDS_PRESENTATION_INSTANCE, - DDS_PRESENTATION_TOPIC, - DDS_PRESENTATION_GROUP -} -dds_presentation_access_scope_kind_t; - -/** Ignore-local QoS: Applies to DataReader, DataWriter */ -typedef enum dds_ignorelocal_kind -{ - DDS_IGNORELOCAL_NONE, - DDS_IGNORELOCAL_PARTICIPANT, - DDS_IGNORELOCAL_PROCESS -} -dds_ignorelocal_kind_t; - - /** * @brief Allocate memory and initialize default QoS-policies * @@ -212,8 +93,8 @@ dds_qos_merge (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src); * * Policies are copied from src to dst, unless src already has the policy set to a non-default value. * - * @param[in,out] dst - Pointer to the destination qos structure - * @param[in] src - Pointer to the source qos structure + * @param[in,out] a - Pointer to the destination qos structure + * @param[in] b - Pointer to the source qos structure */ DDS_EXPORT bool dds_qos_equal (const dds_qos_t * __restrict a, const dds_qos_t * __restrict b); @@ -448,7 +329,7 @@ dds_qset_destination_order ( * @brief Set the writer data-lifecycle policy of a qos structure * * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy - * @param[in] autodispose_unregistered_instances - Automatic disposal of unregistered instances + * @param[in] autodispose - Automatic disposal of unregistered instances */ DDS_EXPORT void dds_qset_writer_data_lifecycle (dds_qos_t * __restrict qos, bool autodispose); @@ -493,7 +374,8 @@ dds_qset_durability_service ( * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy * @param[in] ignore - True if readers and writers owned by the same participant should be ignored */ -DDS_EXPORT void dds_qset_ignorelocal ( +DDS_EXPORT void +dds_qset_ignorelocal ( dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore); @@ -738,7 +620,7 @@ dds_qget_destination_order ( * @brief Get the writer data-lifecycle qos policy * * @param[in] qos - Pointer to a dds_qos_t structure storing the policy - * @param[in,out] autodispose_unregistered_instances - Pointer that will store the autodispose unregistered instances enable value + * @param[in,out] autodispose - Pointer that will store the autodispose unregistered instances enable value * * @returns - false iff any of the arguments is invalid or the qos is not present in the qos object */ diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h b/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h new file mode 100644 index 0000000..810d471 --- /dev/null +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h @@ -0,0 +1,132 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +/** @file + * + * @brief DDS C QoS API + * + * This header file defines the public API of QoS and Policies in the + * Eclipse Cyclone DDS C language binding. + */ +#ifndef DDS_QOSDEFS_H +#define DDS_QOSDEFS_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#define DDS_LENGTH_UNLIMITED -1 + +/** QoS identifiers */ +typedef enum dds_qos_policy_id { + DDS_INVALID_QOS_POLICY_ID, + DDS_USERDATA_QOS_POLICY_ID, + DDS_DURABILITY_QOS_POLICY_ID, + DDS_PRESENTATION_QOS_POLICY_ID, + DDS_DEADLINE_QOS_POLICY_ID, + DDS_LATENCYBUDGET_QOS_POLICY_ID, + DDS_OWNERSHIP_QOS_POLICY_ID, + DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID, + DDS_LIVELINESS_QOS_POLICY_ID, + DDS_TIMEBASEDFILTER_QOS_POLICY_ID, + DDS_PARTITION_QOS_POLICY_ID, + DDS_RELIABILITY_QOS_POLICY_ID, + DDS_DESTINATIONORDER_QOS_POLICY_ID, + DDS_HISTORY_QOS_POLICY_ID, + DDS_RESOURCELIMITS_QOS_POLICY_ID, + DDS_ENTITYFACTORY_QOS_POLICY_ID, + DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID, + DDS_READERDATALIFECYCLE_QOS_POLICY_ID, + DDS_TOPICDATA_QOS_POLICY_ID, + DDS_GROUPDATA_QOS_POLICY_ID, + DDS_TRANSPORTPRIORITY_QOS_POLICY_ID, + DDS_LIFESPAN_QOS_POLICY_ID, + DDS_DURABILITYSERVICE_QOS_POLICY_ID +} dds_qos_policy_id_t; + +/* QoS structure is opaque */ +/** QoS structure */ +typedef struct dds_qos dds_qos_t; + +/** Durability QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_durability_kind +{ + DDS_DURABILITY_VOLATILE, + DDS_DURABILITY_TRANSIENT_LOCAL, + DDS_DURABILITY_TRANSIENT, + DDS_DURABILITY_PERSISTENT +} +dds_durability_kind_t; + +/** History QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_history_kind +{ + DDS_HISTORY_KEEP_LAST, + DDS_HISTORY_KEEP_ALL +} +dds_history_kind_t; + +/** Ownership QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_ownership_kind +{ + DDS_OWNERSHIP_SHARED, + DDS_OWNERSHIP_EXCLUSIVE +} +dds_ownership_kind_t; + +/** Liveliness QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_liveliness_kind +{ + DDS_LIVELINESS_AUTOMATIC, + DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, + DDS_LIVELINESS_MANUAL_BY_TOPIC +} +dds_liveliness_kind_t; + +/** Reliability QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_reliability_kind +{ + DDS_RELIABILITY_BEST_EFFORT, + DDS_RELIABILITY_RELIABLE +} +dds_reliability_kind_t; + +/** DestinationOrder QoS: Applies to Topic, DataReader, DataWriter */ +typedef enum dds_destination_order_kind +{ + DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP, + DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP +} +dds_destination_order_kind_t; + +/** Presentation QoS: Applies to Publisher, Subscriber */ +typedef enum dds_presentation_access_scope_kind +{ + DDS_PRESENTATION_INSTANCE, + DDS_PRESENTATION_TOPIC, + DDS_PRESENTATION_GROUP +} +dds_presentation_access_scope_kind_t; + +/** Ignore-local QoS: Applies to DataReader, DataWriter */ +typedef enum dds_ignorelocal_kind +{ + DDS_IGNORELOCAL_NONE, + DDS_IGNORELOCAL_PARTICIPANT, + DDS_IGNORELOCAL_PROCESS +} +dds_ignorelocal_kind_t; + +#if defined (__cplusplus) +} +#endif +#endif diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_status.h b/src/core/ddsc/include/dds/ddsc/dds_public_status.h index ce9ae79..40df7d6 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_status.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_status.h @@ -185,7 +185,7 @@ dds_inconsistent_topic_status_t; * @param[out] status The pointer to \ref DCPS_Status_InconsistentTopic to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -212,7 +212,7 @@ dds_get_inconsistent_topic_status ( * @param[out] status The pointer to \ref DCPS_Status_PublicationMatched to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -239,7 +239,7 @@ dds_get_publication_matched_status ( * @param[out] status The pointer to \ref DCPS_Status_LivelinessLost to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -266,7 +266,7 @@ dds_get_liveliness_lost_status ( * @param[out] status The pointer to \ref DCPS_Status_OfferedDeadlineMissed to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -293,7 +293,7 @@ dds_get_offered_deadline_missed_status( * @param[out] status The pointer to \ref DCPS_Status_OfferedIncompatibleQoS to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -320,7 +320,7 @@ dds_get_offered_incompatible_qos_status ( * @param[out] status The pointer to \ref DCPS_Status_SubscriptionMatched to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -347,7 +347,7 @@ dds_get_subscription_matched_status ( * @param[out] status The pointer to \ref DCPS_Status_LivelinessChanged to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. @@ -374,7 +374,7 @@ dds_get_liveliness_changed_status ( * @param[out] status The pointer to \ref DCPS_Status_SampleRejected to get the status * * @returns 0 - Success - * @returns <0 - Failure (use dds_err_nr() to get error value). + * @returns <0 - Failure * * @retval DDS_RETCODE_ERROR * An internal error has occurred. diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_stream.h b/src/core/ddsc/include/dds/ddsc/dds_public_stream.h deleted file mode 100644 index 6a3d56f..0000000 --- a/src/core/ddsc/include/dds/ddsc/dds_public_stream.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -/** @file - * - * @brief DDS C Stream API - * - * This header file defines the public API of the Streams in the - * Eclipse Cyclone DDS C language binding. - */ -#ifndef DDS_STREAM_H -#define DDS_STREAM_H - -#include -#include -#include - -#include "dds/export.h" - -#if defined (__cplusplus) -extern "C" { -#endif - -struct dds_sequence; - -typedef union -{ - uint8_t * p8; - uint16_t * p16; - uint32_t * p32; - uint64_t * p64; - float * pf; - double * pd; - void * pv; -} -dds_uptr_t; - -typedef struct dds_stream -{ - dds_uptr_t m_buffer; /* Union of pointers to start of buffer */ - uint32_t m_size; /* Buffer size */ - uint32_t m_index; /* Read/write offset from start of buffer */ - bool m_endian; /* Endian: big (false) or little (true) */ - bool m_failed; /* Attempt made to read beyond end of buffer */ -} -dds_stream_t; - -#define DDS_STREAM_BE false -#define DDS_STREAM_LE true - -DDS_EXPORT dds_stream_t * dds_stream_create (uint32_t size); -DDS_EXPORT dds_stream_t * dds_stream_from_buffer (const void *buf, size_t sz, int bswap); -DDS_EXPORT void dds_stream_delete (dds_stream_t * st); -DDS_EXPORT void dds_stream_fini (dds_stream_t * st); -DDS_EXPORT void dds_stream_reset (dds_stream_t * st); -DDS_EXPORT void dds_stream_init (dds_stream_t * st, uint32_t size); -DDS_EXPORT void dds_stream_grow (dds_stream_t * st, uint32_t size); -DDS_EXPORT bool dds_stream_endian (void); - -struct dds_topic_descriptor; -DDS_EXPORT void dds_stream_read_sample_w_desc (dds_stream_t * is, void * data, const struct dds_topic_descriptor * desc); -DDS_EXPORT bool dds_stream_read_bool (dds_stream_t * is); -DDS_EXPORT uint8_t dds_stream_read_uint8 (dds_stream_t * is); -DDS_EXPORT uint16_t dds_stream_read_uint16 (dds_stream_t * is); -DDS_EXPORT uint32_t dds_stream_read_uint32 (dds_stream_t * is); -DDS_EXPORT uint64_t dds_stream_read_uint64 (dds_stream_t * is); -DDS_EXPORT float dds_stream_read_float (dds_stream_t * is); -DDS_EXPORT double dds_stream_read_double (dds_stream_t * is); -DDS_EXPORT char * dds_stream_read_string (dds_stream_t * is); -DDS_EXPORT void dds_stream_read_buffer (dds_stream_t * is, uint8_t * buffer, uint32_t len); - -inline char dds_stream_read_char (dds_stream_t *is) { return (char) dds_stream_read_uint8 (is); } -inline int8_t dds_stream_read_int8 (dds_stream_t *is) { return (int8_t) dds_stream_read_uint8 (is); } -inline int16_t dds_stream_read_int16 (dds_stream_t *is) { return (int16_t) dds_stream_read_uint16 (is); } -inline int32_t dds_stream_read_int32 (dds_stream_t *is) { return (int32_t) dds_stream_read_uint32 (is); } -inline int64_t dds_stream_read_int64 (dds_stream_t *is) { return (int64_t) dds_stream_read_uint64 (is); } - -DDS_EXPORT void dds_stream_write_bool (dds_stream_t * os, bool val); -DDS_EXPORT void dds_stream_write_uint8 (dds_stream_t * os, uint8_t val); -DDS_EXPORT void dds_stream_write_uint16 (dds_stream_t * os, uint16_t val); -DDS_EXPORT void dds_stream_write_uint32 (dds_stream_t * os, uint32_t val); -DDS_EXPORT void dds_stream_write_uint64 (dds_stream_t * os, uint64_t val); -DDS_EXPORT void dds_stream_write_float (dds_stream_t * os, float val); -DDS_EXPORT void dds_stream_write_double (dds_stream_t * os, double val); -DDS_EXPORT void dds_stream_write_string (dds_stream_t * os, const char * val); -DDS_EXPORT void dds_stream_write_buffer (dds_stream_t * os, uint32_t len, const uint8_t * buffer); -DDS_EXPORT void *dds_stream_address (dds_stream_t * s); -DDS_EXPORT void *dds_stream_alignto (dds_stream_t * s, uint32_t a); - -inline void dds_stream_write_char (dds_stream_t * os, char val) { dds_stream_write_uint8 (os, (uint8_t) val); } -inline void dds_stream_write_int8 (dds_stream_t * os, int8_t val) { dds_stream_write_uint8 (os, (uint8_t) val); } -inline void dds_stream_write_int16 (dds_stream_t * os, int16_t val) { dds_stream_write_uint16 (os, (uint16_t) val); } -inline void dds_stream_write_int32 (dds_stream_t * os, int32_t val) { dds_stream_write_uint32 (os, (uint32_t) val); } -inline void dds_stream_write_int64 (dds_stream_t * os, int64_t val) { dds_stream_write_uint64 (os, (uint64_t) val); } - -#if defined (__cplusplus) -} -#endif -#endif diff --git a/src/core/ddsc/src/dds__builtin.h b/src/core/ddsc/src/dds__builtin.h index fd191f9..1c1f80c 100644 --- a/src/core/ddsc/src/dds__builtin.h +++ b/src/core/ddsc/src/dds__builtin.h @@ -12,7 +12,7 @@ #ifndef _DDS_BUILTIN_H_ #define _DDS_BUILTIN_H_ -#include "dds/ddsi/q_time.h" +#include "dds/ddsi/ddsi_builtin_topic_if.h" #if defined (__cplusplus) extern "C" @@ -20,24 +20,19 @@ extern "C" #endif /* Get actual topic in related participant related to topic 'id'. */ -dds_entity_t dds__get_builtin_topic ( dds_entity_t e, dds_entity_t topic); +dds_entity_t dds__get_builtin_topic (dds_entity_t e, dds_entity_t topic); /* Subscriber singleton within related participant. */ -dds_entity_t dds__get_builtin_subscriber(dds_entity_t e); +dds_entity_t dds__get_builtin_subscriber (dds_entity_t e); /* Checks whether the reader QoS is valid for use with built-in topic TOPIC */ -bool dds__validate_builtin_reader_qos(dds_entity_t topic, const dds_qos_t *qos); +bool dds__validate_builtin_reader_qos (const dds_domain *dom, dds_entity_t topic, const dds_qos_t *qos); + +void dds__builtin_init (struct dds_domain *dom); +void dds__builtin_fini (struct dds_domain *dom); struct entity_common; -struct nn_guid; -struct ddsi_tkmap_instance; - -void dds__builtin_init (void); -void dds__builtin_fini (void); -bool dds__builtin_is_visible (nn_entityid_t entityid, bool onlylocal, nn_vendorid_t vendorid); -struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid); struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, nn_wctime_t timestamp, bool alive); -void dds__builtin_write (const struct entity_common *e, nn_wctime_t timestamp, bool alive); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__domain.h b/src/core/ddsc/src/dds__domain.h index 0b13070..2e3baaa 100644 --- a/src/core/ddsc/src/dds__domain.h +++ b/src/core/ddsc/src/dds__domain.h @@ -18,11 +18,9 @@ extern "C" { #endif -extern DDS_EXPORT const ddsrt_avl_treedef_t dds_domaintree_def; - -DDS_EXPORT dds_domain * dds_domain_create (dds_domainid_t id); -DDS_EXPORT void dds_domain_free (dds_domain * domain); -DDS_EXPORT dds_domain * dds_domain_find_locked (dds_domainid_t id); +DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id); +DDS_EXPORT void dds_domain_free (dds_domain *domain); +DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__entity.h b/src/core/ddsc/src/dds__entity.h index 34c13c5..8541729 100644 --- a/src/core/ddsc/src/dds__entity.h +++ b/src/core/ddsc/src/dds__entity.h @@ -26,20 +26,22 @@ dds_entity_init( dds_entity_kind_t kind, dds_qos_t * qos, const dds_listener_t *listener, - uint32_t mask); + status_mask_t mask); DDS_EXPORT void -dds_entity_add_ref(dds_entity *e); +dds_entity_register_child ( + dds_entity *parent, + dds_entity *child); DDS_EXPORT void -dds_entity_add_ref_nolock(dds_entity *e); +dds_entity_add_ref_locked(dds_entity *e); #define DEFINE_ENTITY_LOCK_UNLOCK(qualifier_, type_, kind_) \ - qualifier_ dds_retcode_t type_##_lock (dds_entity_t hdl, type_ **x) \ + qualifier_ dds_return_t type_##_lock (dds_entity_t hdl, type_ **x) \ { \ - dds_retcode_t rc; \ + dds_return_t rc; \ dds_entity *e; \ - if ((rc = dds_entity_lock (hdl, kind_, &e)) != DDS_RETCODE_OK) \ + if ((rc = dds_entity_lock (hdl, kind_, &e)) < 0) \ return rc; \ *x = (type_ *) e; \ return DDS_RETCODE_OK; \ @@ -50,7 +52,7 @@ dds_entity_add_ref_nolock(dds_entity *e); dds_entity_unlock (&x->m_entity); \ } #define DECL_ENTITY_LOCK_UNLOCK(qualifier_, type_) \ - qualifier_ dds_retcode_t type_##_lock (dds_entity_t hdl, type_ **x); \ + qualifier_ dds_return_t type_##_lock (dds_entity_t hdl, type_ **x); \ qualifier_ void type_##_unlock (type_ *x); DDS_EXPORT inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink) { @@ -61,33 +63,30 @@ DDS_EXPORT inline bool dds_entity_is_enabled (const dds_entity *e) { return (e->m_flags & DDS_ENTITY_ENABLED) != 0; } -DDS_EXPORT void dds_entity_status_set (dds_entity *e, uint32_t t); +DDS_EXPORT void dds_entity_status_set (dds_entity *e, status_mask_t t); +DDS_EXPORT void dds_entity_trigger_set (dds_entity *e, uint32_t t); -DDS_EXPORT inline void dds_entity_status_reset (dds_entity *e, uint32_t t) { - e->m_trigger &= ~t; -} - -DDS_EXPORT inline bool dds_entity_status_match (const dds_entity *e, uint32_t t) { - return (e->m_trigger & t) != 0; +DDS_EXPORT inline void dds_entity_status_reset (dds_entity *e, status_mask_t t) { + ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, SAM_ENABLED_MASK | (status_mask_t) ~t); } DDS_EXPORT inline dds_entity_kind_t dds_entity_kind (const dds_entity *e) { return e->m_kind; } -DDS_EXPORT void dds_entity_status_signal (dds_entity *e); +DDS_EXPORT void dds_entity_status_signal (dds_entity *e, uint32_t status); DDS_EXPORT void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id which, const void *vst); -DDS_EXPORT dds_retcode_t -dds_entity_claim ( +DDS_EXPORT dds_return_t +dds_entity_pin ( dds_entity_t hdl, dds_entity **eptr); -DDS_EXPORT void dds_entity_release ( +DDS_EXPORT void dds_entity_unpin ( dds_entity *e); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t dds_entity_lock( dds_entity_t hdl, dds_entity_kind_t kind, @@ -96,27 +95,17 @@ dds_entity_lock( DDS_EXPORT void dds_entity_unlock(dds_entity *e); -DDS_EXPORT dds_retcode_t -dds_entity_observer_register_nl( - dds_entity *observed, - dds_entity_t observer, - dds_entity_callback cb); - -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t dds_entity_observer_register( - dds_entity_t observed, - dds_entity_t observer, - dds_entity_callback cb); - -DDS_EXPORT dds_retcode_t -dds_entity_observer_unregister_nl( dds_entity *observed, - dds_entity_t observer); + dds_entity *observer, + dds_entity_callback cb, + dds_entity_delete_callback delete_cb); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t dds_entity_observer_unregister( - dds_entity_t observed, - dds_entity_t observer); + dds_entity *observed, + dds_entity *observer); DDS_EXPORT dds_return_t dds_delete_impl( diff --git a/src/core/ddsc/src/dds__get_status.h b/src/core/ddsc/src/dds__get_status.h new file mode 100644 index 0000000..3dec7dc --- /dev/null +++ b/src/core/ddsc/src/dds__get_status.h @@ -0,0 +1,56 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef _DDS_GET_STATUS_H_ +#define _DDS_GET_STATUS_H_ + +#include "dds/ddsrt/countargs.h" + +#define DDS_GET_STATUS_LOCKED_RESET_1(status_, reset0_) \ + (ent->m_##status_##_status.reset0_ = 0); +#define DDS_GET_STATUS_LOCKED_RESET_2(status_, reset0_, reset1_) \ + (ent->m_##status_##_status.reset0_ = 0); \ + (ent->m_##status_##_status.reset1_ = 0); +#define DDS_GET_STATUS_LOCKED_RESET_MSVC_WORKAROUND(x) x +#define DDS_GET_STATUS_LOCKED_RESET_N1(n_, status_, ...) \ + DDS_GET_STATUS_LOCKED_RESET_MSVC_WORKAROUND (DDS_GET_STATUS_LOCKED_RESET_##n_ (status_, __VA_ARGS__)) +#define DDS_GET_STATUS_LOCKED_RESET_N(n_, status_, ...) DDS_GET_STATUS_LOCKED_RESET_N1 (n_, status_, __VA_ARGS__) + +#define DDS_GET_STATUS_LOCKED(ent_type_, status_, STATUS_, ...) \ + static void dds_get_##status_##_status_locked (dds_##ent_type_ *ent, dds_##status_##_status_t *status) \ + { \ + if (status) \ + *status = ent->m_##status_##_status; \ + if (ddsrt_atomic_ld32 (&ent->m_entity.m_status.m_status_and_mask) & (DDS_##STATUS_##_STATUS << SAM_ENABLED_SHIFT)) { \ + do { DDS_GET_STATUS_LOCKED_RESET_N (DDSRT_COUNT_ARGS (__VA_ARGS__), status_, __VA_ARGS__) } while (0); \ + dds_entity_status_reset (&ent->m_entity, DDS_##STATUS_##_STATUS); \ + } \ + } + +#define DDS_GET_STATUS_COMMON(ent_type_, status_) \ + dds_return_t dds_get_##status_##_status (dds_entity_t entity, dds_##status_##_status_t *status) \ + { \ + dds_##ent_type_ *ent; \ + dds_return_t ret; \ + if ((ret = dds_##ent_type_##_lock (entity, &ent)) != DDS_RETCODE_OK) \ + return ret; \ + ddsrt_mutex_lock (&ent->m_entity.m_observers_lock); \ + dds_get_##status_##_status_locked (ent, status); \ + ddsrt_mutex_unlock (&ent->m_entity.m_observers_lock); \ + dds_##ent_type_##_unlock (ent); \ + return DDS_RETCODE_OK; \ + } + +#define DDS_GET_STATUS(ent_type_, status_, STATUS_, ...) \ + DDS_GET_STATUS_LOCKED (ent_type_, status_, STATUS_, __VA_ARGS__) \ + DDS_GET_STATUS_COMMON (ent_type_, status_) + +#endif diff --git a/src/core/ddsc/src/dds__handles.h b/src/core/ddsc/src/dds__handles.h index c13bc59..46bf594 100644 --- a/src/core/ddsc/src/dds__handles.h +++ b/src/core/ddsc/src/dds__handles.h @@ -78,7 +78,7 @@ struct dds_handle_link { * Initialize handleserver singleton. */ DDS_EXPORT dds_return_t -dds_handle_server_init(void (*free_via_gc) (void *x)); +dds_handle_server_init(void); /* @@ -145,13 +145,13 @@ dds_handle_delete( * Returns OK when succeeded. */ DDS_EXPORT int32_t -dds_handle_claim( +dds_handle_pin( dds_handle_t hdl, struct dds_handle_link **entity); DDS_EXPORT void -dds_handle_claim_inc( +dds_handle_repin( struct dds_handle_link *link); @@ -159,7 +159,7 @@ dds_handle_claim_inc( * The active claims count is decreased. */ DDS_EXPORT void -dds_handle_release( +dds_handle_unpin( struct dds_handle_link *link); @@ -177,6 +177,9 @@ dds_handle_is_closed( struct dds_handle_link *link); +DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link); +DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds__init.h b/src/core/ddsc/src/dds__init.h index 859a459..57d41a3 100644 --- a/src/core/ddsc/src/dds__init.h +++ b/src/core/ddsc/src/dds__init.h @@ -18,9 +18,6 @@ extern "C" { #endif -dds_return_t -dds__check_domain(dds_domainid_t domain); - /** *Description : Initialization function, called from main. This operation *initializes all the required DDS resources, @@ -30,8 +27,7 @@ dds__check_domain(dds_domainid_t domain); *Arguments : *-# Returns 0 on success or a non-zero error status **/ -dds_return_t -dds_init(dds_domainid_t domain); +dds_return_t dds_init (void); /* Finalization function, called from main */ @@ -42,16 +38,7 @@ dds_init(dds_domainid_t domain); *Arguments : *-# None **/ -void -dds_fini(void); - -/** - * Description : Function that provides the explicit ID of default domain - * It should be called after DDS initialization. - * @return Valid domain id. Undetermined behaviour if DDS is not initialized. - */ -dds_domainid_t dds_domain_default (void); - +void dds_fini (void); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__qos.h b/src/core/ddsc/src/dds__qos.h index eec04ff..be21eb9 100644 --- a/src/core/ddsc/src/dds__qos.h +++ b/src/core/ddsc/src/dds__qos.h @@ -12,24 +12,43 @@ #ifndef _DDS_QOS_H_ #define _DDS_QOS_H_ -#include "dds__entity.h" #include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/q_time.h" -#include "dds/ddsi/q_plist.h" #if defined (__cplusplus) extern "C" { #endif -bool validate_deadline_and_timebased_filter (const nn_duration_t deadline, const nn_duration_t minimum_separation); -bool validate_entityfactory_qospolicy (const nn_entity_factory_qospolicy_t * entityfactory); -bool validate_octetseq (const nn_octetseq_t* seq); -bool validate_partition_qospolicy (const nn_partition_qospolicy_t * partition); -bool validate_reliability_qospolicy (const nn_reliability_qospolicy_t * reliability); -bool validate_stringseq (const nn_stringseq_t* seq); +#define DDS_TOPIC_QOS_MASK \ + (QP_TOPIC_DATA | QP_DURABILITY | QP_DURABILITY_SERVICE | \ + QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | \ + QP_RELIABILITY | QP_TRANSPORT_PRIORITY | QP_LIFESPAN | \ + QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS) -bool dds_qos_validate_common (const dds_qos_t *qos); -dds_return_t dds_qos_validate_mutable_common (const dds_qos_t *qos); +#define DDS_PARTICIPANT_QOS_MASK \ + (QP_USER_DATA | QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + +#define DDS_PUBLISHER_QOS_MASK \ + (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ + QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + +#define DDS_READER_QOS_MASK \ + (QP_USER_DATA | QP_DURABILITY | QP_DEADLINE | QP_LATENCY_BUDGET | \ + QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \ + QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \ + QP_RESOURCE_LIMITS | QP_PRISMTECH_READER_DATA_LIFECYCLE | \ + QP_CYCLONE_IGNORELOCAL) + +#define DDS_SUBSCRIBER_QOS_MASK \ + (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ + QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + +#define DDS_WRITER_QOS_MASK \ + (QP_USER_DATA | QP_DURABILITY | QP_DURABILITY_SERVICE | QP_DEADLINE | \ + QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_OWNERSHIP_STRENGTH | \ + QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \ + QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \ + QP_RESOURCE_LIMITS | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | \ + QP_CYCLONE_IGNORELOCAL) #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__rhc.h b/src/core/ddsc/src/dds__rhc.h index fc08a7f..0275b39 100644 --- a/src/core/ddsc/src/dds__rhc.h +++ b/src/core/ddsc/src/dds__rhc.h @@ -12,60 +12,81 @@ #ifndef _DDS_RHC_H_ #define _DDS_RHC_H_ +#include "dds/ddsrt/static_assert.h" +#include "dds/ddsi/q_rhc.h" +#include "dds__types.h" /* for dds_readcond */ + #define NO_STATE_MASK_SET (DDS_ANY_STATE + 1) #if defined (__cplusplus) extern "C" { #endif -struct rhc; -struct nn_xqos; -struct ddsi_serdata; -struct ddsi_tkmap_instance; -struct proxy_writer_info; +struct dds_rhc; -DDS_EXPORT struct rhc *dds_rhc_new (dds_reader *reader, const struct ddsi_sertopic *topic); -DDS_EXPORT void dds_rhc_free (struct rhc *rhc); +typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); +typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); +typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); -DDS_EXPORT uint32_t dds_rhc_lock_samples (struct rhc *rhc); +typedef bool (*dds_rhc_add_readcondition_t) (struct dds_readcond *cond); +typedef void (*dds_rhc_remove_readcondition_t) (struct dds_readcond *cond); -DDS_EXPORT bool dds_rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); -DDS_EXPORT void dds_rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); -DDS_EXPORT void dds_rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid); +typedef uint32_t (*dds_rhc_lock_samples_t) (struct dds_rhc *rhc); -DDS_EXPORT int -dds_rhc_read( - struct rhc *rhc, - bool lock, - void ** values, - dds_sample_info_t *info_seq, - uint32_t max_samples, - uint32_t mask, - dds_instance_handle_t handle, - dds_readcond *cond); -DDS_EXPORT int -dds_rhc_take( - struct rhc *rhc, - bool lock, - void ** values, - dds_sample_info_t *info_seq, - uint32_t max_samples, - uint32_t mask, - dds_instance_handle_t handle, - dds_readcond *cond); +struct dds_rhc_ops { + /* A copy of DDSI rhc ops comes first so we can use either interface without + additional indirections */ + struct rhc_ops rhc_ops; + dds_rhc_read_t read; + dds_rhc_take_t take; + dds_rhc_takecdr_t takecdr; + dds_rhc_add_readcondition_t add_readcondition; + dds_rhc_remove_readcondition_t remove_readcondition; + dds_rhc_lock_samples_t lock_samples; +}; -DDS_EXPORT void dds_rhc_set_qos (struct rhc * rhc, const struct nn_xqos * qos); +struct dds_rhc { + union { + const struct dds_rhc_ops *ops; + struct rhc rhc; + } common; +}; -DDS_EXPORT bool dds_rhc_add_readcondition (dds_readcond * cond); -DDS_EXPORT void dds_rhc_remove_readcondition (dds_readcond * cond); +DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct rhc, ops)); -DDS_EXPORT int dds_rhc_takecdr -( - struct rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, - uint32_t max_samples, unsigned sample_states, - unsigned view_states, unsigned instance_states, - dds_instance_handle_t handle -); +DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) { + return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, pwr_info, sample, tk); +} +DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) { + rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, pwr_info); +} +DDS_EXPORT inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid) { + rhc->common.ops->rhc_ops.relinquish_ownership (&rhc->common.rhc, wr_iid); +} +DDS_EXPORT inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *qos) { + rhc->common.ops->rhc_ops.set_qos (&rhc->common.rhc, qos); +} +DDS_EXPORT inline void dds_rhc_free (struct dds_rhc *rhc) { + rhc->common.ops->rhc_ops.free (&rhc->common.rhc); +} +DDS_EXPORT inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { + return (rhc->common.ops->read) (rhc, lock, values, info_seq, max_samples, mask, handle, cond); +} +DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { + return rhc->common.ops->take (rhc, lock, values, info_seq, max_samples, mask, handle, cond); +} +DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { + return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); +} +DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_readcond *cond) { + return cond->m_rhc->common.ops->add_readcondition (cond); +} +DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_readcond *cond) { + cond->m_rhc->common.ops->remove_readcondition (cond); +} +DDS_EXPORT inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc) { + return rhc->common.ops->lock_samples (rhc); +} #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__key.h b/src/core/ddsc/src/dds__rhc_default.h similarity index 57% rename from src/core/ddsc/src/dds__key.h rename to src/core/ddsc/src/dds__rhc_default.h index b01f8bf..654577a 100644 --- a/src/core/ddsc/src/dds__key.h +++ b/src/core/ddsc/src/dds__rhc_default.h @@ -9,25 +9,20 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef _DDS_KEY_H_ -#define _DDS_KEY_H_ - -#include "dds__types.h" - -struct dds_key_hash; +#ifndef _DDS_RHC_DEFAULT_H_ +#define _DDS_RHC_DEFAULT_H_ #if defined (__cplusplus) extern "C" { #endif -void dds_key_md5 (struct dds_key_hash * kh); +struct dds_rhc; +struct dds_reader; +struct ddsi_sertopic; +struct q_globals; -void dds_key_gen -( - const dds_topic_descriptor_t * const desc, - struct dds_key_hash * kh, - const char * sample -); +DDS_EXPORT struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_globals *gv, const struct ddsi_sertopic *topic, bool xchecks); +DDS_EXPORT struct dds_rhc *dds_rhc_default_new (struct dds_reader *reader, const struct ddsi_sertopic *topic); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__serdata_builtintopic.h b/src/core/ddsc/src/dds__serdata_builtintopic.h index 1c4d548..0fa180d 100644 --- a/src/core/ddsc/src/dds__serdata_builtintopic.h +++ b/src/core/ddsc/src/dds__serdata_builtintopic.h @@ -24,7 +24,7 @@ struct ddsi_serdata_builtintopic { struct ddsi_serdata c; nn_guid_t key; dds_instance_handle_t pphandle; - nn_xqos_t xqos; + dds_qos_t xqos; }; enum ddsi_sertopic_builtintopic_type { @@ -33,15 +33,17 @@ enum ddsi_sertopic_builtintopic_type { DSBT_WRITER }; +struct q_globals; struct ddsi_sertopic_builtintopic { struct ddsi_sertopic c; enum ddsi_sertopic_builtintopic_type type; + struct q_globals *gv; }; extern const struct ddsi_sertopic_ops ddsi_sertopic_ops_builtintopic; extern const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic; -struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename); +struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename, struct q_globals *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__stream.h b/src/core/ddsc/src/dds__stream.h index 79eadd1..347f667 100644 --- a/src/core/ddsc/src/dds__stream.h +++ b/src/core/ddsc/src/dds__stream.h @@ -19,47 +19,46 @@ extern "C" { #endif -void dds_stream_write_sample -( - dds_stream_t * os, - const void * data, - const struct ddsi_sertopic_default * topic -); -void dds_stream_read_sample -( - dds_stream_t * is, - void * data, - const struct ddsi_sertopic_default * topic -); +typedef struct dds_istream { + const unsigned char *m_buffer; + uint32_t m_size; /* Buffer size */ + uint32_t m_index; /* Read/write offset from start of buffer */ +} dds_istream_t; -size_t dds_stream_check_optimize (const dds_topic_descriptor_t * desc); -void dds_stream_from_serdata_default (dds_stream_t * s, const struct ddsi_serdata_default *d); -void dds_stream_add_to_serdata_default (dds_stream_t * s, struct ddsi_serdata_default **d); +typedef struct dds_ostream { + unsigned char *m_buffer; + uint32_t m_size; /* Buffer size */ + uint32_t m_index; /* Read/write offset from start of buffer */ +} dds_ostream_t; -void dds_stream_write_key (dds_stream_t * os, const char * sample, const struct ddsi_sertopic_default * topic); -uint32_t dds_stream_extract_key (dds_stream_t *is, dds_stream_t *os, const uint32_t *ops, const bool just_key); -void dds_stream_read_key -( - dds_stream_t * is, - char * sample, - const dds_topic_descriptor_t * desc -); -void dds_stream_read_keyhash -( - dds_stream_t * is, - dds_key_hash_t * kh, - const dds_topic_descriptor_t * desc, - const bool just_key -); -char * dds_stream_reuse_string -( - dds_stream_t * is, - char * str, - const uint32_t bound -); -DDS_EXPORT void dds_stream_swap (void * buff, uint32_t size, uint32_t num); +typedef struct dds_ostreamBE { + dds_ostream_t x; +} dds_ostreamBE_t; -extern const uint32_t dds_op_size[5]; +DDS_EXPORT void dds_ostream_init (dds_ostream_t * __restrict st, uint32_t size); +DDS_EXPORT void dds_ostream_fini (dds_ostream_t * __restrict st); +DDS_EXPORT void dds_ostreamBE_init (dds_ostreamBE_t * __restrict st, uint32_t size); +DDS_EXPORT void dds_ostreamBE_fini (dds_ostreamBE_t * __restrict st); + +bool dds_stream_normalize (void * __restrict data, uint32_t size, bool bswap, const struct ddsi_sertopic_default * __restrict topic, bool just_key); + +void dds_stream_write_sample (dds_ostream_t * __restrict os, const void * __restrict data, const struct ddsi_sertopic_default * __restrict topic); +void dds_stream_read_sample (dds_istream_t * __restrict is, void * __restrict data, const struct ddsi_sertopic_default * __restrict topic); + +size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc); +void dds_istream_from_serdata_default (dds_istream_t * __restrict s, const struct ddsi_serdata_default * __restrict d); +void dds_ostream_from_serdata_default (dds_ostream_t * __restrict s, struct ddsi_serdata_default * __restrict d); +void dds_ostream_add_to_serdata_default (dds_ostream_t * __restrict s, struct ddsi_serdata_default ** __restrict d); +void dds_ostreamBE_from_serdata_default (dds_ostreamBE_t * __restrict s, struct ddsi_serdata_default * __restrict d); +void dds_ostreamBE_add_to_serdata_default (dds_ostreamBE_t * __restrict s, struct ddsi_serdata_default ** __restrict d); + +void dds_stream_write_key (dds_ostream_t * __restrict os, const char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic); +void dds_stream_write_keyBE (dds_ostreamBE_t * __restrict os, const char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic); +void dds_stream_extract_key_from_data (dds_istream_t * __restrict is, dds_ostream_t * __restrict os, const struct ddsi_sertopic_default * __restrict topic); +void dds_stream_extract_keyBE_from_data (dds_istream_t * __restrict is, dds_ostreamBE_t * __restrict os, const struct ddsi_sertopic_default * __restrict topic); +void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t * __restrict kh, const struct ddsi_sertopic_default * __restrict topic, const bool just_key); + +void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic); /* For marshalling op code handling */ @@ -70,14 +69,14 @@ extern const uint32_t dds_op_size[5]; #define DDS_OP_FLAGS_MASK 0x000000ff #define DDS_JEQ_TYPE_MASK 0x00ff0000 -#define DDS_OP(o) ((o) & DDS_OP_MASK) -#define DDS_OP_TYPE(o) (((o) & DDS_OP_TYPE_MASK) >> 16) -#define DDS_OP_SUBTYPE(o) (((o) & DDS_OP_SUBTYPE_MASK) >> 8) -#define DDS_OP_FLAGS(o) ((o) & DDS_OP_FLAGS_MASK) +#define DDS_OP(o) ((enum dds_stream_opcode) ((o) & DDS_OP_MASK)) +#define DDS_OP_TYPE(o) ((enum dds_stream_typecode) (((o) & DDS_OP_TYPE_MASK) >> 16)) +#define DDS_OP_SUBTYPE(o) ((enum dds_stream_typecode) (((o) & DDS_OP_SUBTYPE_MASK) >> 8)) +#define DDS_OP_FLAGS(o) ((o) & DDS_OP_FLAGS_MASK) #define DDS_OP_ADR_JSR(o) ((o) & DDS_OP_JMP_MASK) -#define DDS_OP_JUMP(o) ((int16_t) ((o) & DDS_OP_JMP_MASK)) +#define DDS_OP_JUMP(o) ((int16_t) ((o) & DDS_OP_JMP_MASK)) #define DDS_OP_ADR_JMP(o) ((o) >> 16) -#define DDS_JEQ_TYPE(o) (((o) & DDS_JEQ_TYPE_MASK) >> 16) +#define DDS_JEQ_TYPE(o) ((enum dds_stream_typecode) (((o) & DDS_JEQ_TYPE_MASK) >> 16)) #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__subscriber.h b/src/core/ddsc/src/dds__subscriber.h index c104255..966f43e 100644 --- a/src/core/ddsc/src/dds__subscriber.h +++ b/src/core/ddsc/src/dds__subscriber.h @@ -23,7 +23,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_subscriber, DDS_KIND_SUBSCRIBER) dds_entity_t dds__create_subscriber_l( - struct dds_entity *participant, /* entity-lock must be held */ + struct dds_participant *participant, /* entity-lock must be held */ const dds_qos_t *qos, const dds_listener_t *listener); diff --git a/src/core/ddsc/src/dds__topic.h b/src/core/ddsc/src/dds__topic.h index 7cba5a5..d59dc1f 100644 --- a/src/core/ddsc/src/dds__topic.h +++ b/src/core/ddsc/src/dds__topic.h @@ -21,8 +21,8 @@ extern "C" { DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_topic, DDS_KIND_TOPIC) -DDS_EXPORT struct ddsi_sertopic * dds_topic_lookup (dds_domain * domain, const char * name); -DDS_EXPORT void dds_topic_free (dds_domainid_t domainid, struct ddsi_sertopic * st); +DDS_EXPORT struct ddsi_sertopic * dds_topic_lookup (dds_domain * domain, const char * name) ddsrt_nonnull_all; +DDS_EXPORT void dds_topic_free (dds_domainid_t domainid, struct ddsi_sertopic * st) ddsrt_nonnull_all; #ifndef DDS_TOPIC_INTERN_FILTER_FN_DEFINED #define DDS_TOPIC_INTERN_FILTER_FN_DEFINED diff --git a/src/core/ddsc/src/dds__types.h b/src/core/ddsc/src/dds__types.h index 61c7c57..f6b7a67 100644 --- a/src/core/ddsc/src/dds__types.h +++ b/src/core/ddsc/src/dds__types.h @@ -17,7 +17,9 @@ #include "dds/dds.h" #include "dds/ddsrt/sync.h" #include "dds/ddsi/q_rtps.h" +#include "dds/ddsi/q_globals.h" #include "dds/ddsrt/avl.h" +#include "dds/ddsi/ddsi_builtin_topic_if.h" #include "dds__handles.h" #if defined (__cplusplus) @@ -39,12 +41,11 @@ struct dds_statuscond; struct ddsi_sertopic; struct rhc; -/* Internal entity status flags */ - -#define DDS_INTERNAL_STATUS_MASK (0xFF000000u) - -#define DDS_WAITSET_TRIGGER_STATUS (0x01000000u) -#define DDS_DELETING_STATUS (0x02000000u) +typedef uint16_t status_mask_t; +typedef ddsrt_atomic_uint32_t status_and_enabled_t; +#define SAM_STATUS_MASK 0xffffu +#define SAM_ENABLED_MASK 0xffff0000u +#define SAM_ENABLED_SHIFT 16 /* This can be used when polling for various states. * Obviously, it is encouraged to use condition variables and such. But @@ -92,96 +93,143 @@ struct dds_listener { #define DDS_ENTITY_ENABLED 0x0001u #define DDS_ENTITY_IMPLICIT 0x0002u -typedef struct dds_domain -{ +typedef struct dds_domain { + /* FIXME: protected by dds_global.lock -- for now */ ddsrt_avl_node_t m_node; dds_domainid_t m_id; ddsrt_avl_tree_t m_topics; + ddsrt_avl_tree_t m_ppants; uint32_t m_refc; -} -dds_domain; + struct cfgst *cfgst; + + struct ddsi_sertopic *builtin_participant_topic; + struct ddsi_sertopic *builtin_reader_topic; + struct ddsi_sertopic *builtin_writer_topic; + + struct local_orphan_writer *builtintopic_writer_participant; + struct local_orphan_writer *builtintopic_writer_publications; + struct local_orphan_writer *builtintopic_writer_subscriptions; + + struct ddsi_builtin_topic_interface btif; + struct q_globals gv; +} dds_domain; struct dds_entity; typedef struct dds_entity_deriver { - /* Close can be used to terminate (blocking) actions on a entity before actually deleting it. */ - dds_return_t (*close)(struct dds_entity *e); - /* Delete is used to actually free the entity. */ - dds_return_t (*delete)(struct dds_entity *e); - dds_return_t (*set_qos)(struct dds_entity *e, const dds_qos_t *qos, bool enabled); - dds_return_t (*validate_status)(uint32_t mask); - dds_return_t (*get_instance_hdl)(struct dds_entity *e, dds_instance_handle_t *i); -} -dds_entity_deriver; + /* Close can be used to terminate (blocking) actions on a entity before actually deleting it. */ + dds_return_t (*close)(struct dds_entity *e) ddsrt_nonnull_all; + /* Delete is used to actually free the entity. */ + dds_return_t (*delete)(struct dds_entity *e) ddsrt_nonnull_all; + dds_return_t (*set_qos)(struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all; + dds_return_t (*validate_status)(uint32_t mask); +} dds_entity_deriver; -typedef void (*dds_entity_callback)(dds_entity_t observer, dds_entity_t observed, uint32_t status); +typedef void (*dds_entity_callback)(struct dds_entity *observer, dds_entity_t observed, uint32_t status); +typedef void (*dds_entity_delete_callback)(struct dds_entity *observer, dds_entity_t observed); -typedef struct dds_entity_observer -{ - dds_entity_callback m_cb; - dds_entity_t m_observer; - struct dds_entity_observer *m_next; -} -dds_entity_observer; +typedef struct dds_entity_observer { + dds_entity_callback m_cb; + dds_entity_delete_callback m_delete_cb; + struct dds_entity *m_observer; + struct dds_entity_observer *m_next; +} dds_entity_observer; -typedef struct dds_entity -{ - struct dds_handle_link m_hdllink; - dds_entity_kind_t m_kind; - dds_entity_deriver m_deriver; - uint32_t m_refc; - struct dds_entity * m_next; - struct dds_entity * m_parent; - struct dds_entity * m_children; - struct dds_entity * m_participant; - struct dds_domain * m_domain; - dds_qos_t * m_qos; - dds_domainid_t m_domainid; - nn_guid_t m_guid; - uint32_t m_flags; +typedef struct dds_entity { + struct dds_handle_link m_hdllink; /* handle is constant, cnt_flags private to dds_handle.c */ + dds_entity_kind_t m_kind; /* constant */ + struct dds_entity *m_next; /* [m_mutex] */ + struct dds_entity *m_parent; /* constant */ + ddsrt_avl_node_t m_avlnode_child; /* [m_mutex of m_parent] */ + ddsrt_avl_tree_t m_children; /* [m_mutex] tree on m_iid using m_avlnode_child */ + struct dds_entity *m_participant; /* constant */ + struct dds_domain *m_domain; /* constant */ + dds_qos_t *m_qos; /* [m_mutex] */ + nn_guid_t m_guid; /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */ + dds_instance_handle_t m_iid; /* unique for all time, constant; FIXME: like GUID */ + uint32_t m_flags; /* [m_mutex] */ + + /* Allowed: + - locking parent->...->m_mutex while holding m_mutex + - locking topic::m_mutex while holding {publisher,subscriber}::m_mutex + (no hierarchical relationship there) + - locking topic::m_mutex while holding {reader,writer}::m_mutex + - locking observers_lock while holding m_mutex + */ ddsrt_mutex_t m_mutex; ddsrt_cond_t m_cond; - ddsrt_mutex_t m_observers_lock; + union { + status_and_enabled_t m_status_and_mask; /* for most entities */ + ddsrt_atomic_uint32_t m_trigger; /* for conditions & waitsets */ + } m_status; + + ddsrt_mutex_t m_observers_lock; /* locking parent->...->m_observers_lock while holding it is allowed */ ddsrt_cond_t m_observers_cond; - dds_listener_t m_listener; - uint32_t m_trigger; - uint32_t m_status_enable; - uint32_t m_cb_count; - dds_entity_observer *m_observers; -} -dds_entity; + dds_listener_t m_listener; /* [m_observers_lock] */ + uint32_t m_cb_count; /* [m_observers_lock] */ + dds_entity_observer *m_observers; /* [m_observers_lock] */ +} dds_entity; extern const ddsrt_avl_treedef_t dds_topictree_def; +extern const ddsrt_avl_treedef_t dds_entity_children_td; -typedef struct dds_subscriber -{ - struct dds_entity m_entity; +extern const struct dds_entity_deriver dds_entity_deriver_topic; +extern const struct dds_entity_deriver dds_entity_deriver_participant; +extern const struct dds_entity_deriver dds_entity_deriver_reader; +extern const struct dds_entity_deriver dds_entity_deriver_writer; +extern const struct dds_entity_deriver dds_entity_deriver_subscriber; +extern const struct dds_entity_deriver dds_entity_deriver_publisher; +extern const struct dds_entity_deriver dds_entity_deriver_readcondition; +extern const struct dds_entity_deriver dds_entity_deriver_guardcondition; +extern const struct dds_entity_deriver dds_entity_deriver_waitset; +extern const struct dds_entity_deriver *dds_entity_deriver_table[]; + +dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e); +dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e); +dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled); +dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask); + + +inline dds_return_t dds_entity_deriver_close (struct dds_entity *e) { + return (dds_entity_deriver_table[e->m_kind]->close) (e); } -dds_subscriber; - -typedef struct dds_publisher -{ - struct dds_entity m_entity; +inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e) { + return dds_entity_deriver_table[e->m_kind]->delete (e); +} +inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled) { + return dds_entity_deriver_table[e->m_kind]->set_qos (e, qos, enabled); +} +inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask) { + return dds_entity_deriver_table[e->m_kind]->validate_status (mask); +} +inline bool dds_entity_supports_set_qos (struct dds_entity *e) { + return dds_entity_deriver_table[e->m_kind]->set_qos != dds_entity_deriver_dummy_set_qos; +} +inline bool dds_entity_supports_validate_status (struct dds_entity *e) { + return dds_entity_deriver_table[e->m_kind]->validate_status != dds_entity_deriver_dummy_validate_status; } -dds_publisher; -typedef struct dds_participant -{ +typedef struct dds_subscriber { + struct dds_entity m_entity; +} dds_subscriber; + +typedef struct dds_publisher { + struct dds_entity m_entity; +} dds_publisher; + +typedef struct dds_participant { struct dds_entity m_entity; - struct dds_entity * m_dur_reader; - struct dds_entity * m_dur_writer; dds_entity_t m_builtin_subscriber; -} -dds_participant; +} dds_participant; -typedef struct dds_reader -{ +typedef struct dds_reader { struct dds_entity m_entity; - const struct dds_topic * m_topic; - struct reader * m_rd; + const struct dds_topic *m_topic; + struct dds_rhc *m_rhc; /* aliases m_rd->rhc with a wider interface, FIXME: but m_rd owns it for resource management */ + struct reader *m_rd; bool m_data_on_readers; bool m_loan_out; - void * m_loan; + void *m_loan; uint32_t m_loan_size; /* Status metrics */ @@ -192,16 +240,15 @@ typedef struct dds_reader dds_requested_incompatible_qos_status_t m_requested_incompatible_qos_status; dds_sample_lost_status_t m_sample_lost_status; dds_subscription_matched_status_t m_subscription_matched_status; -} -dds_reader; +} dds_reader; -typedef struct dds_writer -{ +typedef struct dds_writer { struct dds_entity m_entity; - const struct dds_topic * m_topic; - struct nn_xpack * m_xp; - struct writer * m_wr; + const struct dds_topic *m_topic; + struct nn_xpack *m_xp; + struct writer *m_wr; struct whc *m_whc; /* FIXME: ownership still with underlying DDSI writer (cos of DDSI built-in writers )*/ + bool whc_batch; /* FIXME: channels + latency budget */ /* Status metrics */ @@ -209,84 +256,68 @@ typedef struct dds_writer dds_offered_deadline_missed_status_t m_offered_deadline_missed_status; dds_offered_incompatible_qos_status_t m_offered_incompatible_qos_status; dds_publication_matched_status_t m_publication_matched_status; -} -dds_writer; +} dds_writer; #ifndef DDS_TOPIC_INTERN_FILTER_FN_DEFINED #define DDS_TOPIC_INTERN_FILTER_FN_DEFINED typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx); #endif -typedef struct dds_topic -{ +typedef struct dds_topic { struct dds_entity m_entity; - struct ddsi_sertopic * m_stopic; + struct ddsi_sertopic *m_stopic; dds_topic_intern_filter_fn filter_fn; - void * filter_ctx; + void *filter_ctx; /* Status metrics */ dds_inconsistent_topic_status_t m_inconsistent_topic_status; -} -dds_topic; +} dds_topic; typedef uint32_t dds_querycond_mask_t; -typedef struct dds_readcond -{ +typedef struct dds_readcond { dds_entity m_entity; - struct rhc * m_rhc; + struct dds_rhc *m_rhc; uint32_t m_qminv; uint32_t m_sample_states; uint32_t m_view_states; uint32_t m_instance_states; nn_guid_t m_rd_guid; - struct dds_readcond * m_next; - struct - { - dds_querycondition_filter_fn m_filter; - dds_querycond_mask_t m_qcmask; /* condition mask in RHC*/ + struct dds_readcond *m_next; + struct { + dds_querycondition_filter_fn m_filter; + dds_querycond_mask_t m_qcmask; /* condition mask in RHC*/ } m_query; -} -dds_readcond; +} dds_readcond; -typedef struct dds_guardcond -{ +typedef struct dds_guardcond { dds_entity m_entity; -} -dds_guardcond; +} dds_guardcond; -typedef struct dds_attachment -{ - dds_entity *entity; - dds_attach_t arg; - struct dds_attachment* next; -} -dds_attachment; +typedef struct dds_attachment { + dds_entity *entity; + dds_entity_t handle; + dds_attach_t arg; +} dds_attachment; -typedef struct dds_waitset -{ +typedef struct dds_waitset { dds_entity m_entity; - dds_attachment *observed; - dds_attachment *triggered; -} -dds_waitset; + size_t nentities; /* [m_entity.m_mutex] */ + size_t ntriggered; /* [m_entity.m_mutex] */ + dds_attachment *entities; /* [m_entity.m_mutex] 0 .. ntriggered are triggred, ntriggred .. nentities are not */ +} dds_waitset; /* Globals */ -typedef struct dds_globals -{ - dds_domainid_t m_default_domain; +typedef struct dds_globals { int32_t m_init_count; - void (*m_dur_reader) (struct dds_reader * reader, struct rhc * rhc); - int (*m_dur_wait) (struct dds_reader * reader, dds_duration_t timeout); - void (*m_dur_init) (void); - void (*m_dur_fini) (void); ddsrt_avl_tree_t m_domains; ddsrt_mutex_t m_mutex; -} -dds_globals; + uint32_t threadmon_count; + struct ddsi_threadmon *threadmon; +} dds_globals; DDS_EXPORT extern dds_globals dds_global; diff --git a/src/core/ddsc/src/dds__whc.h b/src/core/ddsc/src/dds__whc.h index 13b542d..dcaeb42 100644 --- a/src/core/ddsc/src/dds__whc.h +++ b/src/core/ddsc/src/dds__whc.h @@ -18,7 +18,8 @@ extern "C" { #endif -struct whc *whc_new (int is_transient_local, unsigned hdepth, unsigned tldepth); +struct q_globals; +struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdepth, uint32_t tldepth); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__whc_builtintopic.h b/src/core/ddsc/src/dds__whc_builtintopic.h index 47772fe..650addb 100644 --- a/src/core/ddsc/src/dds__whc_builtintopic.h +++ b/src/core/ddsc/src/dds__whc_builtintopic.h @@ -19,7 +19,7 @@ extern "C" { #endif -struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type); +struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct ephash *guid_hash); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__write.h b/src/core/ddsc/src/dds__write.h index 134b950..d868602 100644 --- a/src/core/ddsc/src/dds__write.h +++ b/src/core/ddsc/src/dds__write.h @@ -31,7 +31,7 @@ typedef enum { dds_return_t dds_write_impl (dds_writer *wr, const void *data, dds_time_t tstamp, dds_write_action action); dds_return_t dds_writecdr_impl (dds_writer *wr, struct ddsi_serdata *d, dds_time_t tstamp, dds_write_action action); -dds_return_t dds_writecdr_impl_lowlevel (struct writer *ddsi_wr, struct nn_xpack *xp, struct ddsi_serdata *d); +dds_return_t dds_writecdr_impl_lowlevel (struct writer *ddsi_wr, struct nn_xpack *xp, struct ddsi_serdata *d, bool flush); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds_alloc.c b/src/core/ddsc/src/dds_alloc.c index 954f77d..7ff7779 100644 --- a/src/core/ddsc/src/dds_alloc.c +++ b/src/core/ddsc/src/dds_alloc.c @@ -87,7 +87,7 @@ void dds_string_free (char * str) dds_free (str); } -void dds_sample_free_contents (char * data, const uint32_t * ops) +void dds_sample_free_contents (char *data, const uint32_t * ops) { uint32_t op; uint32_t type; @@ -179,6 +179,8 @@ void dds_sample_free_contents (char * data, const uint32_t * ops) if (seq->_release) { dds_free (seq->_buffer); + seq->_maximum = 0; + seq->_length = 0; seq->_buffer = NULL; } break; diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c index fff187a..1c5a326 100644 --- a/src/core/ddsc/src/dds_builtin.c +++ b/src/core/ddsc/src/dds_builtin.c @@ -11,14 +11,15 @@ */ #include #include +#include "dds/ddsrt/string.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/q_plist.h" /* for nn_keyhash */ #include "dds__init.h" -#include "dds__qos.h" #include "dds__domain.h" #include "dds__participant.h" -#include "dds__err.h" #include "dds__types.h" #include "dds__builtin.h" #include "dds__subscriber.h" @@ -29,13 +30,6 @@ #include "dds/ddsi/q_qosmatch.h" #include "dds/ddsi/ddsi_tkmap.h" -static struct ddsi_sertopic *builtin_participant_topic; -static struct ddsi_sertopic *builtin_reader_topic; -static struct ddsi_sertopic *builtin_writer_topic; -static struct local_orphan_writer *builtintopic_writer_participant; -static struct local_orphan_writer *builtintopic_writer_publications; -static struct local_orphan_writer *builtintopic_writer_subscriptions; - static dds_qos_t *dds__create_builtin_qos (void) { const char *partition = "__BUILT-IN PARTITION__"; @@ -47,93 +41,87 @@ static dds_qos_t *dds__create_builtin_qos (void) return qos; } -void dds__builtin_init (void) +dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic) { - dds_qos_t *qos = dds__create_builtin_qos (); - - builtin_participant_topic = new_sertopic_builtintopic (DSBT_PARTICIPANT, "DCPSParticipant", "org::eclipse::cyclonedds::builtin::DCPSParticipant"); - builtin_reader_topic = new_sertopic_builtintopic (DSBT_READER, "DCPSSubscription", "org::eclipse::cyclonedds::builtin::DCPSSubscription"); - builtin_writer_topic = new_sertopic_builtintopic (DSBT_WRITER, "DCPSPublication", "org::eclipse::cyclonedds::builtin::DCPSPublication"); - - builtintopic_writer_participant = new_local_orphan_writer (to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER), builtin_participant_topic, qos, builtintopic_whc_new (DSBT_PARTICIPANT)); - builtintopic_writer_publications = new_local_orphan_writer (to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER), builtin_writer_topic, qos, builtintopic_whc_new (DSBT_WRITER)); - builtintopic_writer_subscriptions = new_local_orphan_writer (to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER), builtin_reader_topic, qos, builtintopic_whc_new (DSBT_READER)); - - dds_delete_qos (qos); -} - -void dds__builtin_fini (void) -{ - /* No more sources for builtin topic samples */ - thread_state_awake (lookup_thread_state ()); - delete_local_orphan_writer (builtintopic_writer_participant); - delete_local_orphan_writer (builtintopic_writer_publications); - delete_local_orphan_writer (builtintopic_writer_subscriptions); - thread_state_asleep (lookup_thread_state ()); - - ddsi_sertopic_unref (builtin_participant_topic); - ddsi_sertopic_unref (builtin_reader_topic); - ddsi_sertopic_unref (builtin_writer_topic); -} - -dds_entity_t dds__get_builtin_topic (dds_entity_t e, dds_entity_t topic) -{ - dds_entity_t pp; dds_entity_t tp; + dds_return_t rc; + dds_entity *e; - if ((pp = dds_get_participant (e)) <= 0) - return pp; + if ((rc = dds_entity_pin (entity, &e)) < 0) + return rc; struct ddsi_sertopic *sertopic; - if (topic == DDS_BUILTIN_TOPIC_DCPSPARTICIPANT) { - sertopic = builtin_participant_topic; - } else if (topic == DDS_BUILTIN_TOPIC_DCPSPUBLICATION) { - sertopic = builtin_writer_topic; - } else if (topic == DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION) { - sertopic = builtin_reader_topic; - } else { - assert (0); - return DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); + switch (topic) + { + case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: + sertopic = e->m_domain->builtin_participant_topic; + break; + case DDS_BUILTIN_TOPIC_DCPSPUBLICATION: + sertopic = e->m_domain->builtin_writer_topic; + break; + case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION: + sertopic = e->m_domain->builtin_reader_topic; + break; + default: + assert (0); + dds_entity_unpin (e); + return DDS_RETCODE_BAD_PARAMETER; } dds_qos_t *qos = dds__create_builtin_qos (); - tp = dds_create_topic_arbitrary (pp, sertopic, qos, NULL, NULL); + tp = dds_create_topic_arbitrary (e->m_participant->m_hdllink.hdl, sertopic, qos, NULL, NULL); dds_delete_qos (qos); + dds_entity_unpin (e); return tp; } static bool qos_has_resource_limits (const dds_qos_t *qos) { + assert (qos->present & QP_RESOURCE_LIMITS); return (qos->resource_limits.max_samples != DDS_LENGTH_UNLIMITED || qos->resource_limits.max_instances != DDS_LENGTH_UNLIMITED || qos->resource_limits.max_samples_per_instance != DDS_LENGTH_UNLIMITED); } -bool dds__validate_builtin_reader_qos (dds_entity_t topic, const dds_qos_t *qos) +bool dds__validate_builtin_reader_qos (const dds_domain *dom, dds_entity_t topic, const dds_qos_t *qos) { if (qos == NULL) /* default QoS inherited from topic is ok by definition */ return true; else { - /* failing writes on built-in topics are unwelcome complications, so we simply forbid the creation of - a reader matching a built-in topics writer that has resource limits */ + /* failing writes on built-in topics are unwelcome complications, so we simply + forbid the creation of a reader matching a built-in topics writer that has + resource limits */ struct local_orphan_writer *bwr; - if (topic == DDS_BUILTIN_TOPIC_DCPSPARTICIPANT) { - bwr = builtintopic_writer_participant; - } else if (topic == DDS_BUILTIN_TOPIC_DCPSPUBLICATION) { - bwr = builtintopic_writer_publications; - } else if (topic == DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION) { - bwr = builtintopic_writer_subscriptions; - } else { - assert (0); - return false; + switch (topic) + { + case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: + bwr = dom->builtintopic_writer_participant; + break; + case DDS_BUILTIN_TOPIC_DCPSPUBLICATION: + bwr = dom->builtintopic_writer_publications; + break; + case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION: + bwr = dom->builtintopic_writer_subscriptions; + break; + default: + assert (0); + return false; } - return qos_match_p (qos, bwr->wr.xqos) && !qos_has_resource_limits (qos); + + /* FIXME: DDSI-level readers, writers have topic, type name in their QoS, but + DDSC-level ones don't and that gives an automatic mismatch when comparing + the full QoS object ... Here the two have the same topic by construction + so ignoring them in the comparison makes things work. The discrepancy + should be addressed one day. */ + const uint64_t qmask = ~(QP_TOPIC_NAME | QP_TYPE_NAME); + dds_qos_policy_id_t dummy; + return qos_match_mask_p (qos, bwr->wr.xqos, qmask, &dummy) && !qos_has_resource_limits (qos); } } -static dds_entity_t dds__create_builtin_subscriber (dds_entity *participant) +static dds_entity_t dds__create_builtin_subscriber (dds_participant *participant) { dds_qos_t *qos = dds__create_builtin_qos (); dds_entity_t sub = dds__create_subscriber_l (participant, qos, NULL); @@ -154,27 +142,37 @@ dds_entity_t dds__get_builtin_subscriber (dds_entity_t e) return ret; if (p->m_builtin_subscriber <= 0) { - p->m_builtin_subscriber = dds__create_builtin_subscriber (&p->m_entity); + p->m_builtin_subscriber = dds__create_builtin_subscriber (p); } sub = p->m_builtin_subscriber; dds_participant_unlock(p); return sub; } -bool dds__builtin_is_visible (nn_entityid_t entityid, bool onlylocal, nn_vendorid_t vendorid) +static bool dds__builtin_is_builtintopic (const struct ddsi_sertopic *tp, void *vdomain) { - return !(onlylocal || is_builtin_endpoint (entityid, vendorid)); + (void) vdomain; + return tp->ops == &ddsi_sertopic_ops_builtintopic; } -struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid) +static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendorid, void *vdomain) { + (void) vdomain; + if (is_builtin_endpoint (guid->entityid, vendorid)) + return false; + return true; +} + +static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid, void *vdomain) +{ + struct dds_domain *domain = vdomain; struct ddsi_tkmap_instance *tk; struct ddsi_serdata *sd; struct nn_keyhash kh; memcpy (&kh, guid, sizeof (kh)); /* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" of the topic, not the actual topic; also, this is called early in the initialisation of the entity with this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup fails. */ - sd = ddsi_serdata_from_keyhash (builtin_participant_topic, &kh); - tk = ddsi_tkmap_find (sd, false, true); + sd = ddsi_serdata_from_keyhash (domain->builtin_participant_topic, &kh); + tk = ddsi_tkmap_find (domain->gv.m_tkmap, sd, true); ddsi_serdata_unref (sd); return tk; } @@ -182,6 +180,7 @@ struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid * struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, nn_wctime_t timestamp, bool alive) { /* initialize to avoid gcc warning ultimately caused by C's horrible type system */ + struct dds_domain *dom = e->gv->builtin_topic_interface->arg; struct ddsi_sertopic *topic = NULL; struct ddsi_serdata *serdata; struct nn_keyhash keyhash; @@ -189,15 +188,15 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, nn { case EK_PARTICIPANT: case EK_PROXY_PARTICIPANT: - topic = builtin_participant_topic; + topic = dom->builtin_participant_topic; break; case EK_WRITER: case EK_PROXY_WRITER: - topic = builtin_writer_topic; + topic = dom->builtin_writer_topic; break; case EK_READER: case EK_PROXY_READER: - topic = builtin_reader_topic; + topic = dom->builtin_reader_topic; break; } assert (topic != NULL); @@ -208,9 +207,10 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, nn return serdata; } -void dds__builtin_write (const struct entity_common *e, nn_wctime_t timestamp, bool alive) +static void dds__builtin_write (const struct entity_common *e, nn_wctime_t timestamp, bool alive, void *vdomain) { - if (ddsi_plugin.builtintopic_is_visible (e->guid.entityid, e->onlylocal, get_entity_vendorid (e))) + struct dds_domain *dom = vdomain; + if (dds__builtin_is_visible (&e->guid, get_entity_vendorid (e), dom)) { /* initialize to avoid gcc warning ultimately caused by C's horrible type system */ struct local_orphan_writer *bwr = NULL; @@ -220,17 +220,54 @@ void dds__builtin_write (const struct entity_common *e, nn_wctime_t timestamp, b { case EK_PARTICIPANT: case EK_PROXY_PARTICIPANT: - bwr = builtintopic_writer_participant; + bwr = dom->builtintopic_writer_participant; break; case EK_WRITER: case EK_PROXY_WRITER: - bwr = builtintopic_writer_publications; + bwr = dom->builtintopic_writer_publications; break; case EK_READER: case EK_PROXY_READER: - bwr = builtintopic_writer_subscriptions; + bwr = dom->builtintopic_writer_subscriptions; break; } - dds_writecdr_impl_lowlevel (&bwr->wr, NULL, serdata); + dds_writecdr_impl_lowlevel (&bwr->wr, NULL, serdata, true); } } + +void dds__builtin_init (struct dds_domain *dom) +{ + dds_qos_t *qos = dds__create_builtin_qos (); + + dom->btif.arg = dom; + dom->btif.builtintopic_get_tkmap_entry = dds__builtin_get_tkmap_entry; + dom->btif.builtintopic_is_builtintopic = dds__builtin_is_builtintopic; + dom->btif.builtintopic_is_visible = dds__builtin_is_visible; + dom->btif.builtintopic_write = dds__builtin_write; + dom->gv.builtin_topic_interface = &dom->btif; + + dom->builtin_participant_topic = new_sertopic_builtintopic (DSBT_PARTICIPANT, "DCPSParticipant", "org::eclipse::cyclonedds::builtin::DCPSParticipant", &dom->gv); + dom->builtin_reader_topic = new_sertopic_builtintopic (DSBT_READER, "DCPSSubscription", "org::eclipse::cyclonedds::builtin::DCPSSubscription", &dom->gv); + dom->builtin_writer_topic = new_sertopic_builtintopic (DSBT_WRITER, "DCPSPublication", "org::eclipse::cyclonedds::builtin::DCPSPublication", &dom->gv); + + const struct ephash *gh = dom->gv.guid_hash; + dom->builtintopic_writer_participant = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER), dom->builtin_participant_topic, qos, builtintopic_whc_new (DSBT_PARTICIPANT, gh)); + dom->builtintopic_writer_publications = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER), dom->builtin_writer_topic, qos, builtintopic_whc_new (DSBT_WRITER, gh)); + dom->builtintopic_writer_subscriptions = new_local_orphan_writer (&dom->gv, to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER), dom->builtin_reader_topic, qos, builtintopic_whc_new (DSBT_READER, gh)); + + dds_delete_qos (qos); +} + +void dds__builtin_fini (struct dds_domain *dom) +{ + /* No more sources for builtin topic samples */ + thread_state_awake (lookup_thread_state (), &dom->gv); + delete_local_orphan_writer (dom->builtintopic_writer_participant); + delete_local_orphan_writer (dom->builtintopic_writer_publications); + delete_local_orphan_writer (dom->builtintopic_writer_subscriptions); + thread_state_asleep (lookup_thread_state ()); + + ddsi_sertopic_unref (dom->builtin_participant_topic); + ddsi_sertopic_unref (dom->builtin_reader_topic); + ddsi_sertopic_unref (dom->builtin_writer_topic); +} diff --git a/src/core/ddsc/src/dds_coherent.c b/src/core/ddsc/src/dds_coherent.c index 6123a47..68bf384 100644 --- a/src/core/ddsc/src/dds_coherent.c +++ b/src/core/ddsc/src/dds_coherent.c @@ -15,19 +15,14 @@ #include "dds__entity.h" #include "dds__subscriber.h" #include "dds__publisher.h" -#include "dds__err.h" -dds_return_t -dds_begin_coherent( - dds_entity_t entity) +dds_return_t dds_begin_coherent (dds_entity_t entity) { static const dds_entity_kind_t kinds[] = { DDS_KIND_READER, DDS_KIND_WRITER, DDS_KIND_PUBLISHER, DDS_KIND_SUBSCRIBER }; return dds_generic_unimplemented_operation_manykinds (entity, sizeof (kinds) / sizeof (kinds[0]), kinds); } -dds_return_t -dds_end_coherent( - dds_entity_t entity) +dds_return_t dds_end_coherent (dds_entity_t entity) { static const dds_entity_kind_t kinds[] = { DDS_KIND_READER, DDS_KIND_WRITER, DDS_KIND_PUBLISHER, DDS_KIND_SUBSCRIBER }; return dds_generic_unimplemented_operation_manykinds (entity, sizeof (kinds) / sizeof (kinds[0]), kinds); diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c index b8c12d8..3fe6786 100644 --- a/src/core/ddsc/src/dds_domain.c +++ b/src/core/ddsc/src/dds_domain.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,51 +9,317 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include "dds__domain.h" -#include "dds/ddsi/ddsi_tkmap.h" +#include -static int dds_domain_compare (const int32_t * a, const int32_t * b) +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/heap.h" +#include "dds__init.h" +#include "dds__rhc.h" +#include "dds__domain.h" +#include "dds__builtin.h" +#include "dds__whc_builtintopic.h" +#include "dds/ddsi/ddsi_iid.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_threadmon.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_gc.h" +#include "dds/ddsi/q_globals.h" +#include "dds/version.h" + +static int dds_domain_compare (const void *va, const void *vb) { + const dds_domainid_t *a = va; + const dds_domainid_t *b = vb; return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; } -const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER -( - offsetof (dds_domain, m_node), - offsetof (dds_domain, m_id), - (int (*) (const void *, const void *)) dds_domain_compare, - 0 -); +static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER ( + offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0); -dds_domain * dds_domain_find_locked (dds_domainid_t id) +static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id) +{ + dds_return_t ret = DDS_RETCODE_OK; + char * uri = NULL; + uint32_t len; + + domain->gv.tstart = now (); + domain->m_refc = 1; + ddsrt_avl_init (&dds_topictree_def, &domain->m_topics); + + /* | domain_id | domain id in config | result + +-----------+---------------------+---------- + | DEFAULT | any (or absent) | 0 + | DEFAULT | n | n + | n | any (or absent) | n + | n | m = n | n + | n | m /= n | n, entire config ignored + + Config models: + 1: + ... + + + where ... is all that can today be set in children of CycloneDDS + with the exception of the id + 2: + X + ... + + legacy form, domain id must be the first element in the file with + a value (if nothing has been set previously, it a warning is good + enough) */ + + (void) ddsrt_getenv ("CYCLONEDDS_URI", &uri); + domain->cfgst = config_init (uri, &domain->gv.config, domain_id); + if (domain->cfgst == NULL) + { + DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri); + ret = DDS_RETCODE_ERROR; + goto fail_config; + } + + assert (domain_id == DDS_DOMAIN_DEFAULT || domain_id == domain->gv.config.domainId); + domain->m_id = domain->gv.config.domainId; + + if (rtps_config_prep (&domain->gv, domain->cfgst) != 0) + { + DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to configure RTPS\n"); + ret = DDS_RETCODE_ERROR; + goto fail_rtps_config; + } + + if (rtps_init (&domain->gv) < 0) + { + DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to initialize RTPS\n"); + ret = DDS_RETCODE_ERROR; + goto fail_rtps_init; + } + + /* Start monitoring the liveliness of threads if this is the first + domain to configured to do so. */ + if (domain->gv.config.liveliness_monitoring) + { + if (dds_global.threadmon_count++ == 0) + { + /* FIXME: configure settings */ + dds_global.threadmon = ddsi_threadmon_new (DDS_MSECS (333), true); + if (dds_global.threadmon == NULL) + { + DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to create a thread liveliness monitor\n"); + ret = DDS_RETCODE_OUT_OF_RESOURCES; + goto fail_threadmon_new; + } + /* FIXME: thread properties */ + if (ddsi_threadmon_start (dds_global.threadmon, "threadmon") < 0) + { + DDS_ILOG (DDS_LC_ERROR, domain->m_id, "Failed to start the thread liveliness monitor\n"); + ret = DDS_RETCODE_ERROR; + goto fail_threadmon_start; + } + } + } + + dds__builtin_init (domain); + + /* Set additional default participant properties */ + + char progname[50] = "UNKNOWN"; /* FIXME: once retrieving process names is back in */ + char hostname[64]; + domain->gv.default_local_plist_pp.process_id = (unsigned) ddsrt_getpid(); + domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_PROCESS_ID; + domain->gv.default_local_plist_pp.exec_name = dds_string_alloc(32); + (void) snprintf (domain->gv.default_local_plist_pp.exec_name, 32, "CycloneDDS: %u", domain->gv.default_local_plist_pp.process_id); + len = (uint32_t) (13 + strlen (domain->gv.default_local_plist_pp.exec_name)); + domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_EXEC_NAME; + if (ddsrt_gethostname (hostname, sizeof (hostname)) == DDS_RETCODE_OK) + { + domain->gv.default_local_plist_pp.node_name = dds_string_dup (hostname); + domain->gv.default_local_plist_pp.present |= PP_PRISMTECH_NODE_NAME; + } + domain->gv.default_local_plist_pp.entity_name = dds_alloc (len); + (void) snprintf (domain->gv.default_local_plist_pp.entity_name, len, "%s<%u>", progname, domain->gv.default_local_plist_pp.process_id); + domain->gv.default_local_plist_pp.present |= PP_ENTITY_NAME; + + if (rtps_start (&domain->gv) < 0) + { + DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to start RTPS\n"); + ret = DDS_RETCODE_ERROR; + goto fail_rtps_start; + } + + if (domain->gv.config.liveliness_monitoring) + ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv); + return DDS_RETCODE_OK; + + rtps_stop (&domain->gv); +fail_rtps_start: + if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1) + ddsi_threadmon_stop (dds_global.threadmon); +fail_threadmon_start: + if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0) + { + ddsi_threadmon_free (dds_global.threadmon); + dds_global.threadmon = NULL; + } +fail_threadmon_new: + rtps_fini (&domain->gv); +fail_rtps_init: +fail_rtps_config: + config_fini (domain->cfgst); +fail_config: + return ret; +} + +static void dds_domain_fini (struct dds_domain *domain) +{ + rtps_stop (&domain->gv); + dds__builtin_fini (domain); + + if (domain->gv.config.liveliness_monitoring) + ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv); + + rtps_fini (&domain->gv); + + ddsrt_mutex_lock (&dds_global.m_mutex); + if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0) + { + ddsi_threadmon_stop (dds_global.threadmon); + ddsi_threadmon_free (dds_global.threadmon); + } + ddsrt_mutex_unlock (&dds_global.m_mutex); + + config_fini (domain->cfgst); +} + +dds_domain *dds_domain_find_locked (dds_domainid_t id) { return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id); } -dds_domain * dds_domain_create (dds_domainid_t id) +dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id) { - dds_domain * domain; + struct dds_domain *dom = NULL; + dds_return_t ret; + ddsrt_mutex_lock (&dds_global.m_mutex); - domain = dds_domain_find_locked (id); - if (domain == NULL) + + /* FIXME: hack around default domain ids, not yet being able to handle multiple domains simultaneously */ + if (id != DDS_DOMAIN_DEFAULT) { - domain = dds_alloc (sizeof (*domain)); - domain->m_id = id; - ddsrt_avl_init (&dds_topictree_def, &domain->m_topics); - ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, domain); + if ((dom = dds_domain_find_locked (id)) == NULL) + ret = DDS_RETCODE_NOT_FOUND; + else + ret = DDS_RETCODE_OK; + } + else + { + if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL) + ret = DDS_RETCODE_OK; + else + ret = DDS_RETCODE_NOT_FOUND; + } + + switch (ret) + { + case DDS_RETCODE_OK: + dom->m_refc++; + *domain_out = dom; + break; + case DDS_RETCODE_NOT_FOUND: + dom = dds_alloc (sizeof (*dom)); + if ((ret = dds_domain_init (dom, id)) < 0) + dds_free (dom); + else + { + ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom); + *domain_out = dom; + } + break; + case DDS_RETCODE_PRECONDITION_NOT_MET: + DDS_ILOG (DDS_LC_ERROR, id, "Inconsistent domain configuration detected: domain on configuration: %"PRIu32", domain %"PRIu32"\n", dom->m_id, id); + break; } - domain->m_refc++; ddsrt_mutex_unlock (&dds_global.m_mutex); - return domain; + return ret; } -void dds_domain_free (dds_domain * domain) +void dds_domain_free (dds_domain *domain) { ddsrt_mutex_lock (&dds_global.m_mutex); - if (--domain->m_refc == 0) + if (--domain->m_refc != 0) + { + ddsrt_mutex_unlock (&dds_global.m_mutex); + } + else { ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain); + ddsrt_mutex_unlock (&dds_global.m_mutex); + dds_domain_fini (domain); dds_free (domain); } - ddsrt_mutex_unlock (&dds_global.m_mutex); +} + +#include "dds__entity.h" +static void pushdown_set_batch (struct dds_entity *e, bool enable) +{ + /* e is pinned, no locks held */ + dds_instance_handle_t last_iid = 0; + struct dds_entity *c; + ddsrt_mutex_lock (&e->m_mutex); + while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL) + { + struct dds_entity *x; + last_iid = c->m_iid; + if (dds_entity_pin (c->m_hdllink.hdl, &x) < 0) + continue; + assert (x == c); + ddsrt_mutex_unlock (&e->m_mutex); + if (c->m_kind == DDS_KIND_PARTICIPANT) + pushdown_set_batch (c, enable); + else if (c->m_kind == DDS_KIND_WRITER) + { + struct dds_writer *w = (struct dds_writer *) c; + w->whc_batch = enable; + } + ddsrt_mutex_lock (&e->m_mutex); + dds_entity_unpin (c); + } + ddsrt_mutex_unlock (&e->m_mutex); +} + +void dds_write_set_batch (bool enable) +{ + /* FIXME: get channels + latency budget working and get rid of this; in the mean time, any ugly hack will do. */ + struct dds_domain *dom; + dds_domainid_t next_id = 0; + dds_init (); + ddsrt_mutex_lock (&dds_global.m_mutex); + while ((dom = ddsrt_avl_lookup_succ_eq (&dds_domaintree_def, &dds_global.m_domains, &next_id)) != NULL) + { + /* Must be sure that the compiler doesn't reload curr_id from dom->m_id */ + dds_domainid_t curr_id = *((volatile dds_domainid_t *) &dom->m_id); + next_id = curr_id + 1; + dom->gv.config.whc_batch = enable; + + dds_instance_handle_t last_iid = 0; + struct dds_entity *e; + while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_ppants, &last_iid)) != NULL) + { + struct dds_entity *x; + last_iid = e->m_iid; + if (dds_entity_pin (e->m_hdllink.hdl, &x) < 0) + continue; + assert (x == e); + ddsrt_mutex_unlock (&dds_global.m_mutex); + pushdown_set_batch (e, enable); + ddsrt_mutex_lock (&dds_global.m_mutex); + dds_entity_unpin (e); + dom = ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &curr_id); + } + } + ddsrt_mutex_unlock (&dds_global.m_mutex); + dds_fini (); } diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c index 7d62349..aa2a72a 100644 --- a/src/core/ddsc/src/dds_entity.c +++ b/src/core/ddsc/src/dds_entity.c @@ -19,28 +19,65 @@ #include "dds__writer.h" #include "dds__reader.h" #include "dds__listener.h" -#include "dds__err.h" +#include "dds__qos.h" +#include "dds__topic.h" #include "dds/version.h" +#include "dds/ddsi/q_xqos.h" extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink); extern inline bool dds_entity_is_enabled (const dds_entity *e); -extern inline void dds_entity_status_reset (dds_entity *e, uint32_t t); -extern inline bool dds_entity_status_match (const dds_entity *e, uint32_t t); +extern inline void dds_entity_status_reset (dds_entity *e, status_mask_t t); extern inline dds_entity_kind_t dds_entity_kind (const dds_entity *e); -static void dds_entity_observers_signal (dds_entity *observed, uint32_t status); -static void dds_entity_observers_delete (dds_entity *observed); +const struct dds_entity_deriver *dds_entity_deriver_table[] = { + [DDS_KIND_TOPIC] = &dds_entity_deriver_topic, + [DDS_KIND_PARTICIPANT] = &dds_entity_deriver_participant, + [DDS_KIND_READER] = &dds_entity_deriver_reader, + [DDS_KIND_WRITER] = &dds_entity_deriver_writer, + [DDS_KIND_SUBSCRIBER] = &dds_entity_deriver_subscriber, + [DDS_KIND_PUBLISHER] = &dds_entity_deriver_publisher, + [DDS_KIND_COND_READ] = &dds_entity_deriver_readcondition, + [DDS_KIND_COND_QUERY] = &dds_entity_deriver_readcondition, + [DDS_KIND_COND_GUARD] = &dds_entity_deriver_guardcondition, + [DDS_KIND_WAITSET] = &dds_entity_deriver_waitset, +}; -void dds_entity_add_ref_nolock (dds_entity *e) -{ - e->m_refc++; +dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e) { + (void) e; return DDS_RETCODE_OK; +} +dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e) { + (void) e; return DDS_RETCODE_OK; +} +dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled) { + (void) e; (void) qos; (void) enabled; return DDS_RETCODE_ILLEGAL_OPERATION; +} +dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask) { + (void) mask; return DDS_RETCODE_ILLEGAL_OPERATION; } -void dds_entity_add_ref (dds_entity *e) +extern inline dds_return_t dds_entity_deriver_close (struct dds_entity *e); +extern inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e); +extern inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled); +extern inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask); +extern inline bool dds_entity_supports_set_qos (struct dds_entity *e); +extern inline bool dds_entity_supports_validate_status (struct dds_entity *e); + +static int compare_instance_handle (const void *va, const void *vb) { - ddsrt_mutex_lock (&e->m_mutex); - dds_entity_add_ref_nolock (e); - ddsrt_mutex_unlock (&e->m_mutex); + const dds_instance_handle_t *a = va; + const dds_instance_handle_t *b = vb; + return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; +} + +const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct dds_entity, m_avlnode_child), offsetof (struct dds_entity, m_iid), compare_instance_handle, 0); + +static void dds_entity_observers_signal (dds_entity *observed, uint32_t status); +static void dds_entity_observers_signal_delete (dds_entity *observed); +static void dds_entity_observers_delete (dds_entity *observed); + +void dds_entity_add_ref_locked (dds_entity *e) +{ + dds_handle_add_ref (&e->m_hdllink); } dds_domain *dds__entity_domain (dds_entity *e) @@ -48,41 +85,54 @@ dds_domain *dds__entity_domain (dds_entity *e) return e->m_domain; } -static void dds_set_explicit (dds_entity_t entity) -{ - dds_entity *e; - dds_retcode_t rc; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) == DDS_RETCODE_OK) - { - e->m_flags &= ~DDS_ENTITY_IMPLICIT; - dds_entity_unlock (e); - } -} - static dds_entity *dds__nonself_parent (dds_entity *e) { return e->m_parent == e ? NULL : e->m_parent; } -dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, dds_qos_t *qos, const dds_listener_t *listener, uint32_t mask) +static bool entity_has_status (const dds_entity *e) +{ + switch (e->m_kind) + { + case DDS_KIND_TOPIC: + case DDS_KIND_READER: + case DDS_KIND_WRITER: + case DDS_KIND_PUBLISHER: + case DDS_KIND_SUBSCRIBER: + case DDS_KIND_PARTICIPANT: + return true; + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + case DDS_KIND_COND_GUARD: + case DDS_KIND_WAITSET: + break; + case DDS_KIND_DONTCARE: + abort (); + break; + } + return false; +} + +dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask) { dds_handle_t handle; assert ((kind == DDS_KIND_PARTICIPANT) == (parent == NULL)); assert (e); - e->m_refc = 1; e->m_kind = kind; e->m_qos = qos; e->m_cb_count = 0; e->m_observers = NULL; - e->m_trigger = 0; /* TODO: CHAM-96: Implement dynamic enabling of entity. */ e->m_flags |= DDS_ENTITY_ENABLED; /* set the status enable based on kind */ - e->m_status_enable = mask | DDS_INTERNAL_STATUS_MASK; + if (entity_has_status (e)) + ddsrt_atomic_st32 (&e->m_status.m_status_and_mask, (uint32_t) mask << SAM_ENABLED_SHIFT); + else + ddsrt_atomic_st32 (&e->m_status.m_trigger, 0); ddsrt_mutex_init (&e->m_mutex); ddsrt_mutex_init (&e->m_observers_lock); @@ -93,10 +143,8 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind { e->m_parent = parent; e->m_domain = parent->m_domain; - e->m_domainid = parent->m_domainid; e->m_participant = parent->m_participant; - e->m_next = parent->m_children; - parent->m_children = e; + ddsrt_avl_init (&dds_entity_children_td, &e->m_children); } else { @@ -109,9 +157,9 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind dds_merge_listener (&e->m_listener, listener); if (parent) { - ddsrt_mutex_lock (&e->m_observers_lock); + ddsrt_mutex_lock (&parent->m_observers_lock); dds_inherit_listener (&e->m_listener, &parent->m_listener); - ddsrt_mutex_unlock (&e->m_observers_lock); + ddsrt_mutex_unlock (&parent->m_observers_lock); } if ((handle = dds_handle_create (&e->m_hdllink)) <= 0) @@ -121,16 +169,27 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind return (dds_entity_t) handle; } +void dds_entity_register_child (dds_entity *parent, dds_entity *child) +{ + assert (child->m_iid != 0); + assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &child->m_iid) == NULL); + ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child); +} + dds_return_t dds_delete (dds_entity_t entity) { return dds_delete_impl (entity, false); } -static dds_entity *next_non_topic_child (dds_entity *remaining_children) +static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children) { - while (remaining_children != NULL && dds_entity_kind (remaining_children) == DDS_KIND_TOPIC) - remaining_children = remaining_children->m_next; - return remaining_children; + ddsrt_avl_iter_t it; + for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, remaining_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it)) + { + if (dds_entity_kind (e) != DDS_KIND_TOPIC) + return e; + } + return NULL; } dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit) @@ -138,45 +197,36 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit) dds_time_t timeout = DDS_SECS(10); dds_entity *e; dds_entity *child; - dds_entity *parent; - dds_entity *prev = NULL; - dds_entity *next = NULL; dds_return_t ret; - dds_retcode_t rc; + dds_return_t rc; - rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e); - if (rc != DDS_RETCODE_OK) - { - DDS_TRACE ("dds_delete_impl: error on locking entity %"PRIu32" keep_if_explicit %d\n", entity, (int) keep_if_explicit); - return DDS_ERRNO (rc); - } + if ((rc = dds_entity_pin (entity, &e)) < 0) + return rc; + ddsrt_mutex_lock (&e->m_mutex); if (keep_if_explicit == true && (e->m_flags & DDS_ENTITY_IMPLICIT) == 0) { - dds_entity_unlock(e); + ddsrt_mutex_unlock (&e->m_mutex); + dds_entity_unpin (e); return DDS_RETCODE_OK; } - if (--e->m_refc != 0) + if (! dds_handle_drop_ref (&e->m_hdllink)) { - dds_entity_unlock (e); + ddsrt_mutex_unlock (&e->m_mutex); + dds_entity_unpin (e); return DDS_RETCODE_OK; } - /* FIXME: "closing" the handle here means a listener invoked on X - can still discover that X has become inaccessible */ - /* FIXME: RHC reads m_status_enable outside lock and might still - just invoke the listener */ - dds_handle_close (&e->m_hdllink); - e->m_status_enable = 0; + ddsrt_mutex_lock (&e->m_observers_lock); + if (entity_has_status (e)) + ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, SAM_STATUS_MASK); dds_reset_listener (&e->m_listener); - e->m_trigger |= DDS_DELETING_STATUS; - dds_entity_unlock(e); /* Signal observers that this entity will be deleted and wait for all listeners to complete. */ - ddsrt_mutex_lock (&e->m_observers_lock); - dds_entity_observers_signal (e, e->m_trigger); + ddsrt_mutex_unlock (&e->m_mutex); + dds_entity_observers_signal_delete (e); while (e->m_cb_count > 0) ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock); ddsrt_mutex_unlock (&e->m_observers_lock); @@ -199,29 +249,27 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit) * To circumvent the problem. We ignore topics in the first loop. */ ret = DDS_RETCODE_OK; - child = next_non_topic_child (e->m_children); - while (child != NULL && ret == DDS_RETCODE_OK) + ddsrt_mutex_lock (&e->m_mutex); + while ((child = next_non_topic_child (&e->m_children)) && ret == DDS_RETCODE_OK) { - next = next_non_topic_child (child->m_next); - /* This will probably delete the child entry from the current children's list */ - ret = dds_delete (child->m_hdllink.hdl); - child = next; + dds_entity_t child_handle = child->m_hdllink.hdl; + ddsrt_mutex_unlock (&e->m_mutex); + ret = dds_delete (child_handle); + ddsrt_mutex_lock (&e->m_mutex); } - child = e->m_children; - while (child != NULL && ret == DDS_RETCODE_OK) + while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL && ret == DDS_RETCODE_OK) { - next = child->m_next; assert (dds_entity_kind (child) == DDS_KIND_TOPIC); - ret = dds_delete (child->m_hdllink.hdl); - child = next; - } - if (ret == DDS_RETCODE_OK && e->m_deriver.close) - { - /* Close the entity. This can terminate threads or kick of - * other destroy stuff that takes a while. */ - ret = e->m_deriver.close (e); + dds_entity_t child_handle = child->m_hdllink.hdl; + ddsrt_mutex_unlock (&e->m_mutex); + ret = dds_delete (child_handle); + ddsrt_mutex_lock (&e->m_mutex); } + ddsrt_mutex_unlock (&e->m_mutex); + if (ret == DDS_RETCODE_OK) + ret = dds_entity_deriver_close (e); + dds_entity_unpin (e); if (ret == DDS_RETCODE_OK) { /* The dds_handle_delete will wait until the last active claim on that handle @@ -237,26 +285,17 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit) dds_entity_observers_delete (e); /* Remove from parent */ + dds_entity *parent; if ((parent = dds__nonself_parent(e)) != NULL) { ddsrt_mutex_lock (&parent->m_mutex); - child = parent->m_children; - while (child && child != e) - { - prev = child; - child = child->m_next; - } - assert (child != NULL); - if (prev) - prev->m_next = e->m_next; - else - parent->m_children = e->m_next; + assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &e->m_iid) != NULL); + ddsrt_avl_delete (&dds_entity_children_td, &parent->m_children, e); ddsrt_mutex_unlock (&parent->m_mutex); } /* Do some specific deletion when needed. */ - if (e->m_deriver.delete) - ret = e->m_deriver.delete(e); + ret = dds_entity_deriver_delete (e); } if (ret == DDS_RETCODE_OK) @@ -275,9 +314,9 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit) dds_entity_t dds_get_parent (dds_entity_t entity) { dds_entity *e; - dds_retcode_t rc; + dds_return_t rc; if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; else { dds_entity *parent; @@ -286,8 +325,13 @@ dds_entity_t dds_get_parent (dds_entity_t entity) hdl = DDS_ENTITY_NIL; else { + dds_entity *x; hdl = parent->m_hdllink.hdl; - dds_set_explicit (hdl); + if (dds_entity_lock (hdl, DDS_KIND_DONTCARE, &x) == DDS_RETCODE_OK) + { + parent->m_flags &= ~DDS_ENTITY_IMPLICIT; + dds_entity_unlock (parent); + } } dds_entity_unlock (e); return hdl; @@ -297,9 +341,9 @@ dds_entity_t dds_get_parent (dds_entity_t entity) dds_entity_t dds_get_participant (dds_entity_t entity) { dds_entity *e; - dds_retcode_t rc; + dds_return_t rc; if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; else { dds_entity_t hdl = e->m_participant->m_hdllink.hdl; @@ -311,106 +355,291 @@ dds_entity_t dds_get_participant (dds_entity_t entity) dds_return_t dds_get_children (dds_entity_t entity, dds_entity_t *children, size_t size) { dds_entity *e; - dds_retcode_t rc; + dds_return_t rc; if (children != NULL && (size <= 0 || size >= INT32_MAX)) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; if (children == NULL && size != 0) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return rc; else { - dds_return_t n = 0; - dds_entity *iter = e->m_children; - while (iter) + /* FIXME: fix the implicit/explicit stuff so the set_explicit isn't needed; and then this can also be done with a regular iterator & without unlocking */ + size_t n = 0; + dds_instance_handle_t last_iid = 0; + struct dds_entity *c; + ddsrt_mutex_lock (&e->m_mutex); + while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL) { - if ((size_t) n < size) + last_iid = c->m_iid; + if (n < size) { - children[n] = iter->m_hdllink.hdl; - dds_set_explicit (iter->m_hdllink.hdl); + dds_entity *x; + /* Claim child handle to guarantee the child entity remains valid; as we unlock "e" only when we manage to claim the child, and the child has to remain in existence until we release it, "c" remains a valid pointer despite the unlocking. */ + if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK) + { + assert (x == c); + children[n] = c->m_hdllink.hdl; + ddsrt_mutex_unlock (&e->m_mutex); + + ddsrt_mutex_lock (&c->m_mutex); + c->m_flags &= ~DDS_ENTITY_IMPLICIT; + ddsrt_mutex_unlock (&c->m_mutex); + + ddsrt_mutex_lock (&e->m_mutex); + dds_entity_unpin (c); + } } n++; - iter = iter->m_next; } - dds_entity_unlock(e); - return n; + ddsrt_mutex_unlock (&e->m_mutex); + dds_entity_unpin (e); + /* there are fewer than INT32_MAX handles, so there can never be more entities */ + assert (n <= INT32_MAX); + return (dds_return_t) n; } } +static uint64_t entity_kind_qos_mask (dds_entity_kind_t kind) +{ + switch (kind) + { + case DDS_KIND_TOPIC: + return DDS_TOPIC_QOS_MASK; + case DDS_KIND_PARTICIPANT: + return DDS_PARTICIPANT_QOS_MASK; + case DDS_KIND_READER: + return DDS_READER_QOS_MASK; + case DDS_KIND_WRITER: + return DDS_WRITER_QOS_MASK; + case DDS_KIND_SUBSCRIBER: + return DDS_SUBSCRIBER_QOS_MASK; + case DDS_KIND_PUBLISHER: + return DDS_PUBLISHER_QOS_MASK; + case DDS_KIND_DONTCARE: + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + case DDS_KIND_COND_GUARD: + case DDS_KIND_WAITSET: + break; + } + return 0; +} + dds_return_t dds_get_qos (dds_entity_t entity, dds_qos_t *qos) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; if (qos == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) + return ret; - if (e->m_deriver.set_qos == 0) - ret = DDS_ERRNO(DDS_RETCODE_ILLEGAL_OPERATION); + if (!dds_entity_supports_set_qos (e)) + ret = DDS_RETCODE_ILLEGAL_OPERATION; else { dds_reset_qos (qos); - ret = dds_copy_qos (qos, e->m_qos); + nn_xqos_mergein_missing (qos, e->m_qos, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); + ret = DDS_RETCODE_OK; } dds_entity_unlock(e); return ret; } +static dds_return_t dds_set_qos_locked_impl (dds_entity *e, const dds_qos_t *qos, uint64_t mask) +{ + dds_return_t ret; + dds_qos_t *newqos = dds_create_qos (); + nn_xqos_mergein_missing (newqos, qos, mask); + nn_xqos_mergein_missing (newqos, e->m_qos, ~(uint64_t)0); + if ((ret = nn_xqos_valid (&e->m_domain->gv.logconfig, newqos)) != DDS_RETCODE_OK) + ; /* oops ... invalid or inconsistent */ + else if (!(e->m_flags & DDS_ENTITY_ENABLED)) + ; /* do as you please while the entity is not enabled (perhaps we should even allow invalid ones?) */ + else + { + const uint64_t delta = nn_xqos_delta (e->m_qos, newqos, ~(uint64_t)0); + if (delta == 0) /* no change */ + ret = DDS_RETCODE_OK; + else if (delta & ~QP_CHANGEABLE_MASK) + ret = DDS_RETCODE_IMMUTABLE_POLICY; + else if (delta & (QP_RXO_MASK | QP_PARTITION)) + ret = DDS_RETCODE_UNSUPPORTED; /* not yet supporting things that affect matching */ + else + { + /* yay! */ + } + } + + if (ret != DDS_RETCODE_OK) + dds_delete_qos (newqos); + else if ((ret = dds_entity_deriver_set_qos (e, newqos, e->m_flags & DDS_ENTITY_ENABLED)) != DDS_RETCODE_OK) + dds_delete_qos (newqos); + else + { + dds_delete_qos (e->m_qos); + e->m_qos = newqos; + } + return ret; +} + +static void pushdown_pubsub_qos (dds_entity *e) +{ + /* e claimed but no mutex held */ + struct dds_entity *c; + dds_instance_handle_t last_iid = 0; + ddsrt_mutex_lock (&e->m_mutex); + while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL) + { + struct dds_entity *x; + last_iid = c->m_iid; + if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK) + { + assert (x == c); + assert (dds_entity_kind (c) == DDS_KIND_READER || dds_entity_kind (c) == DDS_KIND_WRITER); + /* see dds_get_children for why "c" remains valid despite unlocking m_mutex; + unlock e, lock c, relock e sequence is to avoid locking a child while holding the parent */ + ddsrt_mutex_unlock (&e->m_mutex); + + ddsrt_mutex_lock (&c->m_mutex); + ddsrt_mutex_lock (&e->m_mutex); + dds_set_qos_locked_impl (c, e->m_qos, QP_GROUP_DATA | QP_PARTITION); + ddsrt_mutex_unlock (&c->m_mutex); + dds_entity_unpin (c); + } + } + ddsrt_mutex_unlock (&e->m_mutex); +} + +static void pushdown_topic_qos (dds_entity *e, struct dds_entity *tp) +{ + /* on input: both entities claimed but no mutexes held */ + enum { NOP, PROP, CHANGE } todo; + switch (dds_entity_kind (e)) + { + case DDS_KIND_READER: { + dds_reader *rd = (dds_reader *) e; + todo = (&rd->m_topic->m_entity == tp) ? CHANGE : NOP; + break; + } + case DDS_KIND_WRITER: { + dds_writer *wr = (dds_writer *) e; + todo = (&wr->m_topic->m_entity == tp) ? CHANGE : NOP; + break; + } + default: { + todo = PROP; + break; + } + } + switch (todo) + { + case NOP: + break; + case CHANGE: { + /* may lock topic while holding reader/writer lock */ + ddsrt_mutex_lock (&e->m_mutex); + ddsrt_mutex_lock (&tp->m_mutex); + dds_set_qos_locked_impl (e, tp->m_qos, QP_TOPIC_DATA); + ddsrt_mutex_unlock (&tp->m_mutex); + ddsrt_mutex_unlock (&e->m_mutex); + break; + } + case PROP: { + struct dds_entity *c; + dds_instance_handle_t last_iid = 0; + ddsrt_mutex_lock (&e->m_mutex); + while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL) + { + struct dds_entity *x; + last_iid = c->m_iid; + if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK) + { + assert (x == c); + /* see dds_get_children for why "c" remains valid despite unlocking m_mutex */ + ddsrt_mutex_unlock (&e->m_mutex); + pushdown_topic_qos (c, tp); + ddsrt_mutex_lock (&e->m_mutex); + dds_entity_unpin (c); + } + } + ddsrt_mutex_unlock (&e->m_mutex); + break; + } + } +} + dds_return_t dds_set_qos (dds_entity_t entity, const dds_qos_t *qos) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; - if (qos == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; + if ((ret = dds_entity_pin (entity, &e)) < 0) + return ret; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); - - if (e->m_deriver.set_qos == 0) - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); - else + const dds_entity_kind_t kind = dds_entity_kind (e); + if (!dds_entity_supports_set_qos (e)) { - if ((ret = e->m_deriver.set_qos (e, qos, e->m_flags & DDS_ENTITY_ENABLED)) == DDS_RETCODE_OK) - { - if (e->m_qos == NULL) - e->m_qos = dds_create_qos (); - rc = dds_copy_qos (e->m_qos, qos); - ret = DDS_ERRNO (rc); + dds_entity_unpin (e); + return DDS_RETCODE_ILLEGAL_OPERATION; + } + + ddsrt_mutex_lock (&e->m_mutex); + ret = dds_set_qos_locked_impl (e, qos, entity_kind_qos_mask (kind)); + ddsrt_mutex_unlock (&e->m_mutex); + if (ret < 0) + { + dds_entity_unpin (e); + return ret; + } + + switch (dds_entity_kind (e)) + { + case DDS_KIND_TOPIC: { + dds_entity *pp; + if (dds_entity_pin (e->m_participant->m_hdllink.hdl, &pp) == DDS_RETCODE_OK) + { + pushdown_topic_qos (pp, e); + dds_entity_unpin (pp); + } + break; + } + case DDS_KIND_PUBLISHER: + case DDS_KIND_SUBSCRIBER: { + pushdown_pubsub_qos (e); + break; + } + default: { + break; } } - dds_entity_unlock (e); - return ret; + + dds_entity_unpin (e); + return 0; } dds_return_t dds_get_listener (dds_entity_t entity, dds_listener_t *listener) { dds_entity *e; - dds_return_t ret = DDS_RETCODE_OK; - dds_retcode_t rc; - - if (listener != NULL) { - rc = dds_entity_lock(entity, DDS_KIND_DONTCARE, &e); - if (rc == DDS_RETCODE_OK) { - ddsrt_mutex_lock (&e->m_observers_lock); - dds_copy_listener (listener, &e->m_listener); - ddsrt_mutex_unlock (&e->m_observers_lock); - dds_entity_unlock(e); - } else { - ret = DDS_ERRNO(rc); - } - } else { - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); + dds_return_t ret; + if (listener == NULL) + return DDS_RETCODE_BAD_PARAMETER; + else if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return ret; + else + { + ddsrt_mutex_lock (&e->m_observers_lock); + dds_copy_listener (listener, &e->m_listener); + ddsrt_mutex_unlock (&e->m_observers_lock); + dds_entity_unpin (e); + return DDS_RETCODE_OK; } - - return ret; } void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id which, const void *vst) @@ -487,71 +716,79 @@ void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id wh static void clear_status_with_listener (struct dds_entity *e) { const struct dds_listener *lst = &e->m_listener; + status_mask_t mask = 0; if (lst->on_inconsistent_topic) - e->m_trigger &= ~DDS_INCONSISTENT_TOPIC_STATUS; + mask |= DDS_INCONSISTENT_TOPIC_STATUS; if (lst->on_liveliness_lost) - e->m_trigger &= ~DDS_LIVELINESS_LOST_STATUS; + mask |= DDS_LIVELINESS_LOST_STATUS; if (lst->on_offered_deadline_missed) - e->m_trigger &= ~DDS_OFFERED_DEADLINE_MISSED_STATUS; + mask |= DDS_OFFERED_DEADLINE_MISSED_STATUS; if (lst->on_offered_deadline_missed_arg) - e->m_trigger &= ~DDS_OFFERED_DEADLINE_MISSED_STATUS; + mask |= DDS_OFFERED_DEADLINE_MISSED_STATUS; if (lst->on_offered_incompatible_qos) - e->m_trigger &= ~DDS_OFFERED_INCOMPATIBLE_QOS_STATUS; + mask |= DDS_OFFERED_INCOMPATIBLE_QOS_STATUS; if (lst->on_data_on_readers) - e->m_trigger &= ~DDS_DATA_ON_READERS_STATUS; + mask |= DDS_DATA_ON_READERS_STATUS; if (lst->on_sample_lost) - e->m_trigger &= ~DDS_SAMPLE_LOST_STATUS; + mask |= DDS_SAMPLE_LOST_STATUS; if (lst->on_data_available) - e->m_trigger &= ~DDS_DATA_AVAILABLE_STATUS; + mask |= DDS_DATA_AVAILABLE_STATUS; if (lst->on_sample_rejected) - e->m_trigger &= ~DDS_SAMPLE_REJECTED_STATUS; + mask |= DDS_SAMPLE_REJECTED_STATUS; if (lst->on_liveliness_changed) - e->m_trigger &= ~DDS_LIVELINESS_CHANGED_STATUS; + mask |= DDS_LIVELINESS_CHANGED_STATUS; if (lst->on_requested_deadline_missed) - e->m_trigger &= ~DDS_REQUESTED_DEADLINE_MISSED_STATUS; + mask |= DDS_REQUESTED_DEADLINE_MISSED_STATUS; if (lst->on_requested_incompatible_qos) - e->m_trigger &= ~DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS; + mask |= DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS; if (lst->on_publication_matched) - e->m_trigger &= ~DDS_PUBLICATION_MATCHED_STATUS; + mask |= DDS_PUBLICATION_MATCHED_STATUS; if (lst->on_subscription_matched) - e->m_trigger &= ~DDS_SUBSCRIPTION_MATCHED_STATUS; + mask |= DDS_SUBSCRIPTION_MATCHED_STATUS; + ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, ~(uint32_t)mask); } -static void pushdown_listener (dds_entity_t entity) +static void pushdown_listener (dds_entity *e) { - dds_entity_t *cs = NULL; - int ncs, size = 0; - while ((ncs = dds_get_children (entity, cs, (size_t) size)) > size) + /* Note: e is claimed, no mutexes held */ + struct dds_entity *c; + dds_instance_handle_t last_iid = 0; + ddsrt_mutex_lock (&e->m_mutex); + while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL) { - size = ncs; - cs = ddsrt_realloc (cs, (size_t) size * sizeof (*cs)); - } - for (int i = 0; i < ncs; i++) - { - dds_entity *e; - if (dds_entity_lock (cs[i], DDS_KIND_DONTCARE, &e) == DDS_RETCODE_OK) + struct dds_entity *x; + last_iid = c->m_iid; + if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK) { - dds_listener_t tmp; + ddsrt_mutex_unlock (&e->m_mutex); + + ddsrt_mutex_lock (&c->m_observers_lock); + while (c->m_cb_count > 0) + ddsrt_cond_wait (&c->m_observers_cond, &c->m_observers_lock); + ddsrt_mutex_lock (&e->m_observers_lock); - while (e->m_cb_count > 0) - ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock); - dds_get_listener (entity, &tmp); - dds_override_inherited_listener (&e->m_listener, &tmp); - clear_status_with_listener (e); + dds_override_inherited_listener (&c->m_listener, &e->m_listener); ddsrt_mutex_unlock (&e->m_observers_lock); - dds_entity_unlock (e); + + clear_status_with_listener (c); + ddsrt_mutex_unlock (&c->m_observers_lock); + + pushdown_listener (c); + + ddsrt_mutex_lock (&e->m_mutex); + dds_entity_unpin (c); } } - ddsrt_free (cs); + ddsrt_mutex_unlock (&e->m_mutex); } dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listener) { dds_entity *e, *x; - dds_retcode_t rc; + dds_return_t rc; - if ((rc = dds_entity_claim (entity, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return rc; ddsrt_mutex_lock (&e->m_observers_lock); while (e->m_cb_count > 0) @@ -567,52 +804,52 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen while (dds_entity_kind (x) != DDS_KIND_PARTICIPANT) { x = x->m_parent; + ddsrt_mutex_lock (&x->m_observers_lock); dds_inherit_listener (&e->m_listener, &x->m_listener); + ddsrt_mutex_unlock (&x->m_observers_lock); } clear_status_with_listener (e); ddsrt_mutex_unlock (&e->m_observers_lock); - dds_entity_release (e); - pushdown_listener (entity); + pushdown_listener (e); + dds_entity_unpin (e); return DDS_RETCODE_OK; } dds_return_t dds_enable (dds_entity_t entity) { dds_entity *e; - dds_retcode_t rc; + dds_return_t rc; - if ((rc = dds_entity_lock(entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) + return rc; if ((e->m_flags & DDS_ENTITY_ENABLED) == 0) { /* TODO: Really enable. */ e->m_flags |= DDS_ENTITY_ENABLED; - DDS_ERROR ("Delayed entity enabling is not supported\n"); + DDS_CERROR (&e->m_domain->gv.logconfig, "Delayed entity enabling is not supported\n"); } - dds_entity_unlock(e); + dds_entity_unlock (e); return DDS_RETCODE_OK; } dds_return_t dds_get_status_changes (dds_entity_t entity, uint32_t *status) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; if (status == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) + return ret; - if (e->m_deriver.validate_status == 0) - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + if (!dds_entity_supports_validate_status (e)) + ret = DDS_RETCODE_ILLEGAL_OPERATION; else { - ddsrt_mutex_lock (&e->m_observers_lock); - *status = e->m_trigger; - ddsrt_mutex_unlock (&e->m_observers_lock); + assert (entity_has_status (e)); + *status = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & SAM_STATUS_MASK; ret = DDS_RETCODE_OK; } dds_entity_unlock(e); @@ -622,25 +859,23 @@ dds_return_t dds_get_status_changes (dds_entity_t entity, uint32_t *status) dds_return_t dds_get_status_mask (dds_entity_t entity, uint32_t *mask) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; if (mask == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_claim (entity, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return ret; - if (e->m_deriver.validate_status == 0) - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + if (!dds_entity_supports_validate_status (e)) + ret = DDS_RETCODE_ILLEGAL_OPERATION; else { - ddsrt_mutex_lock (&e->m_observers_lock); - *mask = (e->m_status_enable & ~DDS_INTERNAL_STATUS_MASK); - ddsrt_mutex_unlock (&e->m_observers_lock); + assert (entity_has_status (e)); + *mask = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) >> SAM_ENABLED_SHIFT; ret = DDS_RETCODE_OK; } - dds_entity_release(e); + dds_entity_unpin(e); return ret; } @@ -652,56 +887,60 @@ dds_return_t dds_get_enabled_status (dds_entity_t entity, uint32_t *status) dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; - if ((rc = dds_entity_claim (entity, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((mask & ~SAM_STATUS_MASK) != 0) + return DDS_RETCODE_BAD_PARAMETER; - if (e->m_deriver.validate_status == 0) - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); - else if ((ret = e->m_deriver.validate_status (mask)) == DDS_RETCODE_OK) + if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return ret; + + if ((ret = dds_entity_deriver_validate_status (e, mask)) == DDS_RETCODE_OK) { + assert (entity_has_status (e)); ddsrt_mutex_lock (&e->m_observers_lock); while (e->m_cb_count > 0) ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock); /* Don't block internal status triggers. */ - mask |= DDS_INTERNAL_STATUS_MASK; - e->m_status_enable = mask; - e->m_trigger &= mask; + uint32_t old, new; + do { + old = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask); + new = (mask << SAM_ENABLED_SHIFT) | (old & mask); + } while (!ddsrt_atomic_cas32 (&e->m_status.m_status_and_mask, old, new)); ddsrt_mutex_unlock (&e->m_observers_lock); } - dds_entity_release (e); + dds_entity_unpin (e); return ret; } dds_return_t dds_set_enabled_status(dds_entity_t entity, uint32_t mask) { - return dds_set_status_mask( entity, mask); + return dds_set_status_mask (entity, mask); } static dds_return_t dds_readtake_status (dds_entity_t entity, uint32_t *status, uint32_t mask, bool reset) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; if (status == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; + if ((mask & ~SAM_STATUS_MASK) != 0) + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) + return ret; - if (e->m_deriver.validate_status == 0) - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); - else if ((ret = e->m_deriver.validate_status (mask)) == DDS_RETCODE_OK) + if ((ret = dds_entity_deriver_validate_status (e, mask)) == DDS_RETCODE_OK) { - ddsrt_mutex_lock (&e->m_observers_lock); - *status = e->m_trigger & mask; + uint32_t s; + assert (entity_has_status (e)); if (reset) - e->m_trigger &= ~mask; - ddsrt_mutex_unlock (&e->m_observers_lock); + s = ddsrt_atomic_and32_ov (&e->m_status.m_status_and_mask, ~mask) & mask; + else + s = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & mask; + *status = s; } dds_entity_unlock (e); return ret; @@ -721,15 +960,15 @@ dds_return_t dds_take_status (dds_entity_t entity, uint32_t *status, uint32_t ma dds_return_t dds_get_domainid (dds_entity_t entity, dds_domainid_t *id) { dds_entity *e; - dds_retcode_t rc; + dds_return_t rc; if (id == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; - *id = e->m_domainid; + *id = e->m_domain->m_id; dds_entity_unlock(e); return DDS_RETCODE_OK; } @@ -737,28 +976,23 @@ dds_return_t dds_get_domainid (dds_entity_t entity, dds_domainid_t *id) dds_return_t dds_get_instance_handle (dds_entity_t entity, dds_instance_handle_t *ihdl) { dds_entity *e; - dds_retcode_t rc; dds_return_t ret; if (ihdl == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); - - if (e->m_deriver.get_instance_hdl) - ret = e->m_deriver.get_instance_hdl (e, ihdl); - else - ret = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); - dds_entity_unlock(e); + if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return ret; + *ihdl = e->m_iid; + dds_entity_unpin(e); return ret; } -dds_retcode_t dds_entity_claim (dds_entity_t hdl, dds_entity **eptr) +dds_return_t dds_entity_pin (dds_entity_t hdl, dds_entity **eptr) { - dds_retcode_t hres; + dds_return_t hres; struct dds_handle_link *hdllink; - if ((hres = dds_handle_claim (hdl, &hdllink)) != DDS_RETCODE_OK) + if ((hres = dds_handle_pin (hdl, &hdllink)) < 0) return hres; else { @@ -767,41 +1001,26 @@ dds_retcode_t dds_entity_claim (dds_entity_t hdl, dds_entity **eptr) } } -void dds_entity_release (dds_entity *e) +void dds_entity_unpin (dds_entity *e) { - dds_handle_release (&e->m_hdllink); + dds_handle_unpin (&e->m_hdllink); } -dds_retcode_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_entity **eptr) +dds_return_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_entity **eptr) { - dds_retcode_t hres; + dds_return_t hres; dds_entity *e; - - /* When the given handle already contains an error, then return that - * same error to retain the original information. */ - if ((hres = dds_entity_claim (hdl, &e)) != DDS_RETCODE_OK) + if ((hres = dds_entity_pin (hdl, &e)) < 0) return hres; else { if (dds_entity_kind (e) != kind && kind != DDS_KIND_DONTCARE) { - dds_handle_release (&e->m_hdllink); + dds_entity_unpin (e); return DDS_RETCODE_ILLEGAL_OPERATION; } ddsrt_mutex_lock (&e->m_mutex); - /* FIXME: The handle could have been closed while we were waiting for the mutex -- that should be handled differently! - - For now, however, it is really important at two points in the logic: - (1) preventing creating new entities as children of a one that is currently being deleted, and - (2) preventing dds_delete_impl from doing anything once the entity is being deleted. - - Without (1), it would be possible to add children while trying to delete them, without (2) you're looking at crashes. */ - if (dds_handle_is_closed (&e->m_hdllink)) - { - dds_entity_unlock (e); - return DDS_RETCODE_BAD_PARAMETER; - } *eptr = e; return DDS_RETCODE_OK; } @@ -810,25 +1029,25 @@ dds_retcode_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_ent void dds_entity_unlock (dds_entity *e) { ddsrt_mutex_unlock (&e->m_mutex); - dds_handle_release (&e->m_hdllink); + dds_handle_unpin (&e->m_hdllink); } dds_return_t dds_triggered (dds_entity_t entity) { dds_entity *e; dds_return_t ret; - dds_retcode_t rc; - if ((rc = dds_entity_lock(entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); - ddsrt_mutex_lock (&e->m_observers_lock); - ret = (e->m_trigger != 0); - ddsrt_mutex_unlock (&e->m_observers_lock); + if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) + return ret; + if (entity_has_status (e)) + ret = ((ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & SAM_STATUS_MASK) != 0); + else + ret = (ddsrt_atomic_ld32 (&e->m_status.m_trigger) != 0); dds_entity_unlock (e); return ret; } -static bool in_observer_list_p (const struct dds_entity *observed, const dds_entity_t observer) +static bool in_observer_list_p (const struct dds_entity *observed, const dds_entity *observer) { dds_entity_observer *cur; for (cur = observed->m_observers; cur != NULL; cur = cur->m_next) @@ -837,9 +1056,9 @@ static bool in_observer_list_p (const struct dds_entity *observed, const dds_ent return false; } -dds_retcode_t dds_entity_observer_register_nl (dds_entity *observed, dds_entity_t observer, dds_entity_callback cb) +dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *observer, dds_entity_callback cb, dds_entity_delete_callback delete_cb) { - dds_retcode_t rc; + dds_return_t rc; assert (observed); ddsrt_mutex_lock (&observed->m_observers_lock); if (in_observer_list_p (observed, observer)) @@ -848,6 +1067,7 @@ dds_retcode_t dds_entity_observer_register_nl (dds_entity *observed, dds_entity_ { dds_entity_observer *o = ddsrt_malloc (sizeof (dds_entity_observer)); o->m_cb = cb; + o->m_delete_cb = delete_cb; o->m_observer = observer; o->m_next = observed->m_observers; observed->m_observers = o; @@ -857,21 +1077,9 @@ dds_retcode_t dds_entity_observer_register_nl (dds_entity *observed, dds_entity_ return rc; } -dds_retcode_t dds_entity_observer_register (dds_entity_t observed, dds_entity_t observer, dds_entity_callback cb) +dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *observer) { - dds_retcode_t rc; - dds_entity *e; - assert (cb); - if ((rc = dds_entity_lock (observed, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return rc; - rc = dds_entity_observer_register_nl (e, observer, cb); - dds_entity_unlock (e); - return rc; -} - -dds_retcode_t dds_entity_observer_unregister_nl (dds_entity *observed, dds_entity_t observer) -{ - dds_retcode_t rc; + dds_return_t rc; dds_entity_observer *prev, *idx; ddsrt_mutex_lock (&observed->m_observers_lock); @@ -897,17 +1105,6 @@ dds_retcode_t dds_entity_observer_unregister_nl (dds_entity *observed, dds_entit return rc; } -dds_retcode_t dds_entity_observer_unregister (dds_entity_t observed, dds_entity_t observer) -{ - dds_retcode_t rc; - dds_entity *e; - if ((rc = dds_entity_lock (observed, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return rc; - rc = dds_entity_observer_unregister_nl (e, observer); - dds_entity_unlock (e); - return rc; -} - static void dds_entity_observers_delete (dds_entity *observed) { dds_entity_observer *idx; @@ -929,30 +1126,53 @@ static void dds_entity_observers_signal (dds_entity *observed, uint32_t status) idx->m_cb (idx->m_observer, observed->m_hdllink.hdl, status); } -void dds_entity_status_signal (dds_entity *e) +static void dds_entity_observers_signal_delete (dds_entity *observed) +{ + for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next) + idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl); +} + +void dds_entity_status_signal (dds_entity *e, uint32_t status) { ddsrt_mutex_lock (&e->m_observers_lock); - dds_entity_observers_signal (e, e->m_trigger); + dds_entity_observers_signal (e, status); ddsrt_mutex_unlock (&e->m_observers_lock); } -void dds_entity_status_set (dds_entity *e, uint32_t t) +void dds_entity_status_set (dds_entity *e, status_mask_t status) { - if (!(e->m_trigger & t)) - { - e->m_trigger |= e->m_status_enable & t; - dds_entity_observers_signal (e, e->m_trigger); - } + assert (entity_has_status (e)); + uint32_t old, delta, new; + do { + old = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask); + delta = ((uint32_t) status & (old >> SAM_ENABLED_SHIFT)); + if (delta == 0) + return; + new = old | delta; + } while (!ddsrt_atomic_cas32 (&e->m_status.m_status_and_mask, old, new)); + if (delta) + dds_entity_observers_signal (e, status); +} + +void dds_entity_trigger_set (dds_entity *e, uint32_t t) +{ + assert (! entity_has_status (e)); + uint32_t oldst; + do { + oldst = ddsrt_atomic_ld32 (&e->m_status.m_trigger); + } while (!ddsrt_atomic_cas32 (&e->m_status.m_trigger, oldst, t)); + if (oldst == 0 && t != 0) + dds_entity_observers_signal (e, t); } dds_entity_t dds_get_topic (dds_entity_t entity) { - dds_retcode_t rc; + dds_return_t rc; dds_entity_t hdl; dds_entity *e; if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; switch (dds_entity_kind (e)) { case DDS_KIND_READER: { @@ -973,7 +1193,7 @@ dds_entity_t dds_get_topic (dds_entity_t entity) break; } default: { - hdl = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + hdl = DDS_RETCODE_ILLEGAL_OPERATION; break; } } @@ -984,9 +1204,9 @@ dds_entity_t dds_get_topic (dds_entity_t entity) dds_return_t dds_generic_unimplemented_operation_manykinds (dds_entity_t handle, size_t nkinds, const dds_entity_kind_t *kinds) { dds_entity *e; - dds_retcode_t ret; - if ((ret = dds_entity_claim (handle, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (ret); + dds_return_t ret; + if ((ret = dds_entity_pin (handle, &e)) != DDS_RETCODE_OK) + return ret; else { const dds_entity_kind_t actual = dds_entity_kind (e); @@ -1000,8 +1220,8 @@ dds_return_t dds_generic_unimplemented_operation_manykinds (dds_entity_t handle, break; } } - dds_entity_release (e); - return DDS_ERRNO (ret); + dds_entity_unpin (e); + return ret; } } diff --git a/src/core/ddsc/src/dds_guardcond.c b/src/core/ddsc/src/dds_guardcond.c index c4feee0..d6f7de6 100644 --- a/src/core/ddsc/src/dds_guardcond.c +++ b/src/core/ddsc/src/dds_guardcond.c @@ -14,24 +14,33 @@ #include "dds__reader.h" #include "dds__guardcond.h" #include "dds__participant.h" -#include "dds__err.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_guardcond) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_guardcond) + +const struct dds_entity_deriver dds_entity_deriver_guardcondition = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_entity_deriver_dummy_delete, + .set_qos = dds_entity_deriver_dummy_set_qos, + .validate_status = dds_entity_deriver_dummy_validate_status +}; dds_entity_t dds_create_guardcondition (dds_entity_t participant) { dds_participant *pp; - dds_retcode_t rc; + dds_return_t rc; if ((rc = dds_participant_lock (participant, &pp)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; else { - dds_guardcond * gcond = dds_alloc (sizeof (*gcond)); + dds_guardcond *gcond = dds_alloc (sizeof (*gcond)); dds_entity_t hdl = dds_entity_init (&gcond->m_entity, &pp->m_entity, DDS_KIND_COND_GUARD, NULL, NULL, 0); + gcond->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&pp->m_entity, &gcond->m_entity); dds_participant_unlock (pp); return hdl; } @@ -40,18 +49,16 @@ dds_entity_t dds_create_guardcondition (dds_entity_t participant) dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered) { dds_guardcond *gcond; - dds_retcode_t rc; + dds_return_t rc; if ((rc = dds_guardcond_lock (condition, &gcond)) != DDS_RETCODE_OK) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return rc; else { - ddsrt_mutex_lock (&gcond->m_entity.m_observers_lock); if (triggered) - dds_entity_status_set (&gcond->m_entity, DDS_WAITSET_TRIGGER_STATUS); + dds_entity_trigger_set (&gcond->m_entity, 1); else - dds_entity_status_reset (&gcond->m_entity, DDS_WAITSET_TRIGGER_STATUS); - ddsrt_mutex_unlock (&gcond->m_entity.m_observers_lock); + ddsrt_atomic_st32 (&gcond->m_entity.m_status.m_trigger, 0); dds_guardcond_unlock (gcond); return DDS_RETCODE_OK; } @@ -60,19 +67,17 @@ dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered) dds_return_t dds_read_guardcondition (dds_entity_t condition, bool *triggered) { dds_guardcond *gcond; - dds_retcode_t rc; + dds_return_t rc; if (triggered == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; *triggered = false; if ((rc = dds_guardcond_lock (condition, &gcond)) != DDS_RETCODE_OK) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return rc; else { - ddsrt_mutex_lock (&gcond->m_entity.m_observers_lock); - *triggered = dds_entity_status_match (&gcond->m_entity, DDS_WAITSET_TRIGGER_STATUS); - ddsrt_mutex_unlock (&gcond->m_entity.m_observers_lock); + *triggered = (ddsrt_atomic_ld32 (&gcond->m_entity.m_status.m_trigger) != 0); dds_guardcond_unlock (gcond); return DDS_RETCODE_OK; } @@ -81,20 +86,17 @@ dds_return_t dds_read_guardcondition (dds_entity_t condition, bool *triggered) dds_return_t dds_take_guardcondition (dds_entity_t condition, bool *triggered) { dds_guardcond *gcond; - dds_retcode_t rc; + dds_return_t rc; if (triggered == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; *triggered = false; if ((rc = dds_guardcond_lock (condition, &gcond)) != DDS_RETCODE_OK) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return rc; else { - ddsrt_mutex_lock (&gcond->m_entity.m_observers_lock); - *triggered = dds_entity_status_match (&gcond->m_entity, DDS_WAITSET_TRIGGER_STATUS); - dds_entity_status_reset (&gcond->m_entity, DDS_WAITSET_TRIGGER_STATUS); - ddsrt_mutex_unlock (&gcond->m_entity.m_observers_lock); + *triggered = (ddsrt_atomic_and32_ov (&gcond->m_entity.m_status.m_trigger, 0) != 0); dds_guardcond_unlock (gcond); return DDS_RETCODE_OK; } diff --git a/src/core/ddsc/src/dds_handles.c b/src/core/ddsc/src/dds_handles.c index dd509dd..7b5afdc 100644 --- a/src/core/ddsc/src/dds_handles.c +++ b/src/core/ddsc/src/dds_handles.c @@ -19,7 +19,6 @@ #include "dds/ddsi/q_thread.h" #include "dds__handles.h" #include "dds__types.h" -#include "dds__err.h" /* FIXME: this code isn't really correct when USE_CHH is set: - the DDS entity code doesn't really play by the awake/asleep mechanism @@ -29,7 +28,19 @@ #define USE_CHH 0 #define HDL_FLAG_CLOSED (0x80000000u) -#define HDL_COUNT_MASK (0x00ffffffu) + +/* ref count: # outstanding references to this handle/object (not so sure it is + ideal to have a one-to-one mapping between the two, but that is what the rest + of the code assumes at the moment); so this limits one to having, e.g., no + more than 64k endpoints referencing the same topic */ +#define HDL_REFCOUNT_MASK (0x0ffff000u) +#define HDL_REFCOUNT_UNIT (0x00001000u) +#define HDL_REFCOUNT_SHIFT 12 + +/* pin count: # concurrent operations, so allowing up to 4096 threads had better + be enough ... */ +#define HDL_PINCOUNT_MASK (0x00000fffu) +#define HDL_PINCOUNT_UNIT (0x00000001u) /* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a random generator for finding a free one, the time spent in the dds_handle_create @@ -65,13 +76,12 @@ static int handle_equal (const void *va, const void *vb) return a->hdl == b->hdl; } -dds_return_t dds_handle_server_init (void (*free_via_gc) (void *x)) +dds_return_t dds_handle_server_init (void) { #if USE_CHH handles.ht = ddsrt_chh_new (128, handle_hash, handle_equal, free_via_gc); #else handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal); - (void) free_via_gc; #endif handles.count = 0; ddsrt_mutex_init (&handles.lock); @@ -106,7 +116,7 @@ static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, e #endif static dds_handle_t dds_handle_create_int (struct dds_handle_link *link) { - ddsrt_atomic_st32 (&link->cnt_flags, 0); + ddsrt_atomic_st32 (&link->cnt_flags, HDL_REFCOUNT_UNIT); do { do { link->hdl = (int32_t) (ddsrt_random () & INT32_MAX); @@ -128,7 +138,7 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link) if (handles.count == MAX_HANDLES) { ddsrt_mutex_unlock (&handles.lock); - ret = DDS_ERRNO (DDS_RETCODE_OUT_OF_RESOURCES); + ret = DDS_RETCODE_OUT_OF_RESOURCES; } else { @@ -160,11 +170,12 @@ int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout) #endif assert (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED); ddsrt_mutex_lock (&handles.lock); - if ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_COUNT_MASK) != 0) + if ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0) { - /* FIXME: */ + /* FIXME: there is no sensible solution when this times out, so it must + never do that ... */ const dds_time_t abstimeout = dds_time () + timeout; - while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_COUNT_MASK) != 0) + while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0) { if (!ddsrt_cond_waituntil (&handles.cond, &handles.lock, abstimeout)) { @@ -189,7 +200,7 @@ int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout) return DDS_RETCODE_OK; } -int32_t dds_handle_claim (dds_handle_t hdl, struct dds_handle_link **link) +int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link) { #if USE_CHH struct thread_state1 * const ts1 = lookup_thread_state (); @@ -197,7 +208,7 @@ int32_t dds_handle_claim (dds_handle_t hdl, struct dds_handle_link **link) struct dds_handle_link dummy = { .hdl = hdl }; int32_t rc; /* it makes sense to check here for initialization: the first thing any operation - (other than create_participant) does is to call dds_handle_claim on the supplied + (other than create_participant) does is to call dds_handle_pin on the supplied entity, so checking here whether the library has been initialised helps avoid crashes if someone forgets to create a participant (or allows a program to continue after failing to create one). @@ -229,7 +240,7 @@ int32_t dds_handle_claim (dds_handle_t hdl, struct dds_handle_link **link) rc = DDS_RETCODE_BAD_PARAMETER; break; } - } while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cnt_flags, cnt_flags + 1)); + } while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cnt_flags, cnt_flags + HDL_PINCOUNT_UNIT)); } #if USE_CHH thread_state_asleep (ts1); @@ -239,16 +250,18 @@ int32_t dds_handle_claim (dds_handle_t hdl, struct dds_handle_link **link) return rc; } -void dds_handle_claim_inc (struct dds_handle_link *link) +void dds_handle_repin (struct dds_handle_link *link) { + DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1); uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags); assert (!(x & HDL_FLAG_CLOSED)); (void) x; } -void dds_handle_release (struct dds_handle_link *link) +void dds_handle_unpin (struct dds_handle_link *link) { - if (ddsrt_atomic_dec32_ov (&link->cnt_flags) == (HDL_FLAG_CLOSED | 1)) + DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1); + if ((ddsrt_atomic_dec32_ov (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSED | HDL_PINCOUNT_UNIT)) { ddsrt_mutex_lock (&handles.lock); ddsrt_cond_broadcast (&handles.cond); @@ -256,6 +269,25 @@ void dds_handle_release (struct dds_handle_link *link) } } +void dds_handle_add_ref (struct dds_handle_link *link) +{ + ddsrt_atomic_add32 (&link->cnt_flags, HDL_REFCOUNT_UNIT); +} + +bool dds_handle_drop_ref (struct dds_handle_link *link) +{ + assert ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) != 0); + uint32_t old, new; + do { + old = ddsrt_atomic_ld32 (&link->cnt_flags); + if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT) + new = old - HDL_REFCOUNT_UNIT; + else + new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSED; + } while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new)); + return (new & HDL_REFCOUNT_MASK) == 0; +} + bool dds_handle_is_closed (struct dds_handle_link *link) { return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED) != 0; diff --git a/src/core/ddsc/src/dds_init.c b/src/core/ddsc/src/dds_init.c index 9db9187..8c64274 100644 --- a/src/core/ddsc/src/dds_init.c +++ b/src/core/ddsc/src/dds_init.c @@ -20,7 +20,6 @@ #include "dds__init.h" #include "dds__rhc.h" #include "dds__domain.h" -#include "dds__err.h" #include "dds__builtin.h" #include "dds__whc_builtintopic.h" #include "dds/ddsi/ddsi_iid.h" @@ -36,271 +35,58 @@ #define DOMAIN_ID_MIN 0 #define DOMAIN_ID_MAX 230 -struct q_globals gv; +dds_globals dds_global; -dds_globals dds_global = { .m_default_domain = DDS_DOMAIN_DEFAULT }; -static struct cfgst * dds_cfgst = NULL; - -static void free_via_gc_cb (struct gcreq *gcreq) +dds_return_t dds_init (void) { - void *bs = gcreq->arg; - gcreq_free (gcreq); - ddsrt_free (bs); -} + dds_return_t ret; -static void free_via_gc (void *bs) -{ - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, free_via_gc_cb); - gcreq->arg = bs; - gcreq_enqueue (gcreq); -} - -dds_return_t -dds_init(dds_domainid_t domain) -{ - dds_return_t ret = DDS_RETCODE_OK; - char * uri = NULL; - char progname[50] = "UNKNOWN"; /* FIXME: once retrieving process names is back in */ - char hostname[64]; - uint32_t len; - ddsrt_mutex_t *init_mutex; - - /* Be sure the DDS lifecycle resources are initialized. */ - ddsrt_init(); - init_mutex = ddsrt_get_singleton_mutex(); - - ddsrt_mutex_lock(init_mutex); - - dds_global.m_init_count++; - if (dds_global.m_init_count > 1) + ddsrt_init (); + ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex (); + ddsrt_mutex_lock (init_mutex); + if (dds_global.m_init_count++ != 0) { - goto skip; + ddsrt_mutex_unlock (init_mutex); + return DDS_RETCODE_OK; } - gv.tstart = now (); - gv.exception = false; ddsrt_mutex_init (&dds_global.m_mutex); - thread_states_init_static(); + ddsi_iid_init (); + thread_states_init_static (); + thread_states_init (64); + upgrade_main_thread (); - (void)ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &uri); - dds_cfgst = config_init (uri); - if (dds_cfgst == NULL) + if (dds_handle_server_init () != DDS_RETCODE_OK) { - DDS_LOG(DDS_LC_CONFIG, "Failed to parse configuration XML file %s\n", uri); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_config; - } - - /* if a domain id was explicitly given, check & fix up the configuration */ - if (domain != DDS_DOMAIN_DEFAULT) - { - if (domain < 0 || domain > 230) - { - DDS_ERROR("requested domain id %"PRId32" is out of range\n", domain); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_config_domainid; - } - else if (config.domainId.isdefault) - { - config.domainId.value = domain; - } - else if (domain != config.domainId.value) - { - DDS_ERROR("requested domain id %"PRId32" is inconsistent with configured value %"PRId32"\n", domain, config.domainId.value); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_config_domainid; - } - } - - /* The config.domainId can change internally in DDSI. So, remember what the - * main configured domain id is. */ - dds_global.m_default_domain = config.domainId.value; - - if (rtps_config_prep(dds_cfgst) != 0) - { - DDS_LOG(DDS_LC_CONFIG, "Failed to configure RTPS\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_rtps_config; - } - - upgrade_main_thread(); - ddsrt_avl_init(&dds_domaintree_def, &dds_global.m_domains); - - /* Start monitoring the liveliness of all threads. */ - if (!config.liveliness_monitoring) - gv.threadmon = NULL; - else - { - gv.threadmon = ddsi_threadmon_new (); - if (gv.threadmon == NULL) - { - DDS_ERROR("Failed to create a thread monitor\n"); - ret = DDS_ERRNO(DDS_RETCODE_OUT_OF_RESOURCES); - goto fail_threadmon_new; - } - } - - if (rtps_init () < 0) - { - DDS_LOG(DDS_LC_CONFIG, "Failed to initialize RTPS\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_rtps_init; - } - - if (dds_handle_server_init (free_via_gc) != DDS_RETCODE_OK) - { - DDS_ERROR("Failed to initialize internal handle server\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); + DDS_ERROR ("Failed to initialize internal handle server\n"); + ret = DDS_RETCODE_ERROR; goto fail_handleserver; } - dds__builtin_init (); - - if (rtps_start () < 0) - { - DDS_LOG(DDS_LC_CONFIG, "Failed to start RTPS\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_rtps_start; - } - - if (gv.threadmon && ddsi_threadmon_start(gv.threadmon) < 0) - { - DDS_ERROR("Failed to start the servicelease\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_threadmon_start; - } - - /* Set additional default participant properties */ - - gv.default_plist_pp.process_id = (unsigned)ddsrt_getpid(); - gv.default_plist_pp.present |= PP_PRISMTECH_PROCESS_ID; - gv.default_plist_pp.exec_name = dds_string_alloc(32); - (void) snprintf(gv.default_plist_pp.exec_name, 32, "%s: %u", DDS_PROJECT_NAME, gv.default_plist_pp.process_id); - len = (uint32_t) (13 + strlen(gv.default_plist_pp.exec_name)); - gv.default_plist_pp.present |= PP_PRISMTECH_EXEC_NAME; - if (ddsrt_gethostname(hostname, sizeof(hostname)) == DDS_RETCODE_OK) - { - gv.default_plist_pp.node_name = dds_string_dup(hostname); - gv.default_plist_pp.present |= PP_PRISMTECH_NODE_NAME; - } - gv.default_plist_pp.entity_name = dds_alloc(len); - (void) snprintf(gv.default_plist_pp.entity_name, len, "%s<%u>", progname, - gv.default_plist_pp.process_id); - gv.default_plist_pp.present |= PP_ENTITY_NAME; - -skip: - ddsrt_mutex_unlock(init_mutex); + ddsrt_mutex_unlock (init_mutex); return DDS_RETCODE_OK; -fail_threadmon_start: - if (gv.threadmon) - ddsi_threadmon_stop (gv.threadmon); - dds_handle_server_fini(); fail_handleserver: - rtps_stop (); -fail_rtps_start: - dds__builtin_fini (); - rtps_fini (); -fail_rtps_init: - if (gv.threadmon) - { - ddsi_threadmon_free (gv.threadmon); - gv.threadmon = NULL; - } -fail_threadmon_new: - downgrade_main_thread (); - thread_states_fini(); -fail_rtps_config: -fail_config_domainid: - dds_global.m_default_domain = DDS_DOMAIN_DEFAULT; - config_fini (dds_cfgst); - dds_cfgst = NULL; -fail_config: ddsrt_mutex_destroy (&dds_global.m_mutex); dds_global.m_init_count--; - ddsrt_mutex_unlock(init_mutex); - ddsrt_fini(); + ddsrt_mutex_unlock (init_mutex); + ddsrt_fini (); return ret; } extern void dds_fini (void) { - ddsrt_mutex_t *init_mutex; - init_mutex = ddsrt_get_singleton_mutex(); - ddsrt_mutex_lock(init_mutex); - assert(dds_global.m_init_count > 0); - dds_global.m_init_count--; - if (dds_global.m_init_count == 0) + ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex (); + ddsrt_mutex_lock (init_mutex); + assert (dds_global.m_init_count > 0); + if (--dds_global.m_init_count == 0) { - if (gv.threadmon) - ddsi_threadmon_stop (gv.threadmon); - dds_handle_server_fini(); - rtps_stop (); - dds__builtin_fini (); - rtps_fini (); - if (gv.threadmon) - ddsi_threadmon_free (gv.threadmon); - gv.threadmon = NULL; + dds_handle_server_fini (); downgrade_main_thread (); thread_states_fini (); - - config_fini (dds_cfgst); - dds_cfgst = NULL; + ddsi_iid_fini (); ddsrt_mutex_destroy (&dds_global.m_mutex); - dds_global.m_default_domain = DDS_DOMAIN_DEFAULT; } - ddsrt_mutex_unlock(init_mutex); - ddsrt_fini(); -} - -static int dds__init_plugin (void) -{ - if (dds_global.m_dur_init) (dds_global.m_dur_init) (); - return 0; -} - -static void dds__fini_plugin (void) -{ - if (dds_global.m_dur_fini) (dds_global.m_dur_fini) (); -} - -void ddsi_plugin_init (void) -{ - ddsi_plugin.init_fn = dds__init_plugin; - ddsi_plugin.fini_fn = dds__fini_plugin; - - ddsi_plugin.builtintopic_is_visible = dds__builtin_is_visible; - ddsi_plugin.builtintopic_get_tkmap_entry = dds__builtin_get_tkmap_entry; - ddsi_plugin.builtintopic_write = dds__builtin_write; - - ddsi_plugin.rhc_plugin.rhc_free_fn = dds_rhc_free; - ddsi_plugin.rhc_plugin.rhc_store_fn = dds_rhc_store; - ddsi_plugin.rhc_plugin.rhc_unregister_wr_fn = dds_rhc_unregister_wr; - ddsi_plugin.rhc_plugin.rhc_relinquish_ownership_fn = dds_rhc_relinquish_ownership; - ddsi_plugin.rhc_plugin.rhc_set_qos_fn = dds_rhc_set_qos; -} - -//provides explicit default domain id. -dds_domainid_t dds_domain_default (void) -{ - return dds_global.m_default_domain; -} - -dds_return_t -dds__check_domain( - dds_domainid_t domain) -{ - dds_return_t ret = DDS_RETCODE_OK; - /* If domain is default: use configured id. */ - if (domain != DDS_DOMAIN_DEFAULT) - { - /* Specific domain has to be the same as the configured domain. */ - if (domain != dds_global.m_default_domain) - { - DDS_ERROR("Inconsistent domain configuration detected: domain on " - "configuration: %"PRId32", domain %"PRId32"\n", dds_global.m_default_domain, domain); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - } - } - return ret; + ddsrt_mutex_unlock (init_mutex); + ddsrt_fini (); } diff --git a/src/core/ddsc/src/dds_instance.c b/src/core/ddsc/src/dds_instance.c index 903d7ee..31a027a 100644 --- a/src/core/ddsc/src/dds_instance.c +++ b/src/core/ddsc/src/dds_instance.c @@ -17,421 +17,308 @@ #include "dds__write.h" #include "dds__writer.h" #include "dds__rhc.h" -#include "dds__err.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_globals.h" -dds_return_t -dds_writedispose( - dds_entity_t writer, - const void *data) +dds_return_t dds_writedispose (dds_entity_t writer, const void *data) { - return dds_writedispose_ts(writer, data, dds_time()); + return dds_writedispose_ts (writer, data, dds_time ()); } -dds_return_t -dds_dispose( - dds_entity_t writer, - const void *data) +dds_return_t dds_dispose (dds_entity_t writer, const void *data) { - return dds_dispose_ts(writer, data, dds_time()); + return dds_dispose_ts (writer, data, dds_time ()); } -dds_return_t -dds_dispose_ih( - dds_entity_t writer, - dds_instance_handle_t handle) +dds_return_t dds_dispose_ih (dds_entity_t writer, dds_instance_handle_t handle) { - return dds_dispose_ih_ts(writer, handle, dds_time()); + return dds_dispose_ih_ts (writer, handle, dds_time ()); } -static struct ddsi_tkmap_instance* -dds_instance_find( - const dds_topic *topic, - const void *data, - const bool create) +static struct ddsi_tkmap_instance *dds_instance_find (const dds_topic *topic, const void *data, const bool create) { - struct ddsi_serdata *sd = ddsi_serdata_from_sample (topic->m_stopic, SDK_KEY, data); - struct ddsi_tkmap_instance * inst = ddsi_tkmap_find (sd, false, create); - ddsi_serdata_unref (sd); - return inst; + struct ddsi_serdata *sd = ddsi_serdata_from_sample (topic->m_stopic, SDK_KEY, data); + struct ddsi_tkmap_instance *inst = ddsi_tkmap_find (topic->m_entity.m_domain->gv.m_tkmap, sd, create); + ddsi_serdata_unref (sd); + return inst; } -static void -dds_instance_remove( - const dds_topic *topic, - const void *data, - dds_instance_handle_t handle) +static void dds_instance_remove (struct dds_domain *dom, const dds_topic *topic, const void *data, dds_instance_handle_t handle) { - struct ddsi_tkmap_instance * inst; - - if (handle != DDS_HANDLE_NIL) - { - inst = ddsi_tkmap_find_by_id (gv.m_tkmap, handle); - } - else - { - assert (data); - inst = dds_instance_find (topic, data, false); - } - if (inst) - { - ddsi_tkmap_instance_unref (inst); - } + struct ddsi_tkmap_instance *inst; + if (handle != DDS_HANDLE_NIL) + inst = ddsi_tkmap_find_by_id (dom->gv.m_tkmap, handle); + else + { + assert (data); + inst = dds_instance_find (topic, data, false); + } + if (inst) + { + ddsi_tkmap_instance_unref (dom->gv.m_tkmap, inst); + } } -static const dds_topic *dds_instance_info (dds_entity *e) +dds_return_t dds_register_instance (dds_entity_t writer, dds_instance_handle_t *handle, const void *data) { - const dds_topic *topic; - switch (dds_entity_kind (e)) - { - case DDS_KIND_READER: - topic = ((dds_reader*) e)->m_topic; - break; - case DDS_KIND_WRITER: - topic = ((dds_writer*) e)->m_topic; - break; - default: - assert (0); - topic = NULL; - } - return topic; -} + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_writer *wr; + dds_return_t ret; -static const dds_topic * dds_instance_info_by_hdl (dds_entity_t e) -{ - const dds_topic * topic = NULL; - dds_retcode_t rc; - dds_entity *w_or_r; + if (data == NULL || handle == NULL) + return DDS_RETCODE_BAD_PARAMETER; - rc = dds_entity_lock(e, DDS_KIND_WRITER, &w_or_r); - if (rc == DDS_RETCODE_ILLEGAL_OPERATION) - { - rc = dds_entity_lock(e, DDS_KIND_READER, &w_or_r); - } - if (rc != DDS_RETCODE_OK) - { - return NULL; - } - topic = dds_instance_info(w_or_r); - dds_entity_unlock(w_or_r); - return topic; -} - -dds_return_t -dds_register_instance( - dds_entity_t writer, - dds_instance_handle_t *handle, - const void *data) -{ - struct thread_state1 * const ts1 = lookup_thread_state (); - struct ddsi_tkmap_instance * inst; - dds_writer *wr; - dds_return_t ret; - dds_retcode_t rc; - - if(data == NULL){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - if(handle == NULL){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - ret = DDS_ERRNO(rc); - goto err; - } - thread_state_awake (ts1); - inst = dds_instance_find (wr->m_topic, data, true); - if(inst != NULL){ - *handle = inst->m_iid; - ret = DDS_RETCODE_OK; - } else { - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - } - thread_state_asleep (ts1); - dds_writer_unlock(wr); -err: + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + struct ddsi_tkmap_instance * const inst = dds_instance_find (wr->m_topic, data, true); + if (inst == NULL) + ret = DDS_RETCODE_ERROR; + else + { + *handle = inst->m_iid; + ret = DDS_RETCODE_OK; + } + thread_state_asleep (ts1); + dds_writer_unlock (wr); + return ret; } -dds_return_t -dds_unregister_instance( - dds_entity_t writer, - const void *data) +dds_return_t dds_unregister_instance (dds_entity_t writer, const void *data) { - return dds_unregister_instance_ts (writer, data, dds_time()); + return dds_unregister_instance_ts (writer, data, dds_time ()); } -dds_return_t -dds_unregister_instance_ih( - dds_entity_t writer, - dds_instance_handle_t handle) +dds_return_t dds_unregister_instance_ih (dds_entity_t writer, dds_instance_handle_t handle) { - return dds_unregister_instance_ih_ts(writer, handle, dds_time()); + return dds_unregister_instance_ih_ts (writer, handle, dds_time ()); } -dds_return_t -dds_unregister_instance_ts( - dds_entity_t writer, - const void *data, - dds_time_t timestamp) +dds_return_t dds_unregister_instance_ts (dds_entity_t writer, const void *data, dds_time_t timestamp) { - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret = DDS_RETCODE_OK; - dds_retcode_t rc; - bool autodispose = true; - dds_write_action action = DDS_WR_ACTION_UNREGISTER; - dds_writer *wr; + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret; + bool autodispose = true; + dds_write_action action = DDS_WR_ACTION_UNREGISTER; + dds_writer *wr; - if (data == NULL){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - if(timestamp < 0){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - ret = DDS_ERRNO(rc); - goto err; - } + if (data == NULL || timestamp < 0) + return DDS_RETCODE_BAD_PARAMETER; - if (wr->m_entity.m_qos) { - dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose); - } - thread_state_awake (ts1); - if (autodispose) { - dds_instance_remove (wr->m_topic, data, DDS_HANDLE_NIL); - action |= DDS_WR_DISPOSE_BIT; - } - ret = dds_write_impl (wr, data, timestamp, action); - thread_state_asleep (ts1); - dds_writer_unlock(wr); -err: + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + if (wr->m_entity.m_qos) + dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose); + + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + if (autodispose) + { + dds_instance_remove (wr->m_entity.m_domain, wr->m_topic, data, DDS_HANDLE_NIL); + action |= DDS_WR_DISPOSE_BIT; + } + ret = dds_write_impl (wr, data, timestamp, action); + thread_state_asleep (ts1); + dds_writer_unlock (wr); + return ret; } -dds_return_t -dds_unregister_instance_ih_ts( - dds_entity_t writer, - dds_instance_handle_t handle, - dds_time_t timestamp) +dds_return_t dds_unregister_instance_ih_ts (dds_entity_t writer, dds_instance_handle_t handle, dds_time_t timestamp) { - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret = DDS_RETCODE_OK; - dds_retcode_t rc; - bool autodispose = true; - dds_write_action action = DDS_WR_ACTION_UNREGISTER; - dds_writer *wr; - struct ddsi_tkmap_instance *tk; + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret = DDS_RETCODE_OK; + bool autodispose = true; + dds_write_action action = DDS_WR_ACTION_UNREGISTER; + dds_writer *wr; + struct ddsi_tkmap_instance *tk; - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - ret = DDS_ERRNO(rc); - goto err; - } - - if (wr->m_entity.m_qos) { - dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose); - } - if (autodispose) { - dds_instance_remove (wr->m_topic, NULL, handle); - action |= DDS_WR_DISPOSE_BIT; - } - - thread_state_awake (ts1); - tk = ddsi_tkmap_find_by_id (gv.m_tkmap, handle); - if (tk) { - struct ddsi_sertopic *tp = wr->m_topic->m_stopic; - void *sample = ddsi_sertopic_alloc_sample (tp); - ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL); - ddsi_tkmap_instance_unref (tk); - ret = dds_write_impl (wr, sample, timestamp, action); - ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL); - } else { - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - } - thread_state_asleep (ts1); - dds_writer_unlock(wr); -err: + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + if (wr->m_entity.m_qos) + dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose); + + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + if (autodispose) + { + dds_instance_remove (wr->m_entity.m_domain, wr->m_topic, NULL, handle); + action |= DDS_WR_DISPOSE_BIT; + } + if ((tk = ddsi_tkmap_find_by_id (wr->m_entity.m_domain->gv.m_tkmap, handle)) == NULL) + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + else + { + struct ddsi_sertopic *tp = wr->m_topic->m_stopic; + void *sample = ddsi_sertopic_alloc_sample (tp); + ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL); + ddsi_tkmap_instance_unref (wr->m_entity.m_domain->gv.m_tkmap, tk); + ret = dds_write_impl (wr, sample, timestamp, action); + ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL); + } + thread_state_asleep (ts1); + dds_writer_unlock (wr); + return ret; } -dds_return_t -dds_writedispose_ts( - dds_entity_t writer, - const void *data, - dds_time_t timestamp) +dds_return_t dds_writedispose_ts (dds_entity_t writer, const void *data, dds_time_t timestamp) { - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret; - dds_retcode_t rc; - dds_writer *wr; - - rc = dds_writer_lock(writer, &wr); - if (rc == DDS_RETCODE_OK) { - thread_state_awake (ts1); - ret = dds_write_impl (wr, data, timestamp, DDS_WR_ACTION_WRITE_DISPOSE); - if (ret == DDS_RETCODE_OK) { - dds_instance_remove (wr->m_topic, data, DDS_HANDLE_NIL); - } - thread_state_asleep (ts1); - dds_writer_unlock(wr); - } else { - ret = DDS_ERRNO(rc); - } + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret; + dds_writer *wr; + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + if ((ret = dds_write_impl (wr, data, timestamp, DDS_WR_ACTION_WRITE_DISPOSE)) == DDS_RETCODE_OK) + dds_instance_remove (wr->m_entity.m_domain, wr->m_topic, data, DDS_HANDLE_NIL); + thread_state_asleep (ts1); + dds_writer_unlock (wr); + return ret; } -static dds_return_t -dds_dispose_impl( - dds_writer *wr, - const void *data, - dds_instance_handle_t handle, - dds_time_t timestamp) +static dds_return_t dds_dispose_impl (dds_writer *wr, const void *data, dds_instance_handle_t handle, dds_time_t timestamp) ddsrt_nonnull_all; + +static dds_return_t dds_dispose_impl (dds_writer *wr, const void *data, dds_instance_handle_t handle, dds_time_t timestamp) { - dds_return_t ret; - assert(thread_is_awake ()); - assert(wr); - ret = dds_write_impl(wr, data, timestamp, DDS_WR_ACTION_DISPOSE); - if (ret == DDS_RETCODE_OK) { - dds_instance_remove (wr->m_topic, data, handle); - } + dds_return_t ret; + assert (thread_is_awake ()); + if ((ret = dds_write_impl (wr, data, timestamp, DDS_WR_ACTION_DISPOSE)) == DDS_RETCODE_OK) + dds_instance_remove (wr->m_entity.m_domain, wr->m_topic, data, handle); + return ret; +} + +dds_return_t dds_dispose_ts (dds_entity_t writer, const void *data, dds_time_t timestamp) +{ + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret; + dds_writer *wr; + + if (data == NULL) + return DDS_RETCODE_BAD_PARAMETER; + + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + ret = dds_dispose_impl (wr, data, DDS_HANDLE_NIL, timestamp); + thread_state_asleep (ts1); + dds_writer_unlock(wr); + return ret; } -dds_return_t -dds_dispose_ts( - dds_entity_t writer, - const void *data, - dds_time_t timestamp) +dds_return_t dds_dispose_ih_ts (dds_entity_t writer, dds_instance_handle_t handle, dds_time_t timestamp) { - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret; - dds_retcode_t rc; - dds_writer *wr; - - rc = dds_writer_lock(writer, &wr); - if (rc == DDS_RETCODE_OK) { - thread_state_awake (ts1); - ret = dds_dispose_impl(wr, data, DDS_HANDLE_NIL, timestamp); - thread_state_asleep (ts1); - dds_writer_unlock(wr); - } else { - ret = DDS_ERRNO(rc); - } + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret; + dds_writer *wr; + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) return ret; + + struct ddsi_tkmap_instance *tk; + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); + if ((tk = ddsi_tkmap_find_by_id (wr->m_entity.m_domain->gv.m_tkmap, handle)) == NULL) + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + else + { + struct ddsi_sertopic *tp = wr->m_topic->m_stopic; + void *sample = ddsi_sertopic_alloc_sample (tp); + ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL); + ddsi_tkmap_instance_unref (wr->m_entity.m_domain->gv.m_tkmap, tk); + ret = dds_dispose_impl (wr, sample, handle, timestamp); + ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL); + } + thread_state_asleep (ts1); + dds_writer_unlock (wr); + return ret; } -dds_return_t -dds_dispose_ih_ts( - dds_entity_t writer, - dds_instance_handle_t handle, - dds_time_t timestamp) +dds_instance_handle_t dds_lookup_instance (dds_entity_t entity, const void *data) { - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret; - dds_retcode_t rc; - dds_writer *wr; + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_instance_handle_t ih = DDS_HANDLE_NIL; + const dds_topic *topic; + struct ddsi_serdata *sd; + dds_entity *w_or_r; - rc = dds_writer_lock(writer, &wr); - if (rc == DDS_RETCODE_OK) { - struct ddsi_tkmap_instance *tk; - thread_state_awake (ts1); - if ((tk = ddsi_tkmap_find_by_id (gv.m_tkmap, handle)) != NULL) { - struct ddsi_sertopic *tp = wr->m_topic->m_stopic; - void *sample = ddsi_sertopic_alloc_sample (tp); - ddsi_serdata_topicless_to_sample (tp, tk->m_sample, sample, NULL, NULL); - ddsi_tkmap_instance_unref (tk); - ret = dds_dispose_impl (wr, sample, handle, timestamp); - ddsi_sertopic_free_sample (tp, sample, DDS_FREE_ALL); - } else { - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - } - thread_state_asleep (ts1); - dds_writer_unlock(wr); - } else { - ret = DDS_ERRNO(rc); - } + if (data == NULL) + return DDS_HANDLE_NIL; + if (dds_entity_lock (entity, DDS_KIND_DONTCARE, &w_or_r) < 0) + return DDS_HANDLE_NIL; + switch (dds_entity_kind (w_or_r)) + { + case DDS_KIND_WRITER: + topic = ((dds_writer *) w_or_r)->m_topic; + break; + case DDS_KIND_READER: + topic = ((dds_reader *) w_or_r)->m_topic; + break; + default: + dds_entity_unlock (w_or_r); + return DDS_HANDLE_NIL; + } + + thread_state_awake (ts1, &w_or_r->m_domain->gv); + sd = ddsi_serdata_from_sample (topic->m_stopic, SDK_KEY, data); + ih = ddsi_tkmap_lookup (w_or_r->m_domain->gv.m_tkmap, sd); + ddsi_serdata_unref (sd); + thread_state_asleep (ts1); + dds_entity_unlock (w_or_r); + return ih; +} + +dds_instance_handle_t dds_instance_lookup (dds_entity_t entity, const void *data) +{ + return dds_lookup_instance (entity, data); +} + +dds_return_t dds_instance_get_key (dds_entity_t entity, dds_instance_handle_t ih, void *data) +{ + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret; + const dds_topic *topic; + struct ddsi_tkmap_instance *tk; + dds_entity *e; + + if (data == NULL) + return DDS_RETCODE_BAD_PARAMETER; + + if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) < 0) return ret; -} - -dds_instance_handle_t -dds_lookup_instance( - dds_entity_t entity, - const void *data) -{ - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_instance_handle_t ih = DDS_HANDLE_NIL; - const dds_topic * topic; - struct ddsi_tkmap * map = gv.m_tkmap; - struct ddsi_serdata *sd; - - if(data == NULL){ - goto err; - } - - topic = dds_instance_info_by_hdl (entity); - if (topic) { - thread_state_awake (ts1); - sd = ddsi_serdata_from_sample (topic->m_stopic, SDK_KEY, data); - ih = ddsi_tkmap_lookup (map, sd); - ddsi_serdata_unref (sd); - thread_state_asleep (ts1); - } -err: - return ih; -} - -dds_instance_handle_t -dds_instance_lookup ( - dds_entity_t entity, - const void *data) -{ - return dds_lookup_instance(entity, data); -} - -dds_return_t -dds_instance_get_key( - dds_entity_t entity, - dds_instance_handle_t ih, - void *data) -{ - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret; - const dds_topic * topic; - struct ddsi_tkmap_instance * tk; - - if(data == NULL){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - - topic = dds_instance_info_by_hdl (entity); - if(topic == NULL){ - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - thread_state_awake (ts1); - if ((tk = ddsi_tkmap_find_by_id(gv.m_tkmap, ih)) != NULL) { - ddsi_sertopic_zero_sample (topic->m_stopic, data); - ddsi_serdata_topicless_to_sample (topic->m_stopic, tk->m_sample, data, NULL, NULL); - ddsi_tkmap_instance_unref (tk); - ret = DDS_RETCODE_OK; - } else { - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - thread_state_asleep (ts1); -err: - return ret; + switch (dds_entity_kind (e)) + { + case DDS_KIND_WRITER: + topic = ((dds_writer *) e)->m_topic; + break; + case DDS_KIND_READER: + topic = ((dds_reader *) e)->m_topic; + break; + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + topic = ((dds_reader *) e->m_parent)->m_topic; + break; + default: + dds_entity_unlock (e); + return DDS_RETCODE_ILLEGAL_OPERATION; + } + + thread_state_awake (ts1, &e->m_domain->gv); + if ((tk = ddsi_tkmap_find_by_id (e->m_domain->gv.m_tkmap, ih)) == NULL) + ret = DDS_RETCODE_BAD_PARAMETER; + else + { + ddsi_sertopic_zero_sample (topic->m_stopic, data); + ddsi_serdata_topicless_to_sample (topic->m_stopic, tk->m_sample, data, NULL, NULL); + ddsi_tkmap_instance_unref (e->m_domain->gv.m_tkmap, tk); + ret = DDS_RETCODE_OK; + } + thread_state_asleep (ts1); + dds_entity_unlock (e); + return ret; } diff --git a/src/core/ddsc/src/dds_key.c b/src/core/ddsc/src/dds_key.c deleted file mode 100644 index b919c85..0000000 --- a/src/core/ddsc/src/dds_key.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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 -#include - -#include "dds/ddsrt/md5.h" -#include "dds__key.h" -#include "dds__stream.h" -#include "dds/ddsi/ddsi_serdata.h" -#include "dds/ddsi/q_bswap.h" - -#ifndef NDEBUG -static bool keyhash_is_reset(const dds_key_hash_t *kh) -{ - return !kh->m_set; -} -#endif - -/* - dds_key_gen: Generates key and keyhash for a sample. - See section 9.6.3.3 of DDSI spec. -*/ - -static void dds_key_gen_stream (const dds_topic_descriptor_t * const desc, dds_stream_t *os, const char *sample) -{ - const char * src; - const uint32_t * op; - uint32_t i; - uint32_t len = 0; - - for (i = 0; i < desc->m_nkeys; i++) - { - op = desc->m_ops + desc->m_keys[i].m_index; - src = sample + op[1]; - assert ((*op & DDS_OP_FLAG_KEY) && ((DDS_OP_MASK & *op) == DDS_OP_ADR)); - - switch (DDS_OP_TYPE (*op)) - { - case DDS_OP_VAL_1BY: - { - dds_stream_write_uint8 (os, *((const uint8_t *) src)); - break; - } - case DDS_OP_VAL_2BY: - { - dds_stream_write_uint16 (os, *((const uint16_t *) src)); - break; - } - case DDS_OP_VAL_4BY: - { - dds_stream_write_uint32 (os, *((const uint32_t *) src)); - break; - } - case DDS_OP_VAL_8BY: - { - dds_stream_write_uint64 (os, *((const uint64_t *) src)); - break; - } - case DDS_OP_VAL_STR: - { - src = *((char**) src); - } - /* FALLS THROUGH */ - case DDS_OP_VAL_BST: - { - len = (uint32_t) (strlen (src) + 1); - dds_stream_write_uint32 (os, len); - dds_stream_write_buffer (os, len, (const uint8_t *) src); - break; - } - case DDS_OP_VAL_ARR: - { - uint32_t size = dds_op_size[DDS_OP_SUBTYPE (*op)]; - char *dst; - len = size * op[2]; - dst = dds_stream_alignto (os, op[2]); - dds_stream_write_buffer (os, len, (const uint8_t *) src); - if (dds_stream_endian () && (size != 1u)) - dds_stream_swap (dst, size, op[2]); - break; - } - default: assert (0); - } - } -} - -void dds_key_gen (const dds_topic_descriptor_t * const desc, dds_key_hash_t * kh, const char * sample) -{ - assert(keyhash_is_reset(kh)); - - kh->m_set = 1; - if (desc->m_nkeys == 0) - kh->m_iskey = 1; - else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) - { - dds_stream_t os; - kh->m_iskey = 1; - dds_stream_init(&os, 0); - os.m_endian = 0; - os.m_buffer.pv = kh->m_hash; - os.m_size = 16; - dds_key_gen_stream (desc, &os, sample); - } - else - { - dds_stream_t os; - ddsrt_md5_state_t md5st; - kh->m_iskey = 0; - dds_stream_init(&os, 64); - os.m_endian = 0; - dds_key_gen_stream (desc, &os, sample); - ddsrt_md5_init (&md5st); - ddsrt_md5_append (&md5st, os.m_buffer.p8, os.m_index); - ddsrt_md5_finish (&md5st, (unsigned char *) kh->m_hash); - dds_stream_fini (&os); - } -} diff --git a/src/core/ddsc/src/dds_listener.c b/src/core/ddsc/src/dds_listener.c index a325753..eee9ef6 100644 --- a/src/core/ddsc/src/dds_listener.c +++ b/src/core/ddsc/src/dds_listener.c @@ -207,324 +207,169 @@ void dds_merge_listener (dds_listener_t * __restrict dst, const dds_listener_t * void dds_listener_merge (dds_listener_t * __restrict dst, const dds_listener_t * __restrict src) { - dds_merge_listener(dst, src); + dds_merge_listener (dst, src); } /************************************************************************************************ * Setters ************************************************************************************************/ -void -dds_lset_data_available (dds_listener_t * __restrict listener, dds_on_data_available_fn callback) +void dds_lset_data_available (dds_listener_t * __restrict listener, dds_on_data_available_fn callback) { - if (listener) { - listener->on_data_available = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_data_available = callback; } -void -dds_lset_data_on_readers (dds_listener_t * __restrict listener, dds_on_data_on_readers_fn callback) +void dds_lset_data_on_readers (dds_listener_t * __restrict listener, dds_on_data_on_readers_fn callback) { - if (listener) { - listener->on_data_on_readers = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_data_on_readers = callback; } -void -dds_lset_inconsistent_topic (dds_listener_t * __restrict listener, dds_on_inconsistent_topic_fn callback) +void dds_lset_inconsistent_topic (dds_listener_t * __restrict listener, dds_on_inconsistent_topic_fn callback) { - if (listener) { - listener->on_inconsistent_topic = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_inconsistent_topic = callback; } -void -dds_lset_liveliness_changed (dds_listener_t * __restrict listener, dds_on_liveliness_changed_fn callback) +void dds_lset_liveliness_changed (dds_listener_t * __restrict listener, dds_on_liveliness_changed_fn callback) { - if (listener) { - listener->on_liveliness_changed = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_liveliness_changed = callback; } -void -dds_lset_liveliness_lost (dds_listener_t * __restrict listener, dds_on_liveliness_lost_fn callback) +void dds_lset_liveliness_lost (dds_listener_t * __restrict listener, dds_on_liveliness_lost_fn callback) { - if (listener) { - listener->on_liveliness_lost = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_liveliness_lost = callback; } -void -dds_lset_offered_deadline_missed (dds_listener_t * __restrict listener, dds_on_offered_deadline_missed_fn callback) +void dds_lset_offered_deadline_missed (dds_listener_t * __restrict listener, dds_on_offered_deadline_missed_fn callback) { - if (listener) { - listener->on_offered_deadline_missed = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_offered_deadline_missed = callback; } -void -dds_lset_offered_incompatible_qos (dds_listener_t * __restrict listener, dds_on_offered_incompatible_qos_fn callback) +void dds_lset_offered_incompatible_qos (dds_listener_t * __restrict listener, dds_on_offered_incompatible_qos_fn callback) { - if (listener) { - listener->on_offered_incompatible_qos = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_offered_incompatible_qos = callback; } -void -dds_lset_publication_matched (dds_listener_t * __restrict listener, dds_on_publication_matched_fn callback) +void dds_lset_publication_matched (dds_listener_t * __restrict listener, dds_on_publication_matched_fn callback) { - if (listener) { - listener->on_publication_matched = callback; - } else { - DDS_ERROR("Argument listener is NULL"); - } + if (listener) + listener->on_publication_matched = callback; } -void -dds_lset_requested_deadline_missed (dds_listener_t * __restrict listener, dds_on_requested_deadline_missed_fn callback) +void dds_lset_requested_deadline_missed (dds_listener_t * __restrict listener, dds_on_requested_deadline_missed_fn callback) { - if (listener) { - listener->on_requested_deadline_missed = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_requested_deadline_missed = callback; } -void -dds_lset_requested_incompatible_qos (dds_listener_t * __restrict listener, dds_on_requested_incompatible_qos_fn callback) +void dds_lset_requested_incompatible_qos (dds_listener_t * __restrict listener, dds_on_requested_incompatible_qos_fn callback) { - if (listener) { - listener->on_requested_incompatible_qos = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_requested_incompatible_qos = callback; } -void -dds_lset_sample_lost (dds_listener_t * __restrict listener, dds_on_sample_lost_fn callback) +void dds_lset_sample_lost (dds_listener_t * __restrict listener, dds_on_sample_lost_fn callback) { - if (listener) { - listener->on_sample_lost = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_sample_lost = callback; } -void -dds_lset_sample_rejected (dds_listener_t * __restrict listener, dds_on_sample_rejected_fn callback) +void dds_lset_sample_rejected (dds_listener_t * __restrict listener, dds_on_sample_rejected_fn callback) { - if (listener) { - listener->on_sample_rejected = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_sample_rejected = callback; } -void -dds_lset_subscription_matched (dds_listener_t * __restrict listener, dds_on_subscription_matched_fn callback) +void dds_lset_subscription_matched (dds_listener_t * __restrict listener, dds_on_subscription_matched_fn callback) { - if (listener) { - listener->on_subscription_matched = callback; - } else { - DDS_ERROR("Argument listener is NULL\n"); - } + if (listener) + listener->on_subscription_matched = callback; } /************************************************************************************************ * Getters ************************************************************************************************/ -void -dds_lget_data_available (const dds_listener_t * __restrict listener, dds_on_data_available_fn *callback) +void dds_lget_data_available (const dds_listener_t * __restrict listener, dds_on_data_available_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_data_available; + if (callback != NULL) + *callback = listener ? listener->on_data_available : 0; } -void -dds_lget_data_on_readers (const dds_listener_t * __restrict listener, dds_on_data_on_readers_fn *callback) +void dds_lget_data_on_readers (const dds_listener_t * __restrict listener, dds_on_data_on_readers_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_data_on_readers; + if (callback) + *callback = listener ? listener->on_data_on_readers : 0; } void dds_lget_inconsistent_topic (const dds_listener_t * __restrict listener, dds_on_inconsistent_topic_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_inconsistent_topic; + if (callback) + *callback = listener ? listener->on_inconsistent_topic : 0; } -void -dds_lget_liveliness_changed (const dds_listener_t * __restrict listener, dds_on_liveliness_changed_fn *callback) +void dds_lget_liveliness_changed (const dds_listener_t * __restrict listener, dds_on_liveliness_changed_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_liveliness_changed; + if (callback) + *callback = listener ? listener->on_liveliness_changed : 0; } -void -dds_lget_liveliness_lost (const dds_listener_t * __restrict listener, dds_on_liveliness_lost_fn *callback) +void dds_lget_liveliness_lost (const dds_listener_t * __restrict listener, dds_on_liveliness_lost_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_liveliness_lost; + if (callback) + *callback = listener ? listener->on_liveliness_lost : 0; } -void -dds_lget_offered_deadline_missed (const dds_listener_t * __restrict listener, dds_on_offered_deadline_missed_fn *callback) +void dds_lget_offered_deadline_missed (const dds_listener_t * __restrict listener, dds_on_offered_deadline_missed_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_offered_deadline_missed; + if (callback) + *callback = listener ? listener->on_offered_deadline_missed : 0; } -void -dds_lget_offered_incompatible_qos (const dds_listener_t * __restrict listener, dds_on_offered_incompatible_qos_fn *callback) +void dds_lget_offered_incompatible_qos (const dds_listener_t * __restrict listener, dds_on_offered_incompatible_qos_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_offered_incompatible_qos; + if (callback) + *callback = listener ? listener->on_offered_incompatible_qos : 0; } -void -dds_lget_publication_matched (const dds_listener_t * __restrict listener, dds_on_publication_matched_fn *callback) +void dds_lget_publication_matched (const dds_listener_t * __restrict listener, dds_on_publication_matched_fn *callback) { - if(!callback){ - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_publication_matched; + if (callback) + *callback = listener ? listener->on_publication_matched : 0; } -void -dds_lget_requested_deadline_missed (const dds_listener_t * __restrict listener, dds_on_requested_deadline_missed_fn *callback) +void dds_lget_requested_deadline_missed (const dds_listener_t * __restrict listener, dds_on_requested_deadline_missed_fn *callback) { - if(!callback) { - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_requested_deadline_missed; + if (callback) + *callback = listener ? listener->on_requested_deadline_missed : 0; } -void -dds_lget_requested_incompatible_qos (const dds_listener_t * __restrict listener, dds_on_requested_incompatible_qos_fn *callback) +void dds_lget_requested_incompatible_qos (const dds_listener_t * __restrict listener, dds_on_requested_incompatible_qos_fn *callback) { - if(!callback) { - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_requested_incompatible_qos; + if (callback) + *callback = listener ? listener->on_requested_incompatible_qos : 0; } -void -dds_lget_sample_lost (const dds_listener_t *__restrict listener, dds_on_sample_lost_fn *callback) +void dds_lget_sample_lost (const dds_listener_t *__restrict listener, dds_on_sample_lost_fn *callback) { - if(!callback) { - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_sample_lost; + if (callback) + *callback = listener ? listener->on_sample_lost : 0; } -void -dds_lget_sample_rejected (const dds_listener_t *__restrict listener, dds_on_sample_rejected_fn *callback) +void dds_lget_sample_rejected (const dds_listener_t *__restrict listener, dds_on_sample_rejected_fn *callback) { - if(!callback) { - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_sample_rejected; + if (callback) + *callback = listener ? listener->on_sample_rejected : 0; } -void -dds_lget_subscription_matched (const dds_listener_t * __restrict listener, dds_on_subscription_matched_fn *callback) +void dds_lget_subscription_matched (const dds_listener_t * __restrict listener, dds_on_subscription_matched_fn *callback) { - if(!callback) { - DDS_ERROR("Argument callback is NULL\n"); - return ; - } - if (!listener) { - DDS_ERROR("Argument listener is NULL\n"); - return ; - } - *callback = listener->on_subscription_matched; + if (callback) + *callback = listener ? listener->on_subscription_matched : 0; } diff --git a/src/core/ddsc/src/dds_matched.c b/src/core/ddsc/src/dds_matched.c new file mode 100644 index 0000000..e1119df --- /dev/null +++ b/src/core/ddsc/src/dds_matched.c @@ -0,0 +1,223 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "dds/version.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_thread.h" +#include "dds/ddsi/q_bswap.h" +#include "dds__writer.h" +#include "dds__reader.h" +#include "dds__topic.h" + +dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_handle_t *rds, size_t nrds) +{ + dds_writer *wr; + dds_return_t rc; + if (rds == NULL && nrds > 0) + return DDS_RETCODE_BAD_PARAMETER; + if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + return rc; + else + { + const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash; + const int32_t nrds_max = (nrds > INT32_MAX) ? INT32_MAX : (int32_t) nrds; + int32_t nrds_act = 0; + ddsrt_avl_iter_t it; + /* FIXME: this ought not be so tightly coupled to the lower layer */ + thread_state_awake (lookup_thread_state (), &wr->m_entity.m_domain->gv); + ddsrt_mutex_lock (&wr->m_wr->e.lock); + for (const struct wr_prd_match *m = ddsrt_avl_iter_first (&wr_readers_treedef, &wr->m_wr->readers, &it); + m != NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct proxy_reader *prd; + if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL) + { + if (nrds_act < nrds_max) + rds[nrds_act] = prd->e.iid; + nrds_act++; + } + } + for (const struct wr_rd_match *m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->m_wr->local_readers, &it); + m != NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct reader *rd; + if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL) + { + if (nrds_act < nrds_max) + rds[nrds_act] = rd->e.iid; + nrds_act++; + } + } + ddsrt_mutex_unlock (&wr->m_wr->e.lock); + thread_state_asleep (lookup_thread_state ()); + dds_writer_unlock (wr); + return nrds_act; + } +} + +dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_handle_t *wrs, size_t nwrs) +{ + dds_reader *rd; + dds_return_t rc; + if (wrs == NULL && nwrs > 0) + return DDS_RETCODE_BAD_PARAMETER; + if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) + return rc; + else + { + const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash; + const int32_t nwrs_max = (nwrs > INT32_MAX) ? INT32_MAX : (int32_t) nwrs; + int32_t nwrs_act = 0; + ddsrt_avl_iter_t it; + /* FIXME: this ought not be so tightly coupled to the lower layer */ + thread_state_awake (lookup_thread_state (), &rd->m_entity.m_domain->gv); + ddsrt_mutex_lock (&rd->m_rd->e.lock); + for (const struct rd_pwr_match *m = ddsrt_avl_iter_first (&rd_writers_treedef, &rd->m_rd->writers, &it); + m != NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct proxy_writer *pwr; + if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL) + { + if (nwrs_act < nwrs_max) + wrs[nwrs_act] = pwr->e.iid; + nwrs_act++; + } + } + for (const struct rd_wr_match *m = ddsrt_avl_iter_first (&rd_local_writers_treedef, &rd->m_rd->local_writers, &it); + m != NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct writer *wr; + if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL) + { + if (nwrs_act < nwrs_max) + wrs[nwrs_act] = wr->e.iid; + nwrs_act++; + } + } + ddsrt_mutex_unlock (&rd->m_rd->e.lock); + thread_state_asleep (lookup_thread_state ()); + dds_reader_unlock (rd); + return nwrs_act; + } +} + +static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const nn_guid_t *guid, const nn_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos) +{ + dds_builtintopic_endpoint_t *ep; + nn_guid_t tmp; + ep = dds_alloc (sizeof (*ep)); + tmp = nn_hton_guid (*guid); + memcpy (&ep->key, &tmp, sizeof (ep->key)); + ep->participant_instance_handle = ppiid; + tmp = nn_hton_guid (*ppguid); + memcpy (&ep->participant_key, &tmp, sizeof (ep->participant_key)); + ep->qos = dds_create_qos (); + nn_xqos_mergein_missing (ep->qos, qos, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); + ep->topic_name = dds_string_dup (qos->topic_name); + ep->type_name = dds_string_dup (qos->type_name); + return ep; +} + +dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t writer, dds_instance_handle_t ih) +{ + dds_writer *wr; + dds_return_t rc; + if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + return NULL; + else + { + const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash; + dds_builtintopic_endpoint_t *ret = NULL; + ddsrt_avl_iter_t it; + /* FIXME: this ought not be so tightly coupled to the lower layer, and not be so inefficient besides */ + thread_state_awake (lookup_thread_state (), &wr->m_entity.m_domain->gv); + ddsrt_mutex_lock (&wr->m_wr->e.lock); + for (const struct wr_prd_match *m = ddsrt_avl_iter_first (&wr_readers_treedef, &wr->m_wr->readers, &it); + m != NULL && ret == NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct proxy_reader *prd; + if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL) + { + if (prd->e.iid == ih) + ret = make_builtintopic_endpoint (&prd->e.guid, &prd->c.proxypp->e.guid, prd->c.proxypp->e.iid, prd->c.xqos); + } + } + for (const struct wr_rd_match *m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->m_wr->local_readers, &it); + m != NULL && ret == NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct reader *rd; + if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL) + { + if (rd->e.iid == ih) + ret = make_builtintopic_endpoint (&rd->e.guid, &rd->c.pp->e.guid, rd->c.pp->e.iid, rd->xqos); + } + } + ddsrt_mutex_unlock (&wr->m_wr->e.lock); + thread_state_asleep (lookup_thread_state ()); + dds_writer_unlock (wr); + return ret; + } +} + +dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t reader, dds_instance_handle_t ih) +{ + dds_reader *rd; + dds_return_t rc; + if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) + return NULL; + else + { + const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash; + dds_builtintopic_endpoint_t *ret = NULL; + ddsrt_avl_iter_t it; + /* FIXME: this ought not be so tightly coupled to the lower layer, and not be so inefficient besides */ + thread_state_awake (lookup_thread_state (), &rd->m_entity.m_domain->gv); + ddsrt_mutex_lock (&rd->m_rd->e.lock); + for (const struct rd_pwr_match *m = ddsrt_avl_iter_first (&rd_writers_treedef, &rd->m_rd->writers, &it); + m != NULL && ret == NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct proxy_writer *pwr; + if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL) + { + if (pwr->e.iid == ih) + ret = make_builtintopic_endpoint (&pwr->e.guid, &pwr->c.proxypp->e.guid, pwr->c.proxypp->e.iid, pwr->c.xqos); + } + } + for (const struct rd_wr_match *m = ddsrt_avl_iter_first (&rd_local_writers_treedef, &rd->m_rd->local_writers, &it); + m != NULL && ret == NULL; + m = ddsrt_avl_iter_next (&it)) + { + struct writer *wr; + if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL) + { + if (wr->e.iid == ih) + ret = make_builtintopic_endpoint (&wr->e.guid, &wr->c.pp->e.guid, wr->c.pp->e.iid, wr->xqos); + } + } + ddsrt_mutex_unlock (&rd->m_rd->e.lock); + thread_state_asleep (lookup_thread_state ()); + dds_reader_unlock (rd); + return ret; + } +} diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c index a0c3c03..046488d 100644 --- a/src/core/ddsc/src/dds_participant.c +++ b/src/core/ddsc/src/dds_participant.c @@ -15,267 +15,165 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/q_globals.h" #include "dds__init.h" -#include "dds__qos.h" #include "dds__domain.h" #include "dds__participant.h" -#include "dds__err.h" #include "dds__builtin.h" +#include "dds__qos.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_participant) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_participant) -#define DDS_PARTICIPANT_STATUS_MASK 0u +#define DDS_PARTICIPANT_STATUS_MASK (0u) -/* List of created participants */ - -static dds_entity * dds_pp_head = NULL; - -static dds_return_t -dds_participant_status_validate( - uint32_t mask) +static dds_return_t dds_participant_status_validate (uint32_t mask) { - dds_return_t ret = DDS_RETCODE_OK; - - if (mask & ~(DDS_PARTICIPANT_STATUS_MASK)) { - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - - return ret; + return (mask & ~DDS_PARTICIPANT_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } -static dds_return_t -dds_participant_delete( - dds_entity *e) +static dds_return_t dds_participant_delete (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_participant_delete (dds_entity *e) { - dds_entity *prev = NULL; - dds_entity *iter; + dds_return_t ret; + assert (dds_entity_kind (e) == DDS_KIND_PARTICIPANT); - assert(e); - assert(dds_entity_kind(e) == DDS_KIND_PARTICIPANT); + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + if ((ret = delete_participant (&e->m_domain->gv, &e->m_guid)) < 0) + DDS_CERROR (&e->m_domain->gv.logconfig, "dds_participant_delete: internal error %"PRId32"\n", ret); + ddsrt_mutex_lock (&dds_global.m_mutex); + ddsrt_avl_delete (&dds_entity_children_td, &e->m_domain->m_ppants, e); + ddsrt_mutex_unlock (&dds_global.m_mutex); + thread_state_asleep (lookup_thread_state ()); - thread_state_awake (lookup_thread_state ()); + /* Every dds_init needs a dds_fini. */ + dds_domain_free (e->m_domain); + dds_fini (); + return DDS_RETCODE_OK; +} - dds_domain_free (e->m_domain); +static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) +{ + /* note: e->m_qos is still the old one to allow for failure here */ + if (enabled) + { + struct participant *pp; + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + if ((pp = ephash_lookup_participant_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL) + { + nn_plist_t plist; + nn_plist_init_empty (&plist); + plist.qos.present = plist.qos.aliased = qos->present; + plist.qos = *qos; + update_participant_plist (pp, &plist); + } + thread_state_asleep (lookup_thread_state ()); + } + return DDS_RETCODE_OK; +} +const struct dds_entity_deriver dds_entity_deriver_participant = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_participant_delete, + .set_qos = dds_participant_qos_set, + .validate_status = dds_participant_status_validate +}; + +dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_t *qos, const dds_listener_t *listener) +{ + dds_domain *dom; + dds_entity_t ret; + nn_guid_t guid; + dds_participant * pp; + nn_plist_t plist; + dds_qos_t *new_qos = NULL; + + /* Make sure DDS instance is initialized. */ + if ((ret = dds_init ()) < 0) + goto err_dds_init; + + if ((ret = dds_domain_create (&dom, domain)) < 0) + goto err_domain_create; + + new_qos = dds_create_qos (); + if (qos != NULL) + nn_xqos_mergein_missing (new_qos, qos, DDS_PARTICIPANT_QOS_MASK); + nn_xqos_mergein_missing (new_qos, &dom->gv.default_local_plist_pp.qos, ~(uint64_t)0); + if ((ret = nn_xqos_valid (&dom->gv.logconfig, new_qos)) < 0) + goto err_qos_validation; + + /* Translate qos */ + nn_plist_init_empty (&plist); + dds_merge_qos (&plist.qos, new_qos); + + thread_state_awake (lookup_thread_state (), &dom->gv); + ret = new_participant (&guid, &dom->gv, 0, &plist); + thread_state_asleep (lookup_thread_state ()); + nn_plist_fini (&plist); + if (ret < 0) + { + ret = DDS_RETCODE_ERROR; + goto err_new_participant; + } + + pp = dds_alloc (sizeof (*pp)); + if ((ret = dds_entity_init (&pp->m_entity, NULL, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0) + goto err_entity_init; + + pp->m_entity.m_guid = guid; + pp->m_entity.m_iid = get_entity_instance_id (&dom->gv, &guid); + pp->m_entity.m_domain = dom; + pp->m_builtin_subscriber = 0; + + /* Add participant to extent */ + ddsrt_mutex_lock (&dds_global.m_mutex); + ddsrt_avl_insert (&dds_entity_children_td, &dom->m_ppants, &pp->m_entity); + ddsrt_mutex_unlock (&dds_global.m_mutex); + return ret; + +err_entity_init: + dds_free (pp); +err_new_participant: +err_qos_validation: + dds_delete_qos (new_qos); + dds_domain_free (dom); +err_domain_create: + dds_fini (); +err_dds_init: + return ret; +} + +dds_entity_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size) +{ + if ((participants != NULL && (size <= 0 || size >= INT32_MAX)) || (participants == NULL && size != 0)) + return DDS_RETCODE_BAD_PARAMETER; + + ddsrt_init (); + ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex (); + + if (participants) + participants[0] = 0; + + dds_return_t ret = 0; + ddsrt_mutex_lock (init_mutex); + if (dds_global.m_init_count > 0) + { + struct dds_domain *dom; ddsrt_mutex_lock (&dds_global.m_mutex); - iter = dds_pp_head; - while (iter) { - if (iter == e) { - if (prev) { - prev->m_next = iter->m_next; - } else { - dds_pp_head = iter->m_next; - } - break; - } - prev = iter; - iter = iter->m_next; + if ((dom = dds_domain_find_locked (domain_id)) != NULL) + { + ddsrt_avl_iter_t it; + for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_ppants, &it); e != NULL; e = ddsrt_avl_iter_next (&it)) + { + if ((size_t) ret < size) + participants[ret] = e->m_hdllink.hdl; + ret++; + } } ddsrt_mutex_unlock (&dds_global.m_mutex); - - assert (iter); - - thread_state_asleep (lookup_thread_state ()); - - /* Every dds_init needs a dds_fini. */ - dds_fini(); - - return DDS_RETCODE_OK; -} - -static dds_return_t -dds_participant_instance_hdl( - dds_entity *e, - dds_instance_handle_t *i) -{ - assert(e); - assert(i); - *i = (dds_instance_handle_t)participant_instance_id(&e->m_guid); - return DDS_RETCODE_OK; -} - -static dds_return_t -dds_participant_qos_validate( - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = DDS_RETCODE_OK; - assert(qos); - (void)enabled; - - /* Check consistency. */ - if ((qos->present & QP_USER_DATA) && !validate_octetseq(&qos->user_data)) { - DDS_ERROR("User data QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy(&qos->entity_factory)) { - DDS_ERROR("Prismtech entity factory QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - return ret; -} - - -static dds_return_t -dds_participant_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = dds_participant_qos_validate(qos, enabled); - (void)e; - if (ret == DDS_RETCODE_OK) { - if (enabled) { - /* TODO: CHAM-95: DDSI does not support changing QoS policies. */ - DDS_ERROR("Changing the participant QoS is not supported\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); - } - } - return ret; -} - -dds_entity_t -dds_create_participant( - const dds_domainid_t domain, - const dds_qos_t *qos, - const dds_listener_t *listener) -{ - int q_rc; - dds_return_t ret; - dds_entity_t e; - nn_guid_t guid; - dds_participant * pp; - nn_plist_t plist; - dds_qos_t * new_qos = NULL; - - /* Make sure DDS instance is initialized. */ - ret = dds_init(domain); - if (ret != DDS_RETCODE_OK) { - e = (dds_entity_t)ret; - goto fail_dds_init; - } - - /* Check domain id */ - ret = dds__check_domain (domain); - if (ret != DDS_RETCODE_OK) { - e = (dds_entity_t)ret; - goto fail_domain_check; - } - - /* Validate qos */ - if (qos) { - ret = dds_participant_qos_validate (qos, false); - if (ret != DDS_RETCODE_OK) { - e = (dds_entity_t)ret; - goto fail_qos_validation; - } - new_qos = dds_create_qos (); - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(new_qos, qos); - } else { - /* Use default qos. */ - new_qos = dds_create_qos (); - } - - /* Translate qos */ - nn_plist_init_empty(&plist); - dds_merge_qos (&plist.qos, new_qos); - - thread_state_awake (lookup_thread_state ()); - q_rc = new_participant (&guid, 0, &plist); - thread_state_asleep (lookup_thread_state ()); - nn_plist_fini (&plist); - if (q_rc != 0) { - DDS_ERROR("Internal error"); - e = DDS_ERRNO(DDS_RETCODE_ERROR); - goto fail_new_participant; - } - - pp = dds_alloc (sizeof (*pp)); - e = dds_entity_init (&pp->m_entity, NULL, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK); - if (e < 0) { - goto fail_entity_init; - } - - pp->m_entity.m_guid = guid; - pp->m_entity.m_domain = dds_domain_create (dds_domain_default()); - pp->m_entity.m_domainid = dds_domain_default(); - pp->m_entity.m_deriver.delete = dds_participant_delete; - pp->m_entity.m_deriver.set_qos = dds_participant_qos_set; - pp->m_entity.m_deriver.get_instance_hdl = dds_participant_instance_hdl; - pp->m_entity.m_deriver.validate_status = dds_participant_status_validate; - pp->m_builtin_subscriber = 0; - - /* Add participant to extent */ - ddsrt_mutex_lock (&dds_global.m_mutex); - pp->m_entity.m_next = dds_pp_head; - dds_pp_head = &pp->m_entity; - ddsrt_mutex_unlock (&dds_global.m_mutex); - - return e; - -fail_entity_init: - dds_free(pp); -fail_new_participant: - dds_delete_qos(new_qos); -fail_qos_validation: -fail_domain_check: - dds_fini(); -fail_dds_init: - return e; -} - -dds_entity_t -dds_lookup_participant( - dds_domainid_t domain_id, - dds_entity_t *participants, - size_t size) -{ - dds_return_t ret = 0; - ddsrt_mutex_t *init_mutex; - - /* Be sure the DDS lifecycle resources are initialized. */ - ddsrt_init(); - init_mutex = ddsrt_get_singleton_mutex(); - - if ((participants != NULL) && ((size <= 0) || (size >= INT32_MAX))) { - DDS_ERROR("Array is given, but with invalid size\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - if ((participants == NULL) && (size != 0)) { - DDS_ERROR("Size is given, but no array\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto err; - } - - if(participants){ - participants[0] = 0; - } - - ddsrt_mutex_lock (init_mutex); - - /* Check if dds is intialized. */ - if (dds_global.m_init_count > 0) { - dds_entity* iter; - ddsrt_mutex_lock (&dds_global.m_mutex); - iter = dds_pp_head; - while (iter) { - if (iter->m_domainid == domain_id) { - if ((size_t)ret < size) { - participants[ret] = iter->m_hdllink.hdl; - } - ret++; - } - iter = iter->m_next; - } - ddsrt_mutex_unlock (&dds_global.m_mutex); - } - - ddsrt_mutex_unlock (init_mutex); - -err: - ddsrt_fini(); - return ret; + } + ddsrt_mutex_unlock (init_mutex); + ddsrt_fini (); + return ret; } diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index 47365c7..b06306c 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -13,179 +13,90 @@ #include #include "dds/ddsrt/misc.h" #include "dds__listener.h" +#include "dds__participant.h" #include "dds__publisher.h" #include "dds__qos.h" -#include "dds__err.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_globals.h" #include "dds/version.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_publisher) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_publisher) -#define DDS_PUBLISHER_STATUS_MASK 0u +#define DDS_PUBLISHER_STATUS_MASK (0u) -static dds_return_t -dds_publisher_instance_hdl( - dds_entity *e, - dds_instance_handle_t *i) +static dds_return_t dds_publisher_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) { - (void)e; - (void)i; - /* TODO: Get/generate proper handle. */ - DDS_ERROR("Getting publisher instance handle is not supported\n"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); -} - -static dds_return_t -dds_publisher_qos_validate( - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = DDS_RETCODE_OK; - assert(qos); - - /* Check consistency. */ - if((qos->present & QP_GROUP_DATA) && !validate_octetseq(&qos->group_data)){ - DDS_ERROR("Group data policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PRESENTATION) && (validate_presentation_qospolicy(&qos->presentation) != 0)){ - DDS_ERROR("Presentation policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PARTITION) && !validate_stringseq(&qos->partition)){ - DDS_ERROR("Partition policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy(&qos->entity_factory)){ - DDS_ERROR("Prismtech entity factory policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if(ret == DDS_RETCODE_OK && enabled && (qos->present & QP_PRESENTATION)){ - /* TODO: Improve/check immutable check. */ - DDS_ERROR("Presentation policy is immutable\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - return ret; -} - -static dds_return_t -dds_publisher_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = dds_publisher_qos_validate(qos, enabled); - (void)e; - if (ret == DDS_RETCODE_OK) { - if (enabled) { - /* TODO: CHAM-95: DDSI does not support changing QoS policies. */ - DDS_ERROR(DDS_PROJECT_NAME" does not support changing QoS policies yet\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); - } - } - return ret; + /* note: e->m_qos is still the old one to allow for failure here */ + (void) e; (void) qos; (void) enabled; + return DDS_RETCODE_OK; } static dds_return_t dds_publisher_status_validate (uint32_t mask) { - dds_return_t ret = DDS_RETCODE_OK; + return (mask & ~DDS_PUBLISHER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; +} - if (mask & ~(DDS_PUBLISHER_STATUS_MASK)) { - DDS_ERROR("Invalid status mask\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } +const struct dds_entity_deriver dds_entity_deriver_publisher = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_entity_deriver_dummy_delete, + .set_qos = dds_publisher_qos_set, + .validate_status = dds_publisher_status_validate +}; +dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener) +{ + dds_participant *par; + dds_publisher *pub; + dds_entity_t hdl; + dds_qos_t *new_qos; + dds_return_t ret; + + if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) return ret; + + new_qos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (new_qos, qos, DDS_PUBLISHER_QOS_MASK); + nn_xqos_mergein_missing (new_qos, &par->m_entity.m_domain->gv.default_xqos_pub, ~(uint64_t)0); + if ((ret = nn_xqos_valid (&par->m_entity.m_domain->gv.logconfig, new_qos)) != DDS_RETCODE_OK) + { + dds_participant_unlock (par); + return ret; + } + + pub = dds_alloc (sizeof (*pub)); + hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK); + pub->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&par->m_entity, &pub->m_entity); + dds_participant_unlock (par); + return hdl; } -dds_entity_t -dds_create_publisher( - dds_entity_t participant, - const dds_qos_t *qos, - const dds_listener_t *listener) -{ - dds_entity * par; - dds_publisher * pub; - dds_entity_t hdl; - dds_qos_t * new_qos = NULL; - dds_return_t ret; - dds_retcode_t rc; - - rc = dds_entity_lock(participant, DDS_KIND_PARTICIPANT, &par); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking participant\n"); - hdl = DDS_ERRNO(rc); - goto lock_err; - } - - /* Validate qos */ - if (qos) { - ret = dds_publisher_qos_validate(qos, false); - if (ret != DDS_RETCODE_OK) { - hdl = ret; - goto qos_err; - } - new_qos = dds_create_qos (); - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(new_qos, qos); - } - - /* Create publisher */ - pub = dds_alloc (sizeof (*pub)); - hdl = dds_entity_init (&pub->m_entity, par, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK); - pub->m_entity.m_deriver.set_qos = dds_publisher_qos_set; - pub->m_entity.m_deriver.get_instance_hdl = dds_publisher_instance_hdl; - pub->m_entity.m_deriver.validate_status = dds_publisher_status_validate; - -qos_err: - dds_entity_unlock(par); -lock_err: - return hdl; -} - -DDS_EXPORT dds_return_t -dds_suspend( - dds_entity_t publisher) +dds_return_t dds_suspend (dds_entity_t publisher) { return dds_generic_unimplemented_operation (publisher, DDS_KIND_PUBLISHER); } -dds_return_t -dds_resume( - dds_entity_t publisher) +dds_return_t dds_resume (dds_entity_t publisher) { return dds_generic_unimplemented_operation (publisher, DDS_KIND_PUBLISHER); } -dds_return_t -dds_wait_for_acks( - dds_entity_t publisher_or_writer, - dds_duration_t timeout) +dds_return_t dds_wait_for_acks (dds_entity_t publisher_or_writer, dds_duration_t timeout) { if (timeout < 0) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; static const dds_entity_kind_t kinds[] = { DDS_KIND_WRITER, DDS_KIND_PUBLISHER }; return dds_generic_unimplemented_operation_manykinds (publisher_or_writer, sizeof (kinds) / sizeof (kinds[0]), kinds); } -dds_return_t -dds_publisher_begin_coherent( - dds_entity_t e) +dds_return_t dds_publisher_begin_coherent (dds_entity_t publisher) { - /* TODO: CHAM-124 Currently unsupported. */ - (void)e; - DDS_ERROR("Using coherency to get a coherent data set is not being supported yet\n"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); + return dds_generic_unimplemented_operation (publisher, DDS_KIND_PUBLISHER); } -dds_return_t -dds_publisher_end_coherent( - dds_entity_t e) +dds_return_t dds_publisher_end_coherent (dds_entity_t publisher) { - /* TODO: CHAM-124 Currently unsupported. */ - (void)e; - DDS_ERROR("Using coherency to get a coherent data set is not being supported yet\n"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); + return dds_generic_unimplemented_operation (publisher, DDS_KIND_PUBLISHER); } - diff --git a/src/core/ddsc/src/dds_qos.c b/src/core/ddsc/src/dds_qos.c index b53d046..68f12e6 100644 --- a/src/core/ddsc/src/dds_qos.c +++ b/src/core/ddsc/src/dds_qos.c @@ -11,553 +11,257 @@ */ #include #include -#include "dds__qos.h" -#include "dds__err.h" -#include "dds/ddsi/q_config.h" +#include +#include "dds/dds.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/q_plist.h" -/* TODO: dd_duration_t is converted to nn_ddsi_time_t declared in q_time.h - This structure contain seconds and fractions. - Revisit on the conversion as default values are { 0x7fffffff, 0xffffffff } -*/ - -static void -dds_qos_data_copy_in( - nn_octetseq_t * data, - const void * __restrict value, - size_t sz) +static void dds_qos_data_copy_in (ddsi_octetseq_t *data, const void * __restrict value, size_t sz, bool overwrite) { - if (data->value) { - dds_free (data->value); - data->value = NULL; - } - data->length = (uint32_t) sz; - if (sz && value) { - data->value = dds_alloc (sz); - memcpy (data->value, value, sz); - } + if (overwrite && data->value) + ddsrt_free (data->value); + data->length = (uint32_t) sz; + data->value = value ? ddsrt_memdup (value, sz) : NULL; } -static bool -dds_qos_data_copy_out( - const nn_octetseq_t * data, - void ** value, - size_t * sz) +static bool dds_qos_data_copy_out (const ddsi_octetseq_t *data, void **value, size_t *sz) { - assert (data->length < UINT32_MAX); - if (sz == NULL && value != NULL) { - return false; - } - if (sz) { - *sz = data->length; - } - if (value) { - if (data->length != 0) { - assert (data->value); - *value = dds_alloc (data->length + 1); - memcpy (*value, data->value, data->length); - ((char *) (*value))[data->length] = 0; - } else { - *value = NULL; - } + assert (data->length < UINT32_MAX); + if (sz == NULL && value != NULL) + return false; + + if (sz) + *sz = data->length; + if (value) + { + if (data->length == 0) + *value = NULL; + else + { + assert (data->value); + *value = dds_alloc (data->length + 1); + memcpy (*value, data->value, data->length); + ((char *) (*value))[data->length] = 0; } + } + return true; +} + +dds_qos_t *dds_create_qos (void) +{ + dds_qos_t *qos = ddsrt_malloc (sizeof (dds_qos_t)); + nn_xqos_init_empty (qos); + return qos; +} + +dds_qos_t *dds_qos_create (void) +{ + return dds_create_qos (); +} + +void dds_reset_qos (dds_qos_t * __restrict qos) +{ + if (qos) + { + nn_xqos_fini (qos); + nn_xqos_init_empty (qos); + } +} + +void dds_qos_reset (dds_qos_t * __restrict qos) +{ + dds_reset_qos (qos); +} + +void dds_delete_qos (dds_qos_t * __restrict qos) +{ + if (qos) + { + nn_xqos_fini (qos); + ddsrt_free (qos); + } +} + +void dds_qos_delete (dds_qos_t * __restrict qos) +{ + dds_delete_qos (qos); +} + +dds_return_t dds_copy_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) +{ + if (src == NULL || dst == NULL) + return DDS_RETCODE_BAD_PARAMETER; + nn_xqos_copy (dst, src); + return DDS_RETCODE_OK; +} + +dds_return_t dds_qos_copy (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) +{ + return dds_copy_qos (dst, src); +} + +void dds_merge_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) +{ + /* Copy qos from source to destination unless already set */ + if (src != NULL && dst != NULL) + nn_xqos_mergein_missing (dst, src, ~(uint64_t)0); +} + +void dds_qos_merge (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) +{ + dds_merge_qos (dst, src); +} + +bool dds_qos_equal (const dds_qos_t * __restrict a, const dds_qos_t * __restrict b) +{ + /* FIXME: a bit of a hack - and I am not so sure I like accepting null pointers here anyway */ + if (a == NULL && b == NULL) return true; + else if (a == NULL || b == NULL) + return false; + else + return nn_xqos_delta (a, b, ~(uint64_t)0) == 0; } -bool -validate_octetseq( - const nn_octetseq_t* seq) +void dds_qset_userdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - /* default value is NULL with length 0 */ - return (((seq->length == 0) && (seq->value == NULL)) || (seq->length > 0 && seq->length < UINT32_MAX)); + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->user_data, value, sz, qos->present & QP_USER_DATA); + qos->present |= QP_USER_DATA; } -bool -validate_stringseq( - const nn_stringseq_t* seq) +void dds_qset_topicdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - if (seq->n != 0) { - unsigned i; - for (i = 0; i < seq->n; i++) { - if (!seq->strs[i]) { - break; - } - } - return (seq->n == i); - } else { - return (seq->strs == NULL); - } + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->topic_data, value, sz, qos->present & QP_TOPIC_DATA); + qos->present |= QP_TOPIC_DATA; } -bool -validate_entityfactory_qospolicy( - const nn_entity_factory_qospolicy_t * entityfactory) +void dds_qset_groupdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - /* Bools must be 0 or 1, i.e., only the lsb may be set */ - return !(entityfactory->autoenable_created_entities & ~1); + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->group_data, value, sz, qos->present & QP_GROUP_DATA); + qos->present |= QP_GROUP_DATA; } -bool -validate_reliability_qospolicy( - const nn_reliability_qospolicy_t * reliability) +void dds_qset_durability (dds_qos_t * __restrict qos, dds_durability_kind_t kind) { - return ( - (reliability->kind == NN_BEST_EFFORT_RELIABILITY_QOS || reliability->kind == NN_RELIABLE_RELIABILITY_QOS) && - (validate_duration(&reliability->max_blocking_time) == 0) - ); + if (qos == NULL) + return; + qos->durability.kind = kind; + qos->present |= QP_DURABILITY; } -bool -validate_deadline_and_timebased_filter( - const nn_duration_t deadline, - const nn_duration_t minimum_separation) +void dds_qset_history (dds_qos_t * __restrict qos, dds_history_kind_t kind, int32_t depth) { - return ( - (validate_duration(&deadline) == 0) && - (validate_duration(&minimum_separation) == 0) && - (nn_from_ddsi_duration(minimum_separation) <= nn_from_ddsi_duration(deadline)) - ); + if (qos == NULL) + return; + qos->history.kind = kind; + qos->history.depth = depth; + qos->present |= QP_HISTORY; } -bool -dds_qos_validate_common ( - const dds_qos_t *qos) +void dds_qset_resource_limits (dds_qos_t * __restrict qos, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance) { - return !( - ((qos->present & QP_DURABILITY) && (validate_durability_qospolicy (&qos->durability) != 0)) || - ((qos->present & QP_DEADLINE) && (validate_duration (&qos->deadline.deadline) != 0)) || - ((qos->present & QP_LATENCY_BUDGET) && (validate_duration (&qos->latency_budget.duration) != 0)) || - ((qos->present & QP_OWNERSHIP) && (validate_ownership_qospolicy (&qos->ownership) != 0)) || - ((qos->present & QP_LIVELINESS) && (validate_liveliness_qospolicy (&qos->liveliness) != 0)) || - ((qos->present & QP_RELIABILITY) && ! validate_reliability_qospolicy (&qos->reliability)) || - ((qos->present & QP_DESTINATION_ORDER) && (validate_destination_order_qospolicy (&qos->destination_order) != 0)) || - ((qos->present & QP_HISTORY) && (validate_history_qospolicy (&qos->history) != 0)) || - ((qos->present & QP_RESOURCE_LIMITS) && (validate_resource_limits_qospolicy (&qos->resource_limits) != 0)) - ); + if (qos == NULL) + return; + qos->resource_limits.max_samples = max_samples; + qos->resource_limits.max_instances = max_instances; + qos->resource_limits.max_samples_per_instance = max_samples_per_instance; + qos->present |= QP_RESOURCE_LIMITS; } -dds_return_t -dds_qos_validate_mutable_common ( - const dds_qos_t *qos) +void dds_qset_presentation (dds_qos_t * __restrict qos, dds_presentation_access_scope_kind_t access_scope, bool coherent_access, bool ordered_access) { - dds_return_t ret = DDS_RETCODE_OK; - - /* TODO: Check whether immutable QoS are changed should actually incorporate change to current QoS */ - if (qos->present & QP_DEADLINE) { - DDS_ERROR("Deadline QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_OWNERSHIP) { - DDS_ERROR("Ownership QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_LIVELINESS) { - DDS_ERROR("Liveliness QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_RELIABILITY) { - DDS_ERROR("Reliability QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_DESTINATION_ORDER) { - DDS_ERROR("Destination order QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_HISTORY) { - DDS_ERROR("History QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - if (qos->present & QP_RESOURCE_LIMITS) { - DDS_ERROR("Resource limits QoS policy caused immutable error\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } - - return ret; + if (qos == NULL) + return; + qos->presentation.access_scope = access_scope; + qos->presentation.coherent_access = coherent_access; + qos->presentation.ordered_access = ordered_access; + qos->present |= QP_PRESENTATION; } -static void -dds_qos_init_defaults ( - dds_qos_t * __restrict qos) +void dds_qset_lifespan (dds_qos_t * __restrict qos, dds_duration_t lifespan) { - assert (qos); - memset (qos, 0, sizeof (*qos)); - qos->durability.kind = (nn_durability_kind_t) DDS_DURABILITY_VOLATILE; - qos->deadline.deadline = nn_to_ddsi_duration (DDS_INFINITY); - qos->durability_service.service_cleanup_delay = nn_to_ddsi_duration (0); - qos->durability_service.history.kind = (nn_history_kind_t) DDS_HISTORY_KEEP_LAST; - qos->durability_service.history.depth = 1; - qos->durability_service.resource_limits.max_samples = DDS_LENGTH_UNLIMITED; - qos->durability_service.resource_limits.max_instances = DDS_LENGTH_UNLIMITED; - qos->durability_service.resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; - qos->presentation.access_scope = (nn_presentation_access_scope_kind_t) DDS_PRESENTATION_INSTANCE; - qos->latency_budget.duration = nn_to_ddsi_duration (0); - qos->ownership.kind = (nn_ownership_kind_t) DDS_OWNERSHIP_SHARED; - qos->liveliness.kind = (nn_liveliness_kind_t) DDS_LIVELINESS_AUTOMATIC; - qos->liveliness.lease_duration = nn_to_ddsi_duration (DDS_INFINITY); - qos->time_based_filter.minimum_separation = nn_to_ddsi_duration (0); - qos->reliability.kind = (nn_reliability_kind_t) DDS_RELIABILITY_BEST_EFFORT; - qos->reliability.max_blocking_time = nn_to_ddsi_duration (DDS_MSECS (100)); - qos->lifespan.duration = nn_to_ddsi_duration (DDS_INFINITY); - qos->destination_order.kind = (nn_destination_order_kind_t) DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP; - qos->history.kind = (nn_history_kind_t) DDS_HISTORY_KEEP_LAST; - qos->history.depth = 1; - qos->resource_limits.max_samples = DDS_LENGTH_UNLIMITED; - qos->resource_limits.max_instances = DDS_LENGTH_UNLIMITED; - qos->resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; - qos->writer_data_lifecycle.autodispose_unregistered_instances = true; - qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = nn_to_ddsi_duration (DDS_INFINITY); - qos->reader_data_lifecycle.autopurge_disposed_samples_delay = nn_to_ddsi_duration (DDS_INFINITY); + if (qos == NULL) + return; + qos->lifespan.duration = lifespan; + qos->present |= QP_LIFESPAN; } -dds_qos_t * dds_create_qos (void) +void dds_qset_deadline (dds_qos_t * __restrict qos, dds_duration_t deadline) { - dds_qos_t *qos = dds_alloc (sizeof (dds_qos_t)); - dds_qos_init_defaults (qos); - return qos; + if (qos == NULL) + return; + qos->deadline.deadline = deadline; + qos->present |= QP_DEADLINE; } -dds_qos_t * dds_qos_create (void) +void dds_qset_latency_budget (dds_qos_t * __restrict qos, dds_duration_t duration) { - return dds_create_qos (); + if (qos == NULL) + return; + qos->latency_budget.duration = duration; + qos->present |= QP_LATENCY_BUDGET; } -void -dds_reset_qos( - dds_qos_t * __restrict qos) +void dds_qset_ownership (dds_qos_t * __restrict qos, dds_ownership_kind_t kind) { - if (qos) { - nn_xqos_fini (qos); - dds_qos_init_defaults (qos); - } else { - DDS_WARNING("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->ownership.kind = kind; + qos->present |= QP_OWNERSHIP; } -void -dds_qos_reset( - dds_qos_t * __restrict qos) +void dds_qset_ownership_strength (dds_qos_t * __restrict qos, int32_t value) { - dds_reset_qos (qos); + if (qos == NULL) + return; + qos->ownership_strength.value = value; + qos->present |= QP_OWNERSHIP_STRENGTH; } -void -dds_delete_qos( - dds_qos_t * __restrict qos) +void dds_qset_liveliness (dds_qos_t * __restrict qos, dds_liveliness_kind_t kind, dds_duration_t lease_duration) { - if (qos) { - dds_reset_qos(qos); - dds_free(qos); - } + if (qos == NULL) + return; + qos->liveliness.kind = kind; + qos->liveliness.lease_duration = lease_duration; + qos->present |= QP_LIVELINESS; } -void -dds_qos_delete( - dds_qos_t * __restrict qos) +void dds_qset_time_based_filter (dds_qos_t * __restrict qos, dds_duration_t minimum_separation) { - dds_delete_qos (qos); + if (qos == NULL) + return; + qos->time_based_filter.minimum_separation = minimum_separation; + qos->present |= QP_TIME_BASED_FILTER; } -dds_return_t -dds_copy_qos ( - dds_qos_t * __restrict dst, - const dds_qos_t * __restrict src) +void dds_qset_partition (dds_qos_t * __restrict qos, uint32_t n, const char ** __restrict ps) { - if(!src){ - DDS_ERROR("Argument source(src) is NULL\n"); - return DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - if(!dst){ - DDS_ERROR("Argument destination(dst) is NULL\n"); - return DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - nn_xqos_copy (dst, src); - return DDS_RETCODE_OK; -} - -dds_return_t -dds_qos_copy ( - dds_qos_t * __restrict dst, - const dds_qos_t * __restrict src) -{ - return dds_copy_qos (dst, src); -} - -void dds_merge_qos ( - dds_qos_t * __restrict dst, - const dds_qos_t * __restrict src) -{ - if(!src){ - DDS_ERROR("Argument source(src) is NULL\n"); - return; - } - if(!dst){ - DDS_ERROR("Argument destination(dst) is NULL\n"); - return; - } - /* Copy qos from source to destination unless already set */ - nn_xqos_mergein_missing (dst, src); -} - -void dds_qos_merge ( - dds_qos_t * __restrict dst, - const dds_qos_t * __restrict src) -{ - dds_merge_qos (dst, src); -} - -bool dds_qos_equal ( - const dds_qos_t * __restrict a, - const dds_qos_t * __restrict b) -{ - /* FIXME: a bit of a hack - and I am not so sure I like accepting null pointers here anyway */ - if (a == NULL && b == NULL) { - return true; - } else if (a == NULL || b == NULL) { - return false; - } else { - return nn_xqos_delta(a, b, ~(uint64_t)0) == 0; - } -} - -void dds_qset_userdata( - dds_qos_t * __restrict qos, - const void * __restrict value, - size_t sz) -{ - if (!qos) { - DDS_ERROR("Argument qos is NULL\n"); - return ; - } - dds_qos_data_copy_in(&qos->user_data, value, sz); - qos->present |= QP_USER_DATA; -} - -void dds_qset_topicdata( - dds_qos_t * __restrict qos, - const void * __restrict value, - size_t sz) -{ - if (!qos) { - DDS_ERROR("Argument qos is NULL\n"); - return ; - } - dds_qos_data_copy_in (&qos->topic_data, value, sz); - qos->present |= QP_TOPIC_DATA; -} - -void dds_qset_groupdata( - dds_qos_t * __restrict qos, - const void * __restrict value, - size_t sz) -{ - if (!qos) { - DDS_ERROR("Argument qos is NULL\n"); - return ; - } - dds_qos_data_copy_in (&qos->group_data, value, sz); - qos->present |= QP_GROUP_DATA; -} - -void dds_qset_durability -( - dds_qos_t * __restrict qos, - dds_durability_kind_t kind -) -{ - if (qos) { - qos->durability.kind = (nn_durability_kind_t) kind; - qos->present |= QP_DURABILITY; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_history -( - dds_qos_t * __restrict qos, - dds_history_kind_t kind, - int32_t depth -) -{ - if (qos) { - qos->history.kind = (nn_history_kind_t) kind; - qos->history.depth = depth; - qos->present |= QP_HISTORY; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_resource_limits -( - dds_qos_t * __restrict qos, - int32_t max_samples, - int32_t max_instances, - int32_t max_samples_per_instance -) -{ - if (qos) { - qos->resource_limits.max_samples = max_samples; - qos->resource_limits.max_instances = max_instances; - qos->resource_limits.max_samples_per_instance = max_samples_per_instance; - qos->present |= QP_RESOURCE_LIMITS; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_presentation -( - dds_qos_t * __restrict qos, - dds_presentation_access_scope_kind_t access_scope, - bool coherent_access, - bool ordered_access -) -{ - if (qos) { - qos->presentation.access_scope = (nn_presentation_access_scope_kind_t) access_scope; - qos->presentation.coherent_access = coherent_access; - qos->presentation.ordered_access = ordered_access; - qos->present |= QP_PRESENTATION; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_lifespan -( - dds_qos_t * __restrict qos, - dds_duration_t lifespan -) -{ - if (qos) { - qos->lifespan.duration = nn_to_ddsi_duration (lifespan); - qos->present |= QP_LIFESPAN; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_deadline -( - dds_qos_t * __restrict qos, - dds_duration_t deadline -) -{ - if (qos) { - qos->deadline.deadline = nn_to_ddsi_duration (deadline); - qos->present |= QP_DEADLINE; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_latency_budget -( - dds_qos_t * __restrict qos, - dds_duration_t duration -) -{ - if (qos) { - qos->latency_budget.duration = nn_to_ddsi_duration (duration); - qos->present |= QP_LATENCY_BUDGET; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_ownership -( - dds_qos_t * __restrict qos, - dds_ownership_kind_t kind -) -{ - if (qos) { - qos->ownership.kind = (nn_ownership_kind_t) kind; - qos->present |= QP_OWNERSHIP; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_ownership_strength -( - dds_qos_t * __restrict qos, - int32_t value -) -{ - if (qos) { - qos->ownership_strength.value = value; - qos->present |= QP_OWNERSHIP_STRENGTH; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_liveliness -( - dds_qos_t * __restrict qos, - dds_liveliness_kind_t kind, - dds_duration_t lease_duration -) -{ - if (qos) { - qos->liveliness.kind = (nn_liveliness_kind_t) kind; - qos->liveliness.lease_duration = nn_to_ddsi_duration (lease_duration); - qos->present |= QP_LIVELINESS; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_time_based_filter -( - dds_qos_t * __restrict qos, - dds_duration_t minimum_separation -) -{ - if (qos) { - qos->time_based_filter.minimum_separation = nn_to_ddsi_duration (minimum_separation); - qos->present |= QP_TIME_BASED_FILTER; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } -} - -void dds_qset_partition -( - dds_qos_t * __restrict qos, - uint32_t n, - const char ** __restrict ps -) -{ - uint32_t i; - - if(!qos) { - DDS_ERROR("Argument qos may not be NULL\n"); - return ; - } - if(n && !ps) { - DDS_ERROR("Argument ps is NULL, but n (%"PRIu32") > 0", n); - return ; - } - - if (qos->partition.strs != NULL){ - for (i = 0; i < qos->partition.n; i++) { - dds_free(qos->partition.strs[i]); - } - dds_free(qos->partition.strs); - qos->partition.strs = NULL; - } - - qos->partition.n = n; - if(n){ - qos->partition.strs = dds_alloc (sizeof (char*) * n); - } - - for (i = 0; i < n; i++) { - qos->partition.strs[i] = dds_string_dup (ps[i]); - } - qos->present |= QP_PARTITION; + if (qos == NULL || (n > 0 && ps == NULL)) + return; + if (qos->present & QP_PARTITION) + { + for (uint32_t i = 0; i < qos->partition.n; i++) + ddsrt_free (qos->partition.strs[i]); + ddsrt_free (qos->partition.strs); + } + qos->partition.n = n; + if (qos->partition.n == 0) + qos->partition.strs = NULL; + else + { + qos->partition.strs = ddsrt_malloc (n * sizeof (*qos->partition.strs)); + for (uint32_t i = 0; i < n; i++) + qos->partition.strs[i] = ddsrt_strdup (ps[i]); + } + qos->present |= QP_PARTITION; } void dds_qset_partition1 (dds_qos_t * __restrict qos, const char * __restrict name) @@ -568,397 +272,296 @@ void dds_qset_partition1 (dds_qos_t * __restrict qos, const char * __restrict na dds_qset_partition (qos, 1, (const char **) &name); } -void dds_qset_reliability -( - dds_qos_t * __restrict qos, - dds_reliability_kind_t kind, - dds_duration_t max_blocking_time -) +void dds_qset_reliability (dds_qos_t * __restrict qos, dds_reliability_kind_t kind, dds_duration_t max_blocking_time) { - if (qos) { - qos->reliability.kind = (nn_reliability_kind_t) kind; - qos->reliability.max_blocking_time = nn_to_ddsi_duration (max_blocking_time); - qos->present |= QP_RELIABILITY; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->reliability.kind = kind; + qos->reliability.max_blocking_time = max_blocking_time; + qos->present |= QP_RELIABILITY; } -void dds_qset_transport_priority -( - dds_qos_t * __restrict qos, - int32_t value -) +void dds_qset_transport_priority (dds_qos_t * __restrict qos, int32_t value) { - if (qos) { - qos->transport_priority.value = value; - qos->present |= QP_TRANSPORT_PRIORITY; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->transport_priority.value = value; + qos->present |= QP_TRANSPORT_PRIORITY; } -void dds_qset_destination_order -( - dds_qos_t * __restrict qos, - dds_destination_order_kind_t kind -) +void dds_qset_destination_order (dds_qos_t * __restrict qos, dds_destination_order_kind_t kind) { - if (qos) { - qos->destination_order.kind = (nn_destination_order_kind_t) kind; - qos->present |= QP_DESTINATION_ORDER; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->destination_order.kind = kind; + qos->present |= QP_DESTINATION_ORDER; } -void dds_qset_writer_data_lifecycle -( - dds_qos_t * __restrict qos, - bool autodispose -) +void dds_qset_writer_data_lifecycle (dds_qos_t * __restrict qos, bool autodispose) { - if(qos) { - qos->writer_data_lifecycle.autodispose_unregistered_instances = autodispose; - qos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->writer_data_lifecycle.autodispose_unregistered_instances = autodispose; + qos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; } -void dds_qset_reader_data_lifecycle -( - dds_qos_t * __restrict qos, - dds_duration_t autopurge_nowriter_samples_delay, - dds_duration_t autopurge_disposed_samples_delay -) +void dds_qset_reader_data_lifecycle (dds_qos_t * __restrict qos, dds_duration_t autopurge_nowriter_samples_delay, dds_duration_t autopurge_disposed_samples_delay) { - if (qos) { - qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = \ - nn_to_ddsi_duration (autopurge_nowriter_samples_delay); - qos->reader_data_lifecycle.autopurge_disposed_samples_delay = \ - nn_to_ddsi_duration (autopurge_disposed_samples_delay); - qos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = autopurge_nowriter_samples_delay; + qos->reader_data_lifecycle.autopurge_disposed_samples_delay = autopurge_disposed_samples_delay; + qos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; } -void dds_qset_durability_service -( - dds_qos_t * __restrict qos, - dds_duration_t service_cleanup_delay, - dds_history_kind_t history_kind, - int32_t history_depth, - int32_t max_samples, - int32_t max_instances, - int32_t max_samples_per_instance -) +void dds_qset_durability_service (dds_qos_t * __restrict qos, dds_duration_t service_cleanup_delay, dds_history_kind_t history_kind, int32_t history_depth, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance) { - if (qos) { - qos->durability_service.service_cleanup_delay = nn_to_ddsi_duration (service_cleanup_delay); - qos->durability_service.history.kind = (nn_history_kind_t) history_kind; - qos->durability_service.history.depth = history_depth; - qos->durability_service.resource_limits.max_samples = max_samples; - qos->durability_service.resource_limits.max_instances = max_instances; - qos->durability_service.resource_limits.max_samples_per_instance = max_samples_per_instance; - qos->present |= QP_DURABILITY_SERVICE; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->durability_service.service_cleanup_delay = service_cleanup_delay; + qos->durability_service.history.kind = history_kind; + qos->durability_service.history.depth = history_depth; + qos->durability_service.resource_limits.max_samples = max_samples; + qos->durability_service.resource_limits.max_instances = max_instances; + qos->durability_service.resource_limits.max_samples_per_instance = max_samples_per_instance; + qos->present |= QP_DURABILITY_SERVICE; } void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore) { - if (qos) { - qos->ignorelocal.value = (nn_ignorelocal_kind_t) ignore; - qos->present |= QP_CYCLONE_IGNORELOCAL; - } else { - DDS_ERROR("Argument QoS is NULL\n"); - } + if (qos == NULL) + return; + qos->ignorelocal.value = ignore; + qos->present |= QP_CYCLONE_IGNORELOCAL; } bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) { - if (!qos || !(qos->present & QP_USER_DATA)) { - return false; - } - return dds_qos_data_copy_out (&qos->user_data, value, sz); + if (qos == NULL || !(qos->present & QP_USER_DATA)) + return false; + return dds_qos_data_copy_out (&qos->user_data, value, sz); } bool dds_qget_topicdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) { - if (!qos || !(qos->present & QP_TOPIC_DATA)) { - return false; - } - return dds_qos_data_copy_out (&qos->topic_data, value, sz); + if (qos == NULL || !(qos->present & QP_TOPIC_DATA)) + return false; + return dds_qos_data_copy_out (&qos->topic_data, value, sz); } bool dds_qget_groupdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) { - if (!qos || !(qos->present & QP_GROUP_DATA)) { - return false; - } - return dds_qos_data_copy_out (&qos->group_data, value, sz); + if (qos == NULL || !(qos->present & QP_GROUP_DATA)) + return false; + return dds_qos_data_copy_out (&qos->group_data, value, sz); } bool dds_qget_durability (const dds_qos_t * __restrict qos, dds_durability_kind_t *kind) { - if (!qos || !(qos->present & QP_DURABILITY)) { - return false; - } - if (kind) { - *kind = (dds_durability_kind_t) qos->durability.kind; - } - return true; + if (qos == NULL || !(qos->present & QP_DURABILITY)) + return false; + if (kind) + *kind = qos->durability.kind; + return true; } bool dds_qget_history (const dds_qos_t * __restrict qos, dds_history_kind_t *kind, int32_t *depth) { - if (!qos || !(qos->present & QP_HISTORY)) { - return false; - } - if (kind) { - *kind = (dds_history_kind_t) qos->history.kind; - } - if (depth) { - *depth = qos->history.depth; - } - return true; + if (qos == NULL || !(qos->present & QP_HISTORY)) + return false; + if (kind) + *kind = qos->history.kind; + if (depth) + *depth = qos->history.depth; + return true; } bool dds_qget_resource_limits (const dds_qos_t * __restrict qos, int32_t *max_samples, int32_t *max_instances, int32_t *max_samples_per_instance) { - if (!qos || !(qos->present & QP_RESOURCE_LIMITS)) { - return false; - } - if (max_samples) { - *max_samples = qos->resource_limits.max_samples; - } - if (max_instances) { - *max_instances = qos->resource_limits.max_instances; - } - if (max_samples_per_instance) { - *max_samples_per_instance = qos->resource_limits.max_samples_per_instance; - } - return true; + if (qos == NULL || !(qos->present & QP_RESOURCE_LIMITS)) + return false; + if (max_samples) + *max_samples = qos->resource_limits.max_samples; + if (max_instances) + *max_instances = qos->resource_limits.max_instances; + if (max_samples_per_instance) + *max_samples_per_instance = qos->resource_limits.max_samples_per_instance; + return true; } bool dds_qget_presentation (const dds_qos_t * __restrict qos, dds_presentation_access_scope_kind_t *access_scope, bool *coherent_access, bool *ordered_access) { - if (!qos || !(qos->present & QP_PRESENTATION)) { - return false; - } - if (access_scope) { - *access_scope = (dds_presentation_access_scope_kind_t) qos->presentation.access_scope; - } - if (coherent_access) { - *coherent_access = qos->presentation.coherent_access; - } - if (ordered_access) { - *ordered_access = qos->presentation.ordered_access; - } - return true; + if (qos == NULL || !(qos->present & QP_PRESENTATION)) + return false; + if (access_scope) + *access_scope = qos->presentation.access_scope; + if (coherent_access) + *coherent_access = qos->presentation.coherent_access; + if (ordered_access) + *ordered_access = qos->presentation.ordered_access; + return true; } bool dds_qget_lifespan (const dds_qos_t * __restrict qos, dds_duration_t *lifespan) { - if (!qos || !(qos->present & QP_LIFESPAN)) { - return false; - } - if (lifespan) { - *lifespan = nn_from_ddsi_duration (qos->lifespan.duration); - } - return true; + if (qos == NULL || !(qos->present & QP_LIFESPAN)) + return false; + if (lifespan) + *lifespan = qos->lifespan.duration; + return true; } bool dds_qget_deadline (const dds_qos_t * __restrict qos, dds_duration_t *deadline) { - if (!qos || !(qos->present & QP_DEADLINE)) { - return false; - } - if (deadline) { - *deadline = nn_from_ddsi_duration (qos->deadline.deadline); - } - return true; + if (qos == NULL || !(qos->present & QP_DEADLINE)) + return false; + if (deadline) + *deadline = qos->deadline.deadline; + return true; } bool dds_qget_latency_budget (const dds_qos_t * __restrict qos, dds_duration_t *duration) { - if (!qos || !(qos->present & QP_LATENCY_BUDGET)) { - return false; - } - if (duration) { - *duration = nn_from_ddsi_duration (qos->latency_budget.duration); - } - return true; + if (qos == NULL || !(qos->present & QP_LATENCY_BUDGET)) + return false; + if (duration) + *duration = qos->latency_budget.duration; + return true; } bool dds_qget_ownership (const dds_qos_t * __restrict qos, dds_ownership_kind_t *kind) { - if (!qos || !(qos->present & QP_OWNERSHIP)) { - return false; - } - if (kind) { - *kind = (dds_ownership_kind_t) qos->ownership.kind; - } - return true; + if (qos == NULL || !(qos->present & QP_OWNERSHIP)) + return false; + if (kind) + *kind = qos->ownership.kind; + return true; } bool dds_qget_ownership_strength (const dds_qos_t * __restrict qos, int32_t *value) { - if (!qos || !(qos->present & QP_OWNERSHIP_STRENGTH)) { - return false; - } - if (value) { - *value = qos->ownership_strength.value; - } - return true; + if (qos == NULL || !(qos->present & QP_OWNERSHIP_STRENGTH)) + return false; + if (value) + *value = qos->ownership_strength.value; + return true; } bool dds_qget_liveliness (const dds_qos_t * __restrict qos, dds_liveliness_kind_t *kind, dds_duration_t *lease_duration) { - if (!qos || !(qos->present & QP_LIVELINESS)) { - return false; - } - if (kind) { - *kind = (dds_liveliness_kind_t) qos->liveliness.kind; - } - if (lease_duration) { - *lease_duration = nn_from_ddsi_duration (qos->liveliness.lease_duration); - } - return true; + if (qos == NULL || !(qos->present & QP_LIVELINESS)) + return false; + if (kind) + *kind = qos->liveliness.kind; + if (lease_duration) + *lease_duration = qos->liveliness.lease_duration; + return true; } bool dds_qget_time_based_filter (const dds_qos_t * __restrict qos, dds_duration_t *minimum_separation) { - if (!qos || !(qos->present & QP_TIME_BASED_FILTER)) { - return false; - } - if (minimum_separation) { - *minimum_separation = nn_from_ddsi_duration (qos->time_based_filter.minimum_separation); - } - return true; + if (qos == NULL || !(qos->present & QP_TIME_BASED_FILTER)) + return false; + if (minimum_separation) + *minimum_separation = qos->time_based_filter.minimum_separation; + return true; } bool dds_qget_partition (const dds_qos_t * __restrict qos, uint32_t *n, char ***ps) { - if (!qos || !(qos->present & QP_PARTITION)) { - return false; + if (qos == NULL || !(qos->present & QP_PARTITION)) + return false; + if (n == NULL && ps != NULL) + return false; + if (n) + *n = qos->partition.n; + if (ps) + { + if (qos->partition.n == 0) + *ps = NULL; + else + { + *ps = dds_alloc (sizeof (char*) * qos->partition.n); + for (uint32_t i = 0; i < qos->partition.n; i++) + (*ps)[i] = dds_string_dup (qos->partition.strs[i]); } - if (n == NULL && ps != NULL) { - return false; - } - if (n) { - *n = qos->partition.n; - } - if (ps) { - if (qos->partition.n != 0) { - *ps = dds_alloc(sizeof(char*) * qos->partition.n); - for (uint32_t i = 0; i < qos->partition.n; i++) { - (*ps)[i] = dds_string_dup(qos->partition.strs[i]); - } - } else { - *ps = NULL; - } - } - return true; + } + return true; } bool dds_qget_reliability (const dds_qos_t * __restrict qos, dds_reliability_kind_t *kind, dds_duration_t *max_blocking_time) { - if (!qos || !(qos->present & QP_RELIABILITY)) { - return false; - } - if (kind) { - *kind = (dds_reliability_kind_t) qos->reliability.kind; - } - if (max_blocking_time) { - *max_blocking_time = nn_from_ddsi_duration (qos->reliability.max_blocking_time); - } - return true; + if (qos == NULL || !(qos->present & QP_RELIABILITY)) + return false; + if (kind) + *kind = qos->reliability.kind; + if (max_blocking_time) + *max_blocking_time = qos->reliability.max_blocking_time; + return true; } bool dds_qget_transport_priority (const dds_qos_t * __restrict qos, int32_t *value) { - if (!qos || !(qos->present & QP_TRANSPORT_PRIORITY)) { - return false; - } - if (value) { - *value = qos->transport_priority.value; - } - return true; + if (qos == NULL || !(qos->present & QP_TRANSPORT_PRIORITY)) + return false; + if (value) + *value = qos->transport_priority.value; + return true; } bool dds_qget_destination_order (const dds_qos_t * __restrict qos, dds_destination_order_kind_t *kind) { - if (!qos || !(qos->present & QP_DESTINATION_ORDER)) { - return false; - } - if (kind) { - *kind = (dds_destination_order_kind_t) qos->destination_order.kind; - } - return true; + if (qos == NULL || !(qos->present & QP_DESTINATION_ORDER)) + return false; + if (kind) + *kind = qos->destination_order.kind; + return true; } bool dds_qget_writer_data_lifecycle (const dds_qos_t * __restrict qos, bool *autodispose) { - if (!qos || !(qos->present & QP_PRISMTECH_WRITER_DATA_LIFECYCLE)) { - return false; - } - if (autodispose) { - *autodispose = qos->writer_data_lifecycle.autodispose_unregistered_instances; - } - return true; + if (qos == NULL || !(qos->present & QP_PRISMTECH_WRITER_DATA_LIFECYCLE)) + return false; + if (autodispose) + *autodispose = qos->writer_data_lifecycle.autodispose_unregistered_instances; + return true; } bool dds_qget_reader_data_lifecycle (const dds_qos_t * __restrict qos, dds_duration_t *autopurge_nowriter_samples_delay, dds_duration_t *autopurge_disposed_samples_delay) { - if (!qos || !(qos->present & QP_PRISMTECH_READER_DATA_LIFECYCLE)) { - return false; - } - if (autopurge_nowriter_samples_delay) { - *autopurge_nowriter_samples_delay = nn_from_ddsi_duration (qos->reader_data_lifecycle.autopurge_nowriter_samples_delay); - } - if (autopurge_disposed_samples_delay) { - *autopurge_disposed_samples_delay = nn_from_ddsi_duration (qos->reader_data_lifecycle.autopurge_disposed_samples_delay); - } - return true; + if (qos == NULL || !(qos->present & QP_PRISMTECH_READER_DATA_LIFECYCLE)) + return false; + if (autopurge_nowriter_samples_delay) + *autopurge_nowriter_samples_delay = qos->reader_data_lifecycle.autopurge_nowriter_samples_delay; + if (autopurge_disposed_samples_delay) + *autopurge_disposed_samples_delay = qos->reader_data_lifecycle.autopurge_disposed_samples_delay; + return true; } bool dds_qget_durability_service (const dds_qos_t * __restrict qos, dds_duration_t *service_cleanup_delay, dds_history_kind_t *history_kind, int32_t *history_depth, int32_t *max_samples, int32_t *max_instances, int32_t *max_samples_per_instance) { - if (!qos || !(qos->present & QP_DURABILITY_SERVICE)) { - return false; - } - if (service_cleanup_delay) { - *service_cleanup_delay = nn_from_ddsi_duration (qos->durability_service.service_cleanup_delay); - } - if (history_kind) { - *history_kind = (dds_history_kind_t) qos->durability_service.history.kind; - } - if (history_depth) { - *history_depth = qos->durability_service.history.depth; - } - if (max_samples) { - *max_samples = qos->durability_service.resource_limits.max_samples; - } - if (max_instances) { - *max_instances = qos->durability_service.resource_limits.max_instances; - } - if (max_samples_per_instance) { - *max_samples_per_instance = qos->durability_service.resource_limits.max_samples_per_instance; - } - return true; + if (qos == NULL || !(qos->present & QP_DURABILITY_SERVICE)) + return false; + if (service_cleanup_delay) + *service_cleanup_delay = qos->durability_service.service_cleanup_delay; + if (history_kind) + *history_kind = qos->durability_service.history.kind; + if (history_depth) + *history_depth = qos->durability_service.history.depth; + if (max_samples) + *max_samples = qos->durability_service.resource_limits.max_samples; + if (max_instances) + *max_instances = qos->durability_service.resource_limits.max_instances; + if (max_samples_per_instance) + *max_samples_per_instance = qos->durability_service.resource_limits.max_samples_per_instance; + return true; } bool dds_qget_ignorelocal (const dds_qos_t * __restrict qos, dds_ignorelocal_kind_t *ignore) { - if (!qos || !(qos->present & QP_CYCLONE_IGNORELOCAL)) { + if (qos == NULL || !(qos->present & QP_CYCLONE_IGNORELOCAL)) return false; - } - if (ignore) { - *ignore = (dds_ignorelocal_kind_t) qos->ignorelocal.value; - } + if (ignore) + *ignore = qos->ignorelocal.value; return true; } diff --git a/src/core/ddsc/src/dds_querycond.c b/src/core/ddsc/src/dds_querycond.c index 0a5e50d..a589ce0 100644 --- a/src/core/ddsc/src/dds_querycond.c +++ b/src/core/ddsc/src/dds_querycond.c @@ -18,36 +18,23 @@ #include "dds__topic.h" #include "dds__querycond.h" #include "dds__readcond.h" -#include "dds__err.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" -DDS_EXPORT dds_entity_t -dds_create_querycondition( - dds_entity_t reader, - uint32_t mask, - dds_querycondition_filter_fn filter) +dds_entity_t dds_create_querycondition (dds_entity_t reader, uint32_t mask, dds_querycondition_filter_fn filter) { + dds_return_t rc; + dds_reader *r; + + if ((rc = dds_reader_lock (reader, &r)) != DDS_RETCODE_OK) + return rc; + else + { dds_entity_t hdl; - dds_retcode_t rc; - dds_reader *r; - - rc = dds_reader_lock(reader, &r); - if (rc == DDS_RETCODE_OK) { - dds_readcond *cond = dds_create_readcond(r, DDS_KIND_COND_QUERY, mask, filter); - assert(cond); - const bool success = (cond->m_entity.m_deriver.delete != 0); - dds_reader_unlock(r); - if (success) { - hdl = cond->m_entity.m_hdllink.hdl; - } else { - dds_delete (cond->m_entity.m_hdllink.hdl); - hdl = DDS_ERRNO(DDS_RETCODE_OUT_OF_RESOURCES); - } - } else { - DDS_ERROR("Error occurred on locking reader\n"); - hdl = DDS_ERRNO(rc); - } - + dds_readcond *cond = dds_create_readcond (r, DDS_KIND_COND_QUERY, mask, filter); + assert (cond); + dds_reader_unlock (r); + hdl = cond->m_entity.m_hdllink.hdl; return hdl; + } } diff --git a/src/core/ddsc/src/dds_read.c b/src/core/ddsc/src/dds_read.c index 2791a44..c8255ca 100644 --- a/src/core/ddsc/src/dds_read.c +++ b/src/core/ddsc/src/dds_read.c @@ -15,60 +15,12 @@ #include "dds__reader.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__rhc.h" -#include "dds__err.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_globals.h" #include "dds/ddsi/ddsi_sertopic.h" -static dds_retcode_t dds_read_lock (dds_entity_t hdl, dds_reader **reader, dds_readcond **condition, bool only_reader) -{ - dds_retcode_t rc; - dds_entity *entity, *parent_entity; - if ((rc = dds_entity_lock (hdl, DDS_KIND_DONTCARE, &entity)) != DDS_RETCODE_OK) - { - return rc; - } - else if (dds_entity_kind (entity) == DDS_KIND_READER) - { - *reader = (dds_reader *) entity; - *condition = NULL; - return DDS_RETCODE_OK; - } - else if (only_reader) - { - dds_entity_unlock (entity); - DDS_ERROR ("Given entity is not a reader\n"); - return DDS_RETCODE_ILLEGAL_OPERATION; - } - else if (dds_entity_kind (entity) != DDS_KIND_COND_READ && dds_entity_kind (entity) != DDS_KIND_COND_QUERY) - { - dds_entity_unlock (entity); - DDS_ERROR ("Given entity is a reader nor a condition\n"); - return DDS_RETCODE_ILLEGAL_OPERATION; - } - else if ((rc = dds_entity_lock (entity->m_parent->m_hdllink.hdl, DDS_KIND_READER, &parent_entity)) != DDS_RETCODE_OK) - { - dds_entity_unlock (entity); - DDS_ERROR ("Failed to lock condition's reader\n"); - return rc; - } - else - { - *reader = (dds_reader *) parent_entity; - *condition = (dds_readcond *) entity; - return DDS_RETCODE_OK; - } -} - -static void dds_read_unlock (dds_reader *reader, dds_readcond *condition) -{ - dds_entity_unlock (&reader->m_entity); - if (condition) - dds_entity_unlock (&condition->m_entity); -} - /* dds_read_impl: Core read/take function. Usually maxs is size of buf and si into which samples/status are written, when set to zero is special case @@ -76,127 +28,135 @@ static void dds_read_unlock (dds_reader *reader, dds_readcond *condition) has been locked. This is used to support C++ API reading length unlimited which is interpreted as "all relevant samples in cache". */ -static dds_return_t -dds_read_impl( - bool take, - dds_entity_t reader_or_condition, - void **buf, - size_t bufsz, - uint32_t maxs, - dds_sample_info_t *si, - uint32_t mask, - dds_instance_handle_t hand, - bool lock, - bool only_reader) -{ - struct thread_state1 * const ts1 = lookup_thread_state (); - dds_return_t ret = DDS_RETCODE_OK; - dds_retcode_t rc; - struct dds_reader * rd; - struct dds_readcond * cond; - - if (buf == NULL) { - DDS_ERROR("The provided buffer is NULL\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if (si == NULL) { - DDS_ERROR("Provided pointer to an array of dds_sample_info_t is NULL\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if (maxs == 0) { - DDS_ERROR("The maximum number of samples to read is zero\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if (bufsz == 0) { - DDS_ERROR("The size of buffer is zero\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if (bufsz < maxs) { - DDS_ERROR("The provided size of buffer is smaller than the maximum number of samples to read\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - - thread_state_awake (ts1); - rc = dds_read_lock(reader_or_condition, &rd, &cond, only_reader); - if (rc != DDS_RETCODE_OK) { - ret = DDS_ERRNO(rc); - goto fail_awake; - } - if (hand != DDS_HANDLE_NIL) { - if (ddsi_tkmap_find_by_id(gv.m_tkmap, hand) == NULL) { - DDS_ERROR("Could not find instance\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - dds_read_unlock(rd, cond); - goto fail_awake; - } - } - /* Allocate samples if not provided (assuming all or none provided) */ - if (buf[0] == NULL) { - /* Allocate, use or reallocate loan cached on reader */ - if (rd->m_loan_out) { - ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs); - } else { - if (rd->m_loan) { - if (rd->m_loan_size < maxs) { - ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, rd->m_loan, rd->m_loan_size, maxs); - rd->m_loan = buf[0]; - rd->m_loan_size = maxs; - } else { - buf[0] = rd->m_loan; - } - } else { - ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs); - rd->m_loan = buf[0]; - rd->m_loan_size = maxs; - } - rd->m_loan_out = true; - } - } - - /* read/take resets data available status -- must reset before reading because - the actual writing is protected by RHC lock, not by rd->m_entity.m_lock */ - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - dds_entity_status_reset (&rd->m_entity, DDS_DATA_AVAILABLE_STATUS); - /* reset DATA_ON_READERS status on subscriber after successful read/take */ - if (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER) { - dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - - if (take) { - ret = (dds_return_t)dds_rhc_take(rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond); - } else { - ret = (dds_return_t)dds_rhc_read(rd->m_rd->rhc, lock, buf, si, maxs, mask, hand, cond); - } - dds_read_unlock(rd, cond); - -fail_awake: - thread_state_asleep (ts1); -fail: - return ret; -} - -static dds_return_t -dds_readcdr_impl( - bool take, - dds_entity_t reader_or_condition, - struct ddsi_serdata ** buf, - uint32_t maxs, - dds_sample_info_t * si, - uint32_t mask, - dds_instance_handle_t hand, - bool lock) +static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, void **buf, size_t bufsz, uint32_t maxs, dds_sample_info_t *si, uint32_t mask, dds_instance_handle_t hand, bool lock, bool only_reader) { struct thread_state1 * const ts1 = lookup_thread_state (); dds_return_t ret = DDS_RETCODE_OK; - dds_retcode_t rc; - struct dds_reader * rd; - struct dds_readcond * cond; + struct dds_entity *entity; + struct dds_reader *rd; + struct dds_readcond *cond; + unsigned nodata_cleanups = 0; +#define NC_CLEAR_LOAN_OUT 1u +#define NC_FREE_BUF 2u +#define NC_RESET_BUF 4u + + if (buf == NULL || si == NULL || maxs == 0 || bufsz == 0 || bufsz < maxs) + return DDS_RETCODE_BAD_PARAMETER; + + if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { + goto fail; + } else if (dds_entity_kind (entity) == DDS_KIND_READER) { + rd = (dds_reader *) entity; + cond = NULL; + } else if (only_reader) { + ret = DDS_RETCODE_ILLEGAL_OPERATION; + goto fail_pinned; + } else if (dds_entity_kind (entity) != DDS_KIND_COND_READ && dds_entity_kind (entity) != DDS_KIND_COND_QUERY) { + ret = DDS_RETCODE_ILLEGAL_OPERATION; + goto fail_pinned; + } else { + rd = (dds_reader *) entity->m_parent; + cond = (dds_readcond *) entity; + } + + thread_state_awake (ts1, &entity->m_domain->gv); + + if (hand != DDS_HANDLE_NIL) + { + if (ddsi_tkmap_find_by_id (entity->m_domain->gv.m_tkmap, hand) == NULL) { + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + goto fail_awake_pinned; + } + } + + /* Allocate samples if not provided (assuming all or none provided) */ + if (buf[0] == NULL) + { + /* Allocate, use or reallocate loan cached on reader */ + ddsrt_mutex_lock (&rd->m_entity.m_mutex); + if (rd->m_loan_out) + { + ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs); + nodata_cleanups = NC_FREE_BUF | NC_RESET_BUF; + } + else + { + if (rd->m_loan) + { + if (rd->m_loan_size >= maxs) + { + /* This ensures buf is properly initialized */ + ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, rd->m_loan, rd->m_loan_size, rd->m_loan_size); + } + else + { + ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, rd->m_loan, rd->m_loan_size, maxs); + rd->m_loan = buf[0]; + rd->m_loan_size = maxs; + } + nodata_cleanups = NC_RESET_BUF; + } + else + { + ddsi_sertopic_realloc_samples (buf, rd->m_topic->m_stopic, NULL, 0, maxs); + rd->m_loan = buf[0]; + rd->m_loan_size = maxs; + } + rd->m_loan_out = true; + nodata_cleanups |= NC_CLEAR_LOAN_OUT; + } + ddsrt_mutex_unlock (&rd->m_entity.m_mutex); + } + + /* read/take resets data available status -- must reset before reading because + the actual writing is protected by RHC lock, not by rd->m_entity.m_lock */ + dds_entity_status_reset (&rd->m_entity, DDS_DATA_AVAILABLE_STATUS); + + /* reset DATA_ON_READERS status on subscriber after successful read/take */ + assert (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER); + dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); + + if (take) + ret = dds_rhc_take (rd->m_rhc, lock, buf, si, maxs, mask, hand, cond); + else + ret = dds_rhc_read (rd->m_rhc, lock, buf, si, maxs, mask, hand, cond); + + /* if no data read, restore the state to what it was before the call, with the sole + exception of holding on to a buffer we just allocated and that is pointed to by + rd->m_loan */ + if (ret <= 0 && nodata_cleanups) + { + ddsrt_mutex_lock (&rd->m_entity.m_mutex); + if (nodata_cleanups & NC_CLEAR_LOAN_OUT) + rd->m_loan_out = false; + if (nodata_cleanups & NC_FREE_BUF) + ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf[0], maxs, DDS_FREE_ALL); + if (nodata_cleanups & NC_RESET_BUF) + buf[0] = NULL; + ddsrt_mutex_unlock (&rd->m_entity.m_mutex); + } + dds_entity_unpin (entity); + thread_state_asleep (ts1); + return ret; + +#undef NC_CLEAR_LOAN_OUT +#undef NC_FREE_BUF +#undef NC_RESET_BUF + +fail_awake_pinned: + thread_state_asleep (ts1); +fail_pinned: + dds_entity_unpin (entity); +fail: + return ret; +} + +static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_condition, struct ddsi_serdata **buf, uint32_t maxs, dds_sample_info_t *si, uint32_t mask, dds_instance_handle_t hand, bool lock) +{ + struct thread_state1 * const ts1 = lookup_thread_state (); + dds_return_t ret = DDS_RETCODE_OK; + struct dds_reader *rd; + struct dds_entity *entity; assert (take); assert (buf); @@ -205,517 +165,330 @@ dds_readcdr_impl( assert (maxs > 0); (void)take; - thread_state_awake (ts1); - rc = dds_read_lock(reader_or_condition, &rd, &cond, false); - if (rc == DDS_RETCODE_OK) { - /* read/take resets data available status -- must reset before reading because - the actual writing is protected by RHC lock, not by rd->m_entity.m_lock */ - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - dds_entity_status_reset (&rd->m_entity, DDS_DATA_AVAILABLE_STATUS); - /* reset DATA_ON_READERS status on subscriber after successful read/take */ - if (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER) { - dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - - ret = dds_rhc_takecdr - ( - rd->m_rd->rhc, lock, buf, si, maxs, - mask & DDS_ANY_SAMPLE_STATE, - mask & DDS_ANY_VIEW_STATE, - mask & DDS_ANY_INSTANCE_STATE, - hand - ); - - dds_read_unlock(rd, cond); + if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { + return ret; + } else if (dds_entity_kind (entity) == DDS_KIND_READER) { + rd = (dds_reader *) entity; + } else if (dds_entity_kind (entity) != DDS_KIND_COND_READ && dds_entity_kind (entity) != DDS_KIND_COND_QUERY) { + dds_entity_unpin (entity); + return DDS_RETCODE_ILLEGAL_OPERATION; } else { - ret = DDS_ERRNO(rc); + rd = (dds_reader *) entity->m_parent; } + thread_state_awake (ts1, &entity->m_domain->gv); + + /* read/take resets data available status -- must reset before reading because + the actual writing is protected by RHC lock, not by rd->m_entity.m_lock */ + dds_entity_status_reset (&rd->m_entity, DDS_DATA_AVAILABLE_STATUS); + + /* reset DATA_ON_READERS status on subscriber after successful read/take */ + assert (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER); + dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); + + ret = dds_rhc_takecdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand); + dds_entity_unpin (entity); thread_state_asleep (ts1); return ret; } -dds_return_t -dds_read( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - size_t bufsz, - uint32_t maxs) +dds_return_t dds_read (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs) { - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs, so use bufsz instead. - * CHAM-306 will remove this ugly piece of code. */ - maxs = (uint32_t)bufsz; - } - return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = (uint32_t) bufsz; + } + return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); } -dds_return_t -dds_read_wl( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - uint32_t maxs) +dds_return_t dds_read_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs) { - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); } -dds_return_t -dds_read_mask( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - size_t bufsz, - uint32_t maxs, - uint32_t mask) +dds_return_t dds_read_mask (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, uint32_t mask) { - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs, so use bufsz instead. - * CHAM-306 will remove this ugly piece of code. */ - maxs = (uint32_t)bufsz; - } - return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, mask, DDS_HANDLE_NIL, lock, false); + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = (uint32_t)bufsz; + } + return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, mask, DDS_HANDLE_NIL, lock, false); } -dds_return_t -dds_read_mask_wl( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - uint32_t maxs, - uint32_t mask) +dds_return_t dds_read_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, uint32_t mask) { - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); } -dds_return_t -dds_read_instance( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - size_t bufsz, - uint32_t maxs, - dds_instance_handle_t handle) +dds_return_t dds_read_instance (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle) { - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; + bool lock = true; - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(false, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_read_instance_wl( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - uint32_t maxs, - dds_instance_handle_t handle) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(false, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_read_instance_mask( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - size_t bufsz, - uint32_t maxs, - dds_instance_handle_t handle, - uint32_t mask) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(false, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_read_instance_mask_wl( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - uint32_t maxs, - dds_instance_handle_t handle, - uint32_t mask) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(false, rd_or_cnd, buf, maxs, maxs, si, mask, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_read_next( - dds_entity_t reader, - void **buf, - dds_sample_info_t *si) -{ - uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - return dds_read_impl (false, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); -} - -dds_return_t -dds_read_next_wl( - dds_entity_t reader, - void **buf, - dds_sample_info_t *si) -{ - uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - return dds_read_impl (false, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); -} - -dds_return_t -dds_take( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - size_t bufsz, - uint32_t maxs) -{ - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs, so use bufsz instead. - * CHAM-306 will remove this ugly piece of code. */ - maxs = (uint32_t)bufsz; - } - return dds_read_impl (true, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); -} - -dds_return_t -dds_take_wl( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - uint32_t maxs) -{ - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - return dds_read_impl (true, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); -} - -dds_return_t -dds_take_mask( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - size_t bufsz, - uint32_t maxs, - uint32_t mask) -{ - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs, so use bufsz instead. - * CHAM-306 will remove this ugly piece of code. */ - maxs = (uint32_t)bufsz; - } - return dds_read_impl (true, rd_or_cnd, buf, bufsz, maxs, si, mask, DDS_HANDLE_NIL, lock, false); -} - -dds_return_t -dds_take_mask_wl( - dds_entity_t rd_or_cnd, - void ** buf, - dds_sample_info_t * si, - uint32_t maxs, - uint32_t mask) -{ - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - return dds_read_impl (true, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); -} - -int -dds_takecdr( - dds_entity_t rd_or_cnd, - struct ddsi_serdata **buf, - uint32_t maxs, - dds_sample_info_t *si, - uint32_t mask) -{ - bool lock = true; - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - return dds_readcdr_impl (true, rd_or_cnd, buf, maxs, si, mask, DDS_HANDLE_NIL, lock); -} - -dds_return_t -dds_take_instance( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - size_t bufsz, - uint32_t maxs, - dds_instance_handle_t handle) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(true, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_take_instance_wl( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - uint32_t maxs, - dds_instance_handle_t handle) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(true, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_take_instance_mask( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - size_t bufsz, - uint32_t maxs, - dds_instance_handle_t handle, - uint32_t mask) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(true, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_take_instance_mask_wl( - dds_entity_t rd_or_cnd, - void **buf, - dds_sample_info_t *si, - uint32_t maxs, - dds_instance_handle_t handle, - uint32_t mask) -{ - dds_return_t ret = DDS_RETCODE_OK; - bool lock = true; - - if (handle == DDS_HANDLE_NIL) { - DDS_ERROR("DDS_HANDLE_NIL was provided\n"); - ret = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - goto fail; - } - if (maxs == DDS_READ_WITHOUT_LOCK) { - lock = false; - /* Use a more sensible maxs. Just an arbitrarily number. - * CHAM-306 will remove this ugly piece of code. */ - maxs = 100; - } - ret = dds_read_impl(true, rd_or_cnd, buf, maxs, maxs, si, mask, handle, lock, false); -fail: - return ret; -} - -dds_return_t -dds_take_next( - dds_entity_t reader, - void **buf, - dds_sample_info_t *si) -{ - uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - return dds_read_impl (true, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); -} - -dds_return_t -dds_take_next_wl( - dds_entity_t reader, - void **buf, - dds_sample_info_t *si) -{ - uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - return dds_read_impl (true, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); -} - -dds_return_t -dds_return_loan( - dds_entity_t reader_or_condition, - void **buf, - int32_t bufsz) -{ - dds_retcode_t rc; - const struct ddsi_sertopic *st; - dds_reader *rd; - dds_readcond *cond; - dds_return_t ret = DDS_RETCODE_OK; - - if (!buf) { - DDS_ERROR("Argument buf is NULL\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if (*buf == NULL && bufsz > 0) { - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - - rc = dds_read_lock(reader_or_condition, &rd, &cond, false); - if (rc != DDS_RETCODE_OK) { - ret = DDS_ERRNO(rc); - goto fail; - } - st = rd->m_topic->m_stopic; - - for (int32_t i = 0; i < bufsz; i++) { - ddsi_sertopic_free_sample (st, buf[i], DDS_FREE_CONTENTS); - } - - /* If possible return loan buffer to reader */ - if (rd->m_loan != 0 && (buf[0] == rd->m_loan)) { - rd->m_loan_out = false; - ddsi_sertopic_zero_samples (st, rd->m_loan, rd->m_loan_size); - buf[0] = NULL; - } - - dds_read_unlock(rd, cond); -fail: + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, handle, lock, false); +} + +dds_return_t dds_read_instance_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, dds_instance_handle_t handle) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, handle, lock, false); +} + +dds_return_t dds_read_instance_mask (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle, uint32_t mask) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); +} + +dds_return_t dds_read_instance_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, dds_instance_handle_t handle, uint32_t mask) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, handle, lock, false); +} + +dds_return_t dds_read_next (dds_entity_t reader, void **buf, dds_sample_info_t *si) +{ + uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + return dds_read_impl (false, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); +} + +dds_return_t dds_read_next_wl ( + dds_entity_t reader, + void **buf, + dds_sample_info_t *si) +{ + uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + return dds_read_impl (false, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); +} + +dds_return_t dds_take (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = (uint32_t)bufsz; + } + return dds_read_impl (true, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); +} + +dds_return_t dds_take_wl (dds_entity_t rd_or_cnd, void ** buf, dds_sample_info_t * si, uint32_t maxs) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (true, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, DDS_HANDLE_NIL, lock, false); +} + +dds_return_t dds_take_mask (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, uint32_t mask) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = (uint32_t) bufsz; + } + return dds_read_impl (true, rd_or_cnd, buf, bufsz, maxs, si, mask, DDS_HANDLE_NIL, lock, false); +} + +dds_return_t dds_take_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, uint32_t mask) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl (true, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); +} + +dds_return_t dds_takecdr (dds_entity_t rd_or_cnd, struct ddsi_serdata **buf, uint32_t maxs, dds_sample_info_t *si, uint32_t mask) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_readcdr_impl (true, rd_or_cnd, buf, maxs, si, mask, DDS_HANDLE_NIL, lock); +} + +dds_return_t dds_take_instance (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl(true, rd_or_cnd, buf, bufsz, maxs, si, NO_STATE_MASK_SET, handle, lock, false); +} + +dds_return_t dds_take_instance_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, dds_instance_handle_t handle) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl(true, rd_or_cnd, buf, maxs, maxs, si, NO_STATE_MASK_SET, handle, lock, false); +} + +dds_return_t dds_take_instance_mask (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle, uint32_t mask) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl(true, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); +} + +dds_return_t dds_take_instance_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, uint32_t maxs, dds_instance_handle_t handle, uint32_t mask) +{ + bool lock = true; + + if (handle == DDS_HANDLE_NIL) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_read_impl(true, rd_or_cnd, buf, maxs, maxs, si, mask, handle, lock, false); +} + +dds_return_t dds_take_next (dds_entity_t reader, void **buf, dds_sample_info_t *si) +{ + uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + return dds_read_impl (true, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); +} + +dds_return_t dds_take_next_wl (dds_entity_t reader, void **buf, dds_sample_info_t *si) +{ + uint32_t mask = DDS_NOT_READ_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + return dds_read_impl (true, reader, buf, 1u, 1u, si, mask, DDS_HANDLE_NIL, true, true); +} + +dds_return_t dds_return_loan (dds_entity_t reader_or_condition, void **buf, int32_t bufsz) +{ + const struct ddsi_sertopic *st; + dds_reader *rd; + dds_entity *entity; + dds_return_t ret = DDS_RETCODE_OK; + + if (buf == NULL || (*buf == NULL && bufsz > 0)) + return DDS_RETCODE_BAD_PARAMETER; + + if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { return ret; + } else if (dds_entity_kind (entity) == DDS_KIND_READER) { + rd = (dds_reader *) entity; + } else if (dds_entity_kind (entity) != DDS_KIND_COND_READ && dds_entity_kind (entity) != DDS_KIND_COND_QUERY) { + dds_entity_unpin (entity); + return DDS_RETCODE_ILLEGAL_OPERATION; + } else { + rd = (dds_reader *) entity->m_parent; + } + + st = rd->m_topic->m_stopic; + for (int32_t i = 0; i < bufsz; i++) + ddsi_sertopic_free_sample (st, buf[i], DDS_FREE_CONTENTS); + + /* If possible return loan buffer to reader */ + ddsrt_mutex_lock (&rd->m_entity.m_mutex); + if (rd->m_loan != 0 && (buf[0] == rd->m_loan)) + { + rd->m_loan_out = false; + ddsi_sertopic_zero_samples (st, rd->m_loan, rd->m_loan_size); + buf[0] = NULL; + } + ddsrt_mutex_unlock (&rd->m_entity.m_mutex); + dds_entity_unpin (entity); + return DDS_RETCODE_OK; } diff --git a/src/core/ddsc/src/dds_readcond.c b/src/core/ddsc/src/dds_readcond.c index ee37521..acfd1b8 100644 --- a/src/core/ddsc/src/dds_readcond.c +++ b/src/core/ddsc/src/dds_readcond.c @@ -14,78 +14,75 @@ #include "dds__readcond.h" #include "dds__rhc.h" #include "dds__entity.h" -#include "dds__err.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" -static dds_return_t -dds_readcond_delete( - dds_entity *e) +static dds_return_t dds_readcond_delete (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_readcond_delete (dds_entity *e) { - dds_rhc_remove_readcondition((dds_readcond*)e); - return DDS_RETCODE_OK; + dds_rhc_remove_readcondition ((dds_readcond *) e); + return DDS_RETCODE_OK; } -dds_readcond* -dds_create_readcond( - dds_reader *rd, - dds_entity_kind_t kind, - uint32_t mask, - dds_querycondition_filter_fn filter) +const struct dds_entity_deriver dds_entity_deriver_readcondition = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_readcond_delete, + .set_qos = dds_entity_deriver_dummy_set_qos, + .validate_status = dds_entity_deriver_dummy_validate_status +}; + +dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint32_t mask, dds_querycondition_filter_fn filter) { - dds_readcond * cond = dds_alloc(sizeof(*cond)); - assert((kind == DDS_KIND_COND_READ && filter == 0) || (kind == DDS_KIND_COND_QUERY && filter != 0)); - (void) dds_entity_init(&cond->m_entity, (dds_entity*)rd, kind, NULL, NULL, 0); - cond->m_entity.m_deriver.delete = dds_readcond_delete; - cond->m_rhc = rd->m_rd->rhc; - cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE; - cond->m_view_states = mask & DDS_ANY_VIEW_STATE; - cond->m_instance_states = mask & DDS_ANY_INSTANCE_STATE; - cond->m_rd_guid = rd->m_entity.m_guid; - if (kind == DDS_KIND_COND_QUERY) { - cond->m_query.m_filter = filter; - cond->m_query.m_qcmask = 0; - } - if (!dds_rhc_add_readcondition (cond)) { - /* FIXME: current entity management code can't deal with an error late in the creation of the - entity because it doesn't allow deleting it again ... instead use a hack to signal a problem - to the caller and let that one handle it. */ - cond->m_entity.m_deriver.delete = 0; - } - return cond; + dds_readcond *cond = dds_alloc (sizeof (*cond)); + assert ((kind == DDS_KIND_COND_READ && filter == 0) || (kind == DDS_KIND_COND_QUERY && filter != 0)); + (void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0); + cond->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&rd->m_entity, &cond->m_entity); + cond->m_rhc = rd->m_rhc; + cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE; + cond->m_view_states = mask & DDS_ANY_VIEW_STATE; + cond->m_instance_states = mask & DDS_ANY_INSTANCE_STATE; + cond->m_rd_guid = rd->m_entity.m_guid; + if (kind == DDS_KIND_COND_QUERY) + { + cond->m_query.m_filter = filter; + cond->m_query.m_qcmask = 0; + } + if (!dds_rhc_add_readcondition (cond)) + { + /* FIXME: current entity management code can't deal with an error late in the creation of the + entity because it doesn't allow deleting it again ... */ + abort(); + } + return cond; } -dds_entity_t -dds_create_readcondition( - dds_entity_t reader, - uint32_t mask) +dds_entity_t dds_create_readcondition (dds_entity_t reader, uint32_t mask) { + dds_reader *rd; + dds_return_t rc; + if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) + return rc; + else + { dds_entity_t hdl; - dds_reader * rd; - dds_retcode_t rc; - - rc = dds_reader_lock(reader, &rd); - if (rc == DDS_RETCODE_OK) { - dds_readcond *cond = dds_create_readcond(rd, DDS_KIND_COND_READ, mask, 0); - assert(cond); - assert(cond->m_entity.m_deriver.delete); - hdl = cond->m_entity.m_hdllink.hdl; - dds_reader_unlock(rd); - } else { - DDS_ERROR("Error occurred on locking reader\n"); - hdl = DDS_ERRNO(rc); - } - + dds_readcond *cond = dds_create_readcond(rd, DDS_KIND_COND_READ, mask, 0); + assert (cond); + hdl = cond->m_entity.m_hdllink.hdl; + dds_reader_unlock (rd); return hdl; + } } dds_entity_t dds_get_datareader (dds_entity_t condition) { struct dds_entity *e; - dds_retcode_t rc; - if ((rc = dds_entity_claim (condition, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + dds_return_t rc; + if ((rc = dds_entity_pin (condition, &e)) != DDS_RETCODE_OK) + return rc; else { dds_entity_t rdh; @@ -97,10 +94,10 @@ dds_entity_t dds_get_datareader (dds_entity_t condition) rdh = e->m_parent->m_hdllink.hdl; break; default: - rdh = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + rdh = DDS_RETCODE_ILLEGAL_OPERATION; break; } - dds_entity_release (e); + dds_entity_unpin (e); return rdh; } } @@ -108,17 +105,17 @@ dds_entity_t dds_get_datareader (dds_entity_t condition) dds_return_t dds_get_mask (dds_entity_t condition, uint32_t *mask) { dds_entity *entity; - dds_retcode_t rc; + dds_return_t rc; if (mask == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; if ((rc = dds_entity_lock (condition, DDS_KIND_DONTCARE, &entity)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + return rc; else if (dds_entity_kind (entity) != DDS_KIND_COND_READ && dds_entity_kind (entity) != DDS_KIND_COND_QUERY) { dds_entity_unlock (entity); - return DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + return DDS_RETCODE_ILLEGAL_OPERATION; } else { diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index be86ed3..96e2a03 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -13,145 +13,80 @@ #include #include "dds/dds.h" #include "dds/version.h" +#include "dds/ddsrt/static_assert.h" #include "dds__subscriber.h" #include "dds__reader.h" #include "dds__listener.h" -#include "dds__qos.h" #include "dds__init.h" #include "dds__rhc.h" -#include "dds__err.h" +#include "dds__rhc_default.h" #include "dds__topic.h" +#include "dds__get_status.h" +#include "dds__qos.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_globals.h" #include "dds__builtin.h" #include "dds/ddsi/ddsi_sertopic.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_reader) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader) #define DDS_READER_STATUS_MASK \ - DDS_SAMPLE_REJECTED_STATUS |\ - DDS_LIVELINESS_CHANGED_STATUS |\ - DDS_REQUESTED_DEADLINE_MISSED_STATUS |\ - DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS |\ - DDS_DATA_AVAILABLE_STATUS |\ - DDS_SAMPLE_LOST_STATUS |\ - DDS_SUBSCRIPTION_MATCHED_STATUS + (DDS_SAMPLE_REJECTED_STATUS |\ + DDS_LIVELINESS_CHANGED_STATUS |\ + DDS_REQUESTED_DEADLINE_MISSED_STATUS |\ + DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS |\ + DDS_DATA_AVAILABLE_STATUS |\ + DDS_SAMPLE_LOST_STATUS |\ + DDS_SUBSCRIPTION_MATCHED_STATUS) -static dds_return_t -dds_reader_instance_hdl( - dds_entity *e, - dds_instance_handle_t *i) +static dds_return_t dds_reader_close (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_reader_close (dds_entity *e) { - assert(e); - assert(i); - *i = (dds_instance_handle_t)reader_instance_id(&e->m_guid); - return DDS_RETCODE_OK; + dds_return_t ret = DDS_RETCODE_OK; + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + if (delete_reader (&e->m_domain->gv, &e->m_guid) != 0) + ret = DDS_RETCODE_ERROR; + thread_state_asleep (lookup_thread_state ()); + return ret; } -static dds_return_t -dds_reader_close( - dds_entity *e) +static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_reader_delete (dds_entity *e) { - dds_retcode_t rc; - dds_return_t ret = DDS_RETCODE_OK; + dds_reader * const rd = (dds_reader *) e; + dds_return_t ret; + if ((ret = dds_delete (rd->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK) + { + /* Delete an implicitly created parent; for normal ones, this is expected + to fail with BAD_PARAMETER - FIXME: there must be a cleaner way */ + ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true); + if (ret == DDS_RETCODE_BAD_PARAMETER) + ret = DDS_RETCODE_OK; + } + dds_free (rd->m_loan); + return ret; +} - assert(e); - - thread_state_awake (lookup_thread_state ()); - if (delete_reader(&e->m_guid) != 0) { - DDS_ERROR("Internal error"); - rc = DDS_RETCODE_ERROR; - ret = DDS_ERRNO(rc); - } +static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) +{ + /* note: e->m_qos is still the old one to allow for failure here */ + if (enabled) + { + struct reader *rd; + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + if ((rd = ephash_lookup_reader_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL) + update_reader_qos (rd, qos); thread_state_asleep (lookup_thread_state ()); - return ret; + } + return DDS_RETCODE_OK; } -static dds_return_t -dds_reader_delete( - dds_entity *e) +static dds_return_t dds_reader_status_validate (uint32_t mask) { - dds_reader *rd = (dds_reader*)e; - dds_return_t ret; - assert(e); - ret = dds_delete(rd->m_topic->m_entity.m_hdllink.hdl); - if(ret == DDS_RETCODE_OK){ - ret = dds_delete_impl(e->m_parent->m_hdllink.hdl, true); - if(dds_err_nr(ret) == DDS_RETCODE_BAD_PARAMETER){ - ret = DDS_RETCODE_OK; - } - } - dds_free(rd->m_loan); - return ret; -} - -static dds_return_t -dds_reader_qos_validate( - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = DDS_RETCODE_OK; - - assert(qos); - - /* Check consistency. */ - if(!dds_qos_validate_common(qos)) { - DDS_ERROR("Argument Qos is not valid\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - } - if((qos->present & QP_USER_DATA) && !(validate_octetseq (&qos->user_data))) { - DDS_ERROR("User data policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PRISMTECH_READER_DATA_LIFECYCLE) && (validate_reader_data_lifecycle (&qos->reader_data_lifecycle) != 0)) { - DDS_ERROR("Prismtech reader data lifecycle policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_TIME_BASED_FILTER) && (validate_duration (&qos->time_based_filter.minimum_separation) != 0)) { - DDS_ERROR("Time based filter policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_HISTORY) && (qos->present & QP_RESOURCE_LIMITS) && (validate_history_and_resource_limits (&qos->history, &qos->resource_limits) != 0)) { - DDS_ERROR("History and resource limits policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_TIME_BASED_FILTER) && (qos->present & QP_DEADLINE) && !(validate_deadline_and_timebased_filter (qos->deadline.deadline, qos->time_based_filter.minimum_separation))) { - DDS_ERROR("Time based filter and deadline policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if(ret == DDS_RETCODE_OK && enabled) { - ret = dds_qos_validate_mutable_common(qos); - } - - return ret; -} - -static dds_return_t -dds_reader_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = dds_reader_qos_validate(qos, enabled); - (void)e; - if (ret == DDS_RETCODE_OK) { - if (enabled) { - /* TODO: CHAM-95: DDSI does not support changing QoS policies. */ - DDS_ERROR(DDS_PROJECT_NAME" does not support changing QoS policies\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); - } - } - return ret; -} - -static dds_return_t -dds_reader_status_validate( - uint32_t mask) -{ - return (mask & ~(DDS_READER_STATUS_MASK)) ? - DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER) : - DDS_RETCODE_OK; + return (mask & ~DDS_READER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } void dds_reader_data_available_cb (struct dds_reader *rd) @@ -162,13 +97,11 @@ void dds_reader_data_available_cb (struct dds_reader *rd) overhead really matters. Otherwise, it is pretty much like dds_reader_status_cb. */ - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (!(rd->m_entity.m_status_enable & DDS_DATA_AVAILABLE_STATUS)) - { - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); + const bool data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT)); + if (!data_av_enabled) return; - } + ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); while (rd->m_entity.m_cb_count > 0) ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock); rd->m_entity.m_cb_count++; @@ -202,7 +135,6 @@ void dds_reader_data_available_cb (struct dds_reader *rd) else { dds_entity_status_set (&rd->m_entity, DDS_DATA_AVAILABLE_STATUS); - ddsrt_mutex_lock (&sub->m_observers_lock); dds_entity_status_set (sub, DDS_DATA_ON_READERS_STATUS); ddsrt_mutex_unlock (&sub->m_observers_lock); @@ -222,7 +154,7 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) { /* Release the initial claim that was done during the create. This * will indicate that further API deletion is now possible. */ - dds_handle_release (&entity->m_hdllink); + dds_handle_unpin (&entity->m_hdllink); return; } @@ -336,7 +268,7 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) if (invoke) { ddsrt_mutex_unlock (&entity->m_observers_lock); - dds_entity_invoke_listener(entity, status_id, vst); + dds_entity_invoke_listener (entity, status_id, vst); ddsrt_mutex_lock (&entity->m_observers_lock); *reset[0] = 0; if (reset[1]) @@ -344,7 +276,7 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) } else { - dds_entity_status_set (entity, 1u << status_id); + dds_entity_status_set (entity, (status_mask_t) (1u << status_id)); } entity->m_cb_count--; @@ -352,174 +284,155 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) ddsrt_mutex_unlock (&entity->m_observers_lock); } -dds_entity_t -dds_create_reader( - dds_entity_t participant_or_subscriber, - dds_entity_t topic, - const dds_qos_t *qos, - const dds_listener_t *listener) +const struct dds_entity_deriver dds_entity_deriver_reader = { + .close = dds_reader_close, + .delete = dds_reader_delete, + .set_qos = dds_reader_qos_set, + .validate_status = dds_reader_status_validate +}; + +dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener) { - dds_qos_t * rqos; - dds_retcode_t rc; - dds_subscriber * sub = NULL; - dds_entity_t subscriber; - dds_reader * rd; - struct rhc * rhc; - dds_topic * tp; - dds_entity_t reader; - dds_entity_t t; - dds_return_t ret = DDS_RETCODE_OK; - bool internal_topic; + dds_qos_t *rqos; + dds_subscriber *sub = NULL; + dds_entity_t subscriber; + dds_reader *rd; + dds_topic *tp; + dds_entity_t reader; + dds_entity_t t; + dds_return_t ret = DDS_RETCODE_OK; + bool internal_topic; - switch (topic) { - case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: - case DDS_BUILTIN_TOPIC_DCPSTOPIC: - case DDS_BUILTIN_TOPIC_DCPSPUBLICATION: - case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION: - internal_topic = true; - subscriber = dds__get_builtin_subscriber(participant_or_subscriber); - t = dds__get_builtin_topic (subscriber, topic); - break; + switch (topic) + { + case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: + case DDS_BUILTIN_TOPIC_DCPSTOPIC: + case DDS_BUILTIN_TOPIC_DCPSPUBLICATION: + case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION: + internal_topic = true; + subscriber = dds__get_builtin_subscriber (participant_or_subscriber); + t = dds__get_builtin_topic (subscriber, topic); + break; - default: { - dds_entity *p_or_s; - if ((rc = dds_entity_claim (participant_or_subscriber, &p_or_s)) != DDS_RETCODE_OK) { - return DDS_ERRNO (rc); - } - if (dds_entity_kind (p_or_s) == DDS_KIND_PARTICIPANT) { - subscriber = dds_create_subscriber(participant_or_subscriber, qos, NULL); - } else { - subscriber = participant_or_subscriber; - } - dds_entity_release (p_or_s); - internal_topic = false; - t = topic; - break; - } + default: { + dds_entity *p_or_s; + if ((ret = dds_entity_pin (participant_or_subscriber, &p_or_s)) != DDS_RETCODE_OK) + return ret; + if (dds_entity_kind (p_or_s) == DDS_KIND_PARTICIPANT) + subscriber = dds_create_subscriber (participant_or_subscriber, qos, NULL); + else + subscriber = participant_or_subscriber; + dds_entity_unpin (p_or_s); + internal_topic = false; + t = topic; + break; } + } - if ((rc = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK) { - reader = DDS_ERRNO (rc); - goto err_sub_lock; - } + if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK) + { + reader = ret; + goto err_sub_lock; + } - if ((subscriber != participant_or_subscriber) && !internal_topic) { - /* Delete implicit subscriber if reader creation fails */ - sub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT; - } + if (subscriber != participant_or_subscriber && !internal_topic) + { + /* Delete implicit subscriber if reader creation fails */ + sub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT; + } - rc = dds_topic_lock(t, &tp); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking topic\n"); - reader = DDS_ERRNO(rc); - goto err_tp_lock; - } - assert (tp->m_stopic); - assert (sub->m_entity.m_domain == tp->m_entity.m_domain); + if ((ret = dds_topic_lock (t, &tp)) != DDS_RETCODE_OK) + { + reader = ret; + goto err_tp_lock; + } + assert (tp->m_stopic); + /* FIXME: domain check */ + assert (sub->m_entity.m_domain == tp->m_entity.m_domain); - /* Merge qos from topic and subscriber */ - rqos = dds_create_qos (); - if (qos) { - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(rqos, qos); - } + /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null + argument, but that isn't the case here */ + rqos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK); + if (sub->m_entity.m_qos) + nn_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); + if (tp->m_entity.m_qos) + nn_xqos_mergein_missing (rqos, tp->m_entity.m_qos, ~(uint64_t)0); + nn_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0); - if(sub->m_entity.m_qos){ - dds_merge_qos (rqos, sub->m_entity.m_qos); - } + if ((ret = nn_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) != DDS_RETCODE_OK) + { + dds_delete_qos (rqos); + reader = ret; + goto err_bad_qos; + } - if (tp->m_entity.m_qos) { - dds_merge_qos (rqos, tp->m_entity.m_qos); + /* Additional checks required for built-in topics: we don't want to + run into a resource limit on a built-in topic, it is a needless + complication */ + if (internal_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, topic, rqos)) + { + dds_delete_qos (rqos); + reader = DDS_RETCODE_INCONSISTENT_POLICY; + goto err_bad_qos; + } - /* reset the following qos policies if set during topic qos merge as they aren't applicable for reader */ - rqos->present &= ~(QP_DURABILITY_SERVICE | QP_TRANSPORT_PRIORITY | QP_LIFESPAN); - } - nn_xqos_mergein_missing (rqos, &gv.default_xqos_rd); + /* Create reader and associated read cache */ + rd = dds_alloc (sizeof (*rd)); + reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK); + rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; + rd->m_topic = tp; + rd->m_rhc = dds_rhc_default_new (rd, tp->m_stopic); + dds_entity_add_ref_locked (&tp->m_entity); - ret = dds_reader_qos_validate (rqos, false); - if (ret != 0) { - dds_delete_qos(rqos); - reader = ret; - goto err_bad_qos; - } + /* Extra claim of this reader to make sure that the delete waits until DDSI + has deleted its reader as well. This can be known through the callback. */ + dds_handle_repin (&rd->m_entity.m_hdllink); - /* Additional checks required for built-in topics */ - if (internal_topic && !dds__validate_builtin_reader_qos(topic, qos)) { - dds_delete_qos(rqos); - DDS_ERROR("Invalid QoS specified for built-in topic reader"); - reader = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - goto err_bad_qos; - } + ddsrt_mutex_unlock (&tp->m_entity.m_mutex); + ddsrt_mutex_unlock (&sub->m_entity.m_mutex); - /* Create reader and associated read cache */ - rd = dds_alloc (sizeof (*rd)); - reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK); - rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; - rd->m_topic = tp; - rhc = dds_rhc_new (rd, tp->m_stopic); - dds_entity_add_ref_nolock (&tp->m_entity); - rd->m_entity.m_deriver.close = dds_reader_close; - rd->m_entity.m_deriver.delete = dds_reader_delete; - rd->m_entity.m_deriver.set_qos = dds_reader_qos_set; - rd->m_entity.m_deriver.validate_status = dds_reader_status_validate; - rd->m_entity.m_deriver.get_instance_hdl = dds_reader_instance_hdl; + thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv); + ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &sub->m_entity.m_participant->m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); + ddsrt_mutex_lock (&sub->m_entity.m_mutex); + ddsrt_mutex_lock (&tp->m_entity.m_mutex); + assert (ret == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ + thread_state_asleep (lookup_thread_state ()); + + rd->m_entity.m_iid = get_entity_instance_id (&rd->m_entity.m_domain->gv, &rd->m_entity.m_guid); + dds_entity_register_child (&sub->m_entity, &rd->m_entity); - /* Extra claim of this reader to make sure that the delete waits until DDSI - * has deleted its reader as well. This can be known through the callback. */ - dds_handle_claim_inc (&rd->m_entity.m_hdllink); + dds_topic_unlock (tp); + dds_subscriber_unlock (sub); - ddsrt_mutex_unlock(&tp->m_entity.m_mutex); - ddsrt_mutex_unlock(&sub->m_entity.m_mutex); - - thread_state_awake (lookup_thread_state ()); - ret = new_reader(&rd->m_rd, &rd->m_entity.m_guid, NULL, &sub->m_entity.m_participant->m_guid, tp->m_stopic, - rqos, rhc, dds_reader_status_cb, rd); - ddsrt_mutex_lock(&sub->m_entity.m_mutex); - ddsrt_mutex_lock(&tp->m_entity.m_mutex); - assert (ret == DDS_RETCODE_OK); - thread_state_asleep (lookup_thread_state ()); - - /* For persistent data register reader with durability */ - if (dds_global.m_dur_reader && (rd->m_entity.m_qos->durability.kind > NN_TRANSIENT_LOCAL_DURABILITY_QOS)) { - (dds_global.m_dur_reader) (rd, rhc); - } - dds_topic_unlock(tp); - dds_subscriber_unlock(sub); - - if (internal_topic) { - /* If topic is builtin, then the topic entity is local and should - * be deleted because the application won't. */ - dds_delete(t); - } - - return reader; + if (internal_topic) + { + /* If topic is builtin, then the topic entity is local and should be deleted because the application won't. */ + dds_delete (t); + } + return reader; err_bad_qos: - dds_topic_unlock(tp); + dds_topic_unlock (tp); err_tp_lock: - dds_subscriber_unlock(sub); - if((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){ - (void)dds_delete(subscriber); - } + dds_subscriber_unlock (sub); + if ((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0) + (void) dds_delete (subscriber); err_sub_lock: - if (internal_topic) { - /* If topic is builtin, then the topic entity is local and should - * be deleted because the application won't. */ - dds_delete(t); - } - return reader; + if (internal_topic) + dds_delete (t); + return reader; } void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb, void *cbarg) { dds_entity *dds_entity; - if (dds_entity_claim(entity, &dds_entity) != DDS_RETCODE_OK) + if (dds_entity_pin (entity, &dds_entity) != DDS_RETCODE_OK) return; - if (dds_entity_kind (dds_entity) != DDS_KIND_READER) { - dds_entity_release (dds_entity); + dds_entity_unpin (dds_entity); return; } @@ -536,7 +449,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb while ((m = ddsrt_avl_lookup_succ_eq (&rd_writers_treedef, &rd->writers, &pwrguid)) != NULL) { /* have to be careful walking the tree -- pretty is different, but - I want to check this before I write a lookup_succ function. */ + I want to check this before I write a lookup_succ function. */ struct rd_pwr_match *m_next; nn_guid_t pwrguid_next; pwrguid = m->pwr_guid; @@ -548,7 +461,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb pwrguid_next.entityid.u = (pwrguid_next.entityid.u & ~(uint32_t)0xff) | NN_ENTITYID_KIND_WRITER_NO_KEY; } ddsrt_mutex_unlock (&rd->e.lock); - if ((pwr = ephash_lookup_proxy_writer_guid (&pwrguid)) != NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (dds_entity->m_domain->gv.guid_hash, &pwrguid)) != NULL) { ddsrt_mutex_lock (&pwr->e.lock); pwr->ddsi2direct_cb = cb; @@ -559,7 +472,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb ddsrt_mutex_lock (&rd->e.lock); } ddsrt_mutex_unlock (&rd->e.lock); - dds_entity_release (dds_entity); + dds_entity_unpin (dds_entity); } uint32_t dds_reader_lock_samples (dds_entity_t reader) @@ -568,17 +481,18 @@ uint32_t dds_reader_lock_samples (dds_entity_t reader) uint32_t n; if (dds_reader_lock (reader, &rd) != DDS_RETCODE_OK) return 0; - n = dds_rhc_lock_samples (rd->m_rd->rhc); + n = dds_rhc_lock_samples (rd->m_rhc); dds_reader_unlock (rd); return n; } -int dds_reader_wait_for_historical_data (dds_entity_t reader, dds_duration_t max_wait) +dds_return_t dds_reader_wait_for_historical_data (dds_entity_t reader, dds_duration_t max_wait) { dds_reader *rd; - int ret; + dds_return_t ret; + (void) max_wait; if ((ret = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) - return DDS_ERRNO (ret); + return ret; switch (rd->m_entity.m_qos->durability.kind) { case DDS_DURABILITY_VOLATILE: @@ -588,7 +502,6 @@ int dds_reader_wait_for_historical_data (dds_entity_t reader, dds_duration_t max break; case DDS_DURABILITY_TRANSIENT: case DDS_DURABILITY_PERSISTENT: - ret = (dds_global.m_dur_wait) (rd, max_wait); break; } dds_reader_unlock(rd); @@ -598,9 +511,9 @@ int dds_reader_wait_for_historical_data (dds_entity_t reader, dds_duration_t max dds_entity_t dds_get_subscriber (dds_entity_t entity) { dds_entity *e; - dds_retcode_t ret; - if ((ret = dds_entity_claim (entity, &e)) != DDS_RETCODE_OK) - return (dds_entity_t) DDS_ERRNO (ret); + dds_return_t ret; + if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK) + return ret; else { dds_entity_t subh; @@ -617,189 +530,21 @@ dds_entity_t dds_get_subscriber (dds_entity_t entity) subh = e->m_parent->m_parent->m_hdllink.hdl; break; default: - subh = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + subh = DDS_RETCODE_ILLEGAL_OPERATION; break; } - dds_entity_release (e); + dds_entity_unpin (e); return subh; } } -dds_return_t -dds_get_subscription_matched_status ( - dds_entity_t reader, - dds_subscription_matched_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; +/* Reset sets everything (type) 0, including the reason field, verify that 0 is correct */ +DDSRT_STATIC_ASSERT ((int) DDS_NOT_REJECTED == 0); - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_subscription_matched_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_SUBSCRIPTION_MATCHED_STATUS) { - rd->m_subscription_matched_status.total_count_change = 0; - rd->m_subscription_matched_status.current_count_change = 0; - dds_entity_status_reset(&rd->m_entity, DDS_SUBSCRIPTION_MATCHED_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} +DDS_GET_STATUS (reader, subscription_matched, SUBSCRIPTION_MATCHED, total_count_change, current_count_change) +DDS_GET_STATUS (reader, liveliness_changed, LIVELINESS_CHANGED, alive_count_change, not_alive_count_change) +DDS_GET_STATUS (reader, sample_rejected, SAMPLE_REJECTED, total_count_change) +DDS_GET_STATUS (reader, sample_lost, SAMPLE_LOST, total_count_change) +DDS_GET_STATUS (reader, requested_deadline_missed, REQUESTED_DEADLINE_MISSED, total_count_change) +DDS_GET_STATUS (reader, requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, total_count_change) -dds_return_t -dds_get_liveliness_changed_status ( - dds_entity_t reader, - dds_liveliness_changed_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_liveliness_changed_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_LIVELINESS_CHANGED_STATUS) { - rd->m_liveliness_changed_status.alive_count_change = 0; - rd->m_liveliness_changed_status.not_alive_count_change = 0; - dds_entity_status_reset(&rd->m_entity, DDS_LIVELINESS_CHANGED_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} - -dds_return_t dds_get_sample_rejected_status ( - dds_entity_t reader, - dds_sample_rejected_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_sample_rejected_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_SAMPLE_REJECTED_STATUS) { - rd->m_sample_rejected_status.total_count_change = 0; - rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; - dds_entity_status_reset(&rd->m_entity, DDS_SAMPLE_REJECTED_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} - -dds_return_t dds_get_sample_lost_status ( - dds_entity_t reader, - dds_sample_lost_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_sample_lost_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_SAMPLE_LOST_STATUS) { - rd->m_sample_lost_status.total_count_change = 0; - dds_entity_status_reset(&rd->m_entity, DDS_SAMPLE_LOST_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} - -dds_return_t dds_get_requested_deadline_missed_status ( - dds_entity_t reader, - dds_requested_deadline_missed_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_requested_deadline_missed_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_REQUESTED_DEADLINE_MISSED_STATUS) { - rd->m_requested_deadline_missed_status.total_count_change = 0; - dds_entity_status_reset(&rd->m_entity, DDS_REQUESTED_DEADLINE_MISSED_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} - -dds_return_t dds_get_requested_incompatible_qos_status ( - dds_entity_t reader, - dds_requested_incompatible_qos_status_t * status) -{ - dds_retcode_t rc; - dds_reader *rd; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_reader_lock(reader, &rd); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking reader\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = rd->m_requested_incompatible_qos_status; - } - ddsrt_mutex_lock (&rd->m_entity.m_observers_lock); - if (rd->m_entity.m_status_enable & DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS) { - rd->m_requested_incompatible_qos_status.total_count_change = 0; - dds_entity_status_reset(&rd->m_entity, DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS); - } - ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock); - dds_reader_unlock(rd); -fail: - return ret; -} diff --git a/src/core/ddsc/src/dds_rhc.c b/src/core/ddsc/src/dds_rhc.c index 79a134a..86bbf79 100644 --- a/src/core/ddsc/src/dds_rhc.c +++ b/src/core/ddsc/src/dds_rhc.c @@ -9,2761 +9,19 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include -#include -#include -#if HAVE_VALGRIND && ! defined (NDEBUG) -#include -#define USE_VALGRIND 1 -#else -#define USE_VALGRIND 0 -#endif - -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/sync.h" - -#include "dds__entity.h" -#include "dds__reader.h" +#include "dds/dds.h" +#include "dds/ddsi/q_rhc.h" #include "dds__rhc.h" -#include "dds/ddsi/ddsi_tkmap.h" -#include "dds/ddsrt/hopscotch.h" -#include "dds/ddsrt/avl.h" -#include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/q_error.h" -#include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" -#include "dds/ddsi/q_radmin.h" /* sampleinfo */ -#include "dds/ddsi/q_entity.h" /* proxy_writer_info */ -#include "dds/ddsi/ddsi_serdata.h" -#include "dds/ddsi/ddsi_serdata_default.h" -#include "dds/ddsi/sysdeps.h" -/* INSTANCE MANAGEMENT - =================== - - Instances are created implicitly by "write" and "dispose", unregistered by - "unregister". Valid samples are added only by write operations (possibly - a combined with dispose and/or unregister), invalid samples only by dispose - and unregister operations, and only when there is no sample or the latest - available sample is read. (This might be a bit funny in the oddish case - where someone would take only the latest of multiple valid samples.) - - There is at most one invalid sample per instance, its sample info is taken - straight from the instance when it is returned to the reader and its - presence and sample_state are represented by two bits. Any incoming sample - (or "incoming invalid sample") will cause an existing invalid sample to be - dropped. Thus, invalid samples are used solely to signal an instance state - change when there are no samples. - - (Note: this can fairly easily be changed to let an invalid sample always - be generated on dispose/unregister.) - - The instances and the RHC as a whole keep track of the number of valid - samples and the number of read valid samples, as well as the same for the - invalid ones, with the twist that the "inv_exists" and "inv_isread" booleans - in the RHC serve as flags and as counters at the same time. - - Instances are dropped when the number of samples (valid & invalid combined) - and the number of registrations both go to 0. The number of registrations - is kept track of in "wrcount", and a unique identifier for the most recent - writer is typically in "wr_iid". Typically, because an unregister by - "wr_iid" clears it. The actual set of registrations is in principle a set - of tuples stored in "registrations", but excluded from it - are those instances that have "wrcount" = 1 and "wr_iid" != 0. The typical - case is a single active writer for an instance, and this means the typical - case has no tuples in "registrations". - - It is unfortunate that this model complicates the transitions from 1 writer - to 2 writers, and from 2 writers back to 1 writer. This seems a reasonable - price to pay for the significant performance gain from not having to do - anything in the case of a single (or single dominant) writer. - - (Note: "registrations" may perhaps be moved to a global registration table - of tuples, using a lock-free hash table, but that - doesn't affect the model.) - - The unique identifiers for instances and writers are approximately uniformly - drawn from the set of positive unsigned 64-bit integers. This means they - are excellent hash keys, and both the instance hash table and the writer - registrations hash table use these directly. - - QOS SUPPORT - =========== - - History is implemented as a (circular) linked list, but the invalid samples - model implemented here allows this to trivially be changed to an array of - samples, and this is probably profitable for shallow histories. Currently - the instance has a single sample embedded in particular to optimise the - KEEP_LAST with depth=1 case. - - BY_SOURCE ordering is implemented differently from OpenSplice and does not - perform back-filling of the history. The arguments against that can be - found in JIRA, but in short: (1) not backfilling is significantly simpler - (and thus faster), (2) backfilling potentially requires rewriting the - states of samples already read, (3) it is as much "eventually consistent", - the only difference is that the model implemented here considers the - dataspace to fundamentally be "keep last 1" and always move forward (source - timestamp increases), and the per-reader history to be a record of sampling - that dataspace by the reader, whereas with backfilling the model is that - the eventual consistency applies to the full history. - - (As it happens, the model implemented here is that also used by RTI and - probably other implementations -- OpenSplice is the odd one out in this - regard.) - - Exclusive ownership is implemented by dropping all data from all writers - other than "wr_iid", unless "wr_iid" is 0 or the strength of the arriving - sample is higher than the current strength of the instance (in "strength"). - The writer id is only reset by unregistering, in which case it is natural - that ownership is up for grabs again. QoS changes (not supported in this - DDSI implementation, but still) will be done by also reseting "wr_iid" - when an exclusive ownership writer lowers its strength. - - Lifespan, time base filter and deadline, are based on the instance - timestamp ("tstamp"). This time stamp needs to be changed to either source - or reception timestamp, depending on the ordering chosen. - - READ CONDITIONS - =============== - - Read conditions are currently *always* attached to the reader, creating a - read condition and not attaching it to a waitset is a bit of a waste of - resources. This can be changed, of course, but it is doubtful many read - conditions get created without actually being used. - - The "trigger" of a read condition counts the number of instances - matching its condition and is synchronously updated whenever the state - of instances and/or samples changes. The instance/sample states are - reduced to a triplet of a bitmask representing the instance and view - states, whether or not the instance has unread samples, and whether or not - it has read ones. (Invalid samples included.) Two of these triplets, - pre-change and post-change are passed to "update_conditions_locked", - which then runs over the array of attached read conditions and updates - the trigger. It returns whether or not a trigger changed - from 0 to 1, as this indicates the attached waitsets must be signalled. - The actual signalling of the waitsets then takes places later, by calling - "signal_conditions" after releasing the RHC lock. -*/ - -/* FIXME: tkmap should perhaps retain data with timestamp set to invalid - An invalid timestamp is (logically) unordered with respect to valid - timestamps, and that would mean BY_SOURCE order could be respected - even when generating an invalid sample for an unregister message using - the tkmap data. */ - -#define MAX_ATTACHED_QUERYCONDS (CHAR_BIT * sizeof (dds_querycond_mask_t)) - -#define INCLUDE_TRACE 1 -#if INCLUDE_TRACE -#define TRACE(...) DDS_LOG(DDS_LC_RHC, __VA_ARGS__) -#else -#define TRACE(...) ((void)0) -#endif - -/****************************** - ****** LIVE WRITERS ****** - ******************************/ - -struct lwreg -{ - uint64_t iid; - uint64_t wr_iid; -}; - -struct lwregs -{ - struct ddsrt_ehh * regs; -}; - -static uint32_t lwreg_hash (const void *vl) -{ - const struct lwreg * l = vl; - return (uint32_t) (l->iid ^ l->wr_iid); -} - -static int lwreg_equals (const void *va, const void *vb) -{ - const struct lwreg * a = va; - const struct lwreg * b = vb; - return a->iid == b->iid && a->wr_iid == b->wr_iid; -} - -static void lwregs_init (struct lwregs *rt) -{ - rt->regs = ddsrt_ehh_new (sizeof (struct lwreg), 1, lwreg_hash, lwreg_equals); -} - -static void lwregs_fini (struct lwregs *rt) -{ - ddsrt_ehh_free (rt->regs); -} - -static int lwregs_contains (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) -{ - struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; - return ddsrt_ehh_lookup (rt->regs, &dummy) != NULL; -} - -static int lwregs_add (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) -{ - struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; - return ddsrt_ehh_add (rt->regs, &dummy); -} - -static int lwregs_delete (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) -{ - struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; - return ddsrt_ehh_remove (rt->regs, &dummy); -} - -void lwregs_dump (struct lwregs *rt) -{ - struct ddsrt_ehh_iter it; - for (struct lwreg *r = ddsrt_ehh_iter_first(rt->regs, &it); r; r = ddsrt_ehh_iter_next(&it)) - printf("iid=%"PRIu64" wr_iid=%"PRIu64"\n", r->iid, r->wr_iid); -} - -/************************* - ****** RHC ****** - *************************/ - -struct rhc_sample { - struct ddsi_serdata *sample; /* serialised data (either just_key or real data) */ - struct rhc_sample *next; /* next sample in time ordering, or oldest sample if most recent */ - uint64_t wr_iid; /* unique id for writer of this sample (perhaps better in serdata) */ - dds_querycond_mask_t conds; /* matching query conditions */ - bool isread; /* READ or NOT_READ sample state */ - unsigned disposed_gen; /* snapshot of instance counter at time of insertion */ - unsigned no_writers_gen; /* __/ */ -}; - -struct rhc_instance { - uint64_t iid; /* unique instance id, key of table, also serves as instance handle */ - uint64_t wr_iid; /* unique of id of writer of latest sample or 0; if wrcount = 0 it is the wr_iid that caused */ - struct rhc_sample *latest; /* latest received sample; circular list old->new; null if no sample */ - unsigned nvsamples; /* number of "valid" samples in instance */ - unsigned nvread; /* number of READ "valid" samples in instance (0 <= nvread <= nvsamples) */ - dds_querycond_mask_t conds; /* matching query conditions */ - uint32_t wrcount; /* number of live writers */ - unsigned isnew : 1; /* NEW or NOT_NEW view state */ - unsigned a_sample_free : 1; /* whether or not a_sample is in use */ - unsigned isdisposed : 1; /* DISPOSED or NOT_DISPOSED (if not disposed, wrcount determines ALIVE/NOT_ALIVE_NO_WRITERS) */ - unsigned wr_iid_islive : 1; /* whether wr_iid is of a live writer */ - unsigned inv_exists : 1; /* whether or not state change occurred since last sample (i.e., must return invalid sample) */ - unsigned inv_isread : 1; /* whether or not that state change has been read before */ - unsigned disposed_gen; /* bloody generation counters - worst invention of mankind */ - unsigned no_writers_gen; /* __/ */ - int32_t strength; /* "current" ownership strength */ - nn_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */ - nn_wctime_t tstamp; /* source time stamp of last update */ - struct rhc_instance *next; /* next non-empty instance in arbitrary ordering */ - struct rhc_instance *prev; - struct ddsi_tkmap_instance *tk; /* backref into TK for unref'ing */ - struct rhc_sample a_sample; /* pre-allocated storage for 1 sample */ -}; - -typedef enum rhc_store_result { - RHC_STORED, - RHC_FILTERED, - RHC_REJECTED -} rhc_store_result_t; - -struct rhc { - struct ddsrt_hh *instances; - struct rhc_instance *nonempty_instances; /* circular, points to most recently added one, NULL if none */ - struct lwregs registrations; /* should be a global one (with lock-free lookups) */ - - /* Instance/Sample maximums from resource limits QoS */ - - int32_t max_instances; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ - int32_t max_samples; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ - int32_t max_samples_per_instance; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ - - uint32_t n_instances; /* # instances, including empty [NOT USED] */ - uint32_t n_nonempty_instances; /* # non-empty instances */ - uint32_t n_not_alive_disposed; /* # disposed, non-empty instances [NOT USED] */ - uint32_t n_not_alive_no_writers; /* # not-alive-no-writers, non-empty instances [NOT USED] */ - uint32_t n_new; /* # new, non-empty instances [NOT USED] */ - uint32_t n_vsamples; /* # "valid" samples over all instances */ - uint32_t n_vread; /* # read "valid" samples over all instances [NOT USED] */ - uint32_t n_invsamples; /* # invalid samples over all instances [NOT USED] */ - uint32_t n_invread; /* # read invalid samples over all instances [NOT USED] */ - - bool by_source_ordering; /* true if BY_SOURCE, false if BY_RECEPTION */ - bool exclusive_ownership; /* true if EXCLUSIVE, false if SHARED */ - bool reliable; /* true if reliability RELIABLE */ - - dds_reader *reader; /* reader */ - const struct ddsi_sertopic *topic; /* topic description */ - unsigned history_depth; /* depth, 1 for KEEP_LAST_1, 2**32-1 for KEEP_ALL */ - - ddsrt_mutex_t lock; - dds_readcond * conds; /* List of associated read conditions */ - uint32_t nconds; /* Number of associated read conditions */ - uint32_t nqconds; /* Number of associated query conditions */ - dds_querycond_mask_t qconds_samplest; /* Mask of associated query conditions that check the sample state */ - void *qcond_eval_samplebuf; /* Temporary storage for evaluating query conditions, NULL if no qconds */ -}; - -struct trigger_info_cmn { - unsigned qminst; - bool has_read; - bool has_not_read; -}; - -struct trigger_info_pre { - struct trigger_info_cmn c; -}; - -struct trigger_info_qcond { - /* 0 or inst->conds depending on whether an invalid/valid sample was pushed out/added; - inc_xxx_read is there so read can indicate a sample changed from unread to read */ - bool dec_invsample_read; - bool dec_sample_read; - bool inc_invsample_read; - bool inc_sample_read; - dds_querycond_mask_t dec_conds_invsample; - dds_querycond_mask_t dec_conds_sample; - dds_querycond_mask_t inc_conds_invsample; - dds_querycond_mask_t inc_conds_sample; -}; - -struct trigger_info_post { - struct trigger_info_cmn c; -}; - -static unsigned qmask_of_sample (const struct rhc_sample *s) -{ - return s->isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; -} - -static unsigned qmask_of_invsample (const struct rhc_instance *i) -{ - return i->inv_isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; -} - -static uint32_t inst_nsamples (const struct rhc_instance *i) -{ - return i->nvsamples + i->inv_exists; -} - -static uint32_t inst_nread (const struct rhc_instance *i) -{ - return i->nvread + (uint32_t) (i->inv_exists & i->inv_isread); -} - -static bool inst_is_empty (const struct rhc_instance *i) -{ - return inst_nsamples (i) == 0; -} - -static bool inst_has_read (const struct rhc_instance *i) -{ - return inst_nread (i) > 0; -} - -static bool inst_has_unread (const struct rhc_instance *i) -{ - return inst_nread (i) < inst_nsamples (i); -} - -static void topicless_to_clean_invsample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim) -{ - /* ddsi_serdata_topicless_to_sample just deals with the key value, without paying any attention to attributes; - but that makes life harder for the user: the attributes of an invalid sample would be garbage, but would - nonetheless have to be freed in the end. Zero'ing it explicitly solves that problem. */ - ddsi_sertopic_free_sample (topic, sample, DDS_FREE_CONTENTS); - ddsi_sertopic_zero_sample (topic, sample); - ddsi_serdata_topicless_to_sample (topic, d, sample, bufptr, buflim); -} - -static unsigned qmask_of_inst (const struct rhc_instance *inst); -static bool update_conditions_locked (struct rhc *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst); -#ifndef NDEBUG -static int rhc_check_counts_locked (struct rhc *rhc, bool check_conds, bool check_qcmask); -#endif - -static uint32_t instance_iid_hash (const void *va) -{ - const struct rhc_instance *a = va; - return (uint32_t) a->iid; -} - -static int instance_iid_eq (const void *va, const void *vb) -{ - const struct rhc_instance *a = va; - const struct rhc_instance *b = vb; - return (a->iid == b->iid); -} - -static void add_inst_to_nonempty_list (struct rhc *rhc, struct rhc_instance *inst) -{ - if (rhc->nonempty_instances == NULL) - { - inst->next = inst->prev = inst; - } - else - { - struct rhc_instance * const hd = rhc->nonempty_instances; -#ifndef NDEBUG - { - const struct rhc_instance *x = hd; - do { assert (x != inst); x = x->next; } while (x != hd); - } -#endif - inst->next = hd->next; - inst->prev = hd; - hd->next = inst; - inst->next->prev = inst; - } - rhc->nonempty_instances = inst; - rhc->n_nonempty_instances++; -} - -static void remove_inst_from_nonempty_list (struct rhc *rhc, struct rhc_instance *inst) -{ - assert (inst_is_empty (inst)); -#ifndef NDEBUG - { - const struct rhc_instance *x = rhc->nonempty_instances; - assert (x); - do { if (x == inst) break; x = x->next; } while (x != rhc->nonempty_instances); - assert (x == inst); - } -#endif - - if (inst->next == inst) - { - rhc->nonempty_instances = NULL; - } - else - { - struct rhc_instance * const inst_prev = inst->prev; - struct rhc_instance * const inst_next = inst->next; - inst_prev->next = inst_next; - inst_next->prev = inst_prev; - if (rhc->nonempty_instances == inst) - rhc->nonempty_instances = inst_prev; - } - assert (rhc->n_nonempty_instances > 0); - rhc->n_nonempty_instances--; -} - -struct rhc * dds_rhc_new (dds_reader * reader, const struct ddsi_sertopic * topic) -{ - struct rhc * rhc = ddsrt_malloc (sizeof (*rhc)); - memset (rhc, 0, sizeof (*rhc)); - - lwregs_init (&rhc->registrations); - ddsrt_mutex_init (&rhc->lock); - rhc->instances = ddsrt_hh_new (1, instance_iid_hash, instance_iid_eq); - rhc->topic = topic; - rhc->reader = reader; - - return rhc; -} - -void dds_rhc_set_qos (struct rhc * rhc, const nn_xqos_t * qos) -{ - /* Set read related QoS */ - - rhc->max_samples = qos->resource_limits.max_samples; - rhc->max_instances = qos->resource_limits.max_instances; - rhc->max_samples_per_instance = qos->resource_limits.max_samples_per_instance; - rhc->by_source_ordering = (qos->destination_order.kind == NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS); - rhc->exclusive_ownership = (qos->ownership.kind == NN_EXCLUSIVE_OWNERSHIP_QOS); - rhc->reliable = (qos->reliability.kind == NN_RELIABLE_RELIABILITY_QOS); - assert(qos->history.kind != NN_KEEP_LAST_HISTORY_QOS || qos->history.depth > 0); - rhc->history_depth = (qos->history.kind == NN_KEEP_LAST_HISTORY_QOS) ? (uint32_t)qos->history.depth : ~0u; -} - -static bool eval_predicate_sample (const struct rhc *rhc, const struct ddsi_serdata *sample, bool (*pred) (const void *sample)) -{ - ddsi_serdata_to_sample (sample, rhc->qcond_eval_samplebuf, NULL, NULL); - bool ret = pred (rhc->qcond_eval_samplebuf); - return ret; -} - -static bool eval_predicate_invsample (const struct rhc *rhc, const struct rhc_instance *inst, bool (*pred) (const void *sample)) -{ - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, rhc->qcond_eval_samplebuf, NULL, NULL); - bool ret = pred (rhc->qcond_eval_samplebuf); - return ret; -} - -static struct rhc_sample *alloc_sample (struct rhc_instance *inst) -{ - if (inst->a_sample_free) - { - inst->a_sample_free = 0; -#if USE_VALGRIND - VALGRIND_MAKE_MEM_UNDEFINED (&inst->a_sample, sizeof (inst->a_sample)); -#endif - return &inst->a_sample; - } - else - { - /* This instead of sizeof(rhc_sample) gets us type checking */ - struct rhc_sample *s; - s = ddsrt_malloc (sizeof (*s)); - return s; - } -} - -static void free_sample (struct rhc_instance *inst, struct rhc_sample *s) -{ - ddsi_serdata_unref (s->sample); - if (s == &inst->a_sample) - { - assert (!inst->a_sample_free); -#if USE_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS (&inst->a_sample, sizeof (inst->a_sample)); -#endif - inst->a_sample_free = 1; - } - else - { - ddsrt_free (s); - } -} - -static void inst_clear_invsample (struct rhc *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc) -{ - assert (inst->inv_exists); - assert (trig_qc->dec_conds_invsample == 0); - inst->inv_exists = 0; - trig_qc->dec_conds_invsample = inst->conds; - if (inst->inv_isread) - { - trig_qc->dec_invsample_read = true; - rhc->n_invread--; - } - rhc->n_invsamples--; -} - -static void inst_clear_invsample_if_exists (struct rhc *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc) -{ - if (inst->inv_exists) - inst_clear_invsample (rhc, inst, trig_qc); -} - -static void inst_set_invsample (struct rhc *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc, bool *nda) -{ - if (!inst->inv_exists || inst->inv_isread) - { - /* Obviously optimisable, but that is perhaps not worth the bother */ - inst_clear_invsample_if_exists (rhc, inst, trig_qc); - assert (trig_qc->inc_conds_invsample == 0); - trig_qc->inc_conds_invsample = inst->conds; - inst->inv_exists = 1; - inst->inv_isread = 0; - rhc->n_invsamples++; - *nda = true; - } -} - -static void free_empty_instance (struct rhc_instance *inst) -{ - assert (inst_is_empty (inst)); - ddsi_tkmap_instance_unref (inst->tk); - ddsrt_free (inst); -} - -static void free_instance_rhc_free (struct rhc_instance *inst, struct rhc *rhc) -{ - struct rhc_sample *s = inst->latest; - const bool was_empty = inst_is_empty (inst); - struct trigger_info_qcond dummy_trig_qc; - if (s) - { - do { - struct rhc_sample * const s1 = s->next; - free_sample (inst, s); - s = s1; - } while (s != inst->latest); - rhc->n_vsamples -= inst->nvsamples; - rhc->n_vread -= inst->nvread; - inst->nvsamples = 0; - inst->nvread = 0; - } -#ifndef NDEBUG - memset (&dummy_trig_qc, 0, sizeof (dummy_trig_qc)); -#endif - inst_clear_invsample_if_exists (rhc, inst, &dummy_trig_qc); - if (!was_empty) - { - remove_inst_from_nonempty_list (rhc, inst); - } - ddsi_tkmap_instance_unref (inst->tk); - ddsrt_free (inst); -} - -uint32_t dds_rhc_lock_samples (struct rhc *rhc) -{ - uint32_t no; - ddsrt_mutex_lock (&rhc->lock); - no = rhc->n_vsamples + rhc->n_invsamples; - if (no == 0) - { - ddsrt_mutex_unlock (&rhc->lock); - } - return no; -} - -static void free_instance_rhc_free_wrap (void *vnode, void *varg) -{ - free_instance_rhc_free (vnode, varg); -} - -void dds_rhc_free (struct rhc *rhc) -{ - assert (rhc_check_counts_locked (rhc, true, true)); - ddsrt_hh_enum (rhc->instances, free_instance_rhc_free_wrap, rhc); - assert (rhc->nonempty_instances == NULL); - ddsrt_hh_free (rhc->instances); - lwregs_fini (&rhc->registrations); - if (rhc->qcond_eval_samplebuf != NULL) - ddsi_sertopic_free_sample (rhc->topic, rhc->qcond_eval_samplebuf, DDS_FREE_ALL); - ddsrt_mutex_destroy (&rhc->lock); - ddsrt_free (rhc); -} - -static void init_trigger_info_cmn_nonmatch (struct trigger_info_cmn *info) -{ - info->qminst = ~0u; - info->has_read = false; - info->has_not_read = false; -} - -static void get_trigger_info_cmn (struct trigger_info_cmn *info, struct rhc_instance *inst) -{ - info->qminst = qmask_of_inst (inst); - info->has_read = inst_has_read (inst); - info->has_not_read = inst_has_unread (inst); -} - -static void get_trigger_info_pre (struct trigger_info_pre *info, struct rhc_instance *inst) -{ - get_trigger_info_cmn (&info->c, inst); -} - -static void init_trigger_info_qcond (struct trigger_info_qcond *qc) -{ - qc->dec_invsample_read = false; - qc->dec_sample_read = false; - qc->inc_invsample_read = false; - qc->inc_sample_read = false; - qc->dec_conds_invsample = 0; - qc->dec_conds_sample = 0; - qc->inc_conds_invsample = 0; - qc->inc_conds_sample = 0; -} - -static bool trigger_info_differs (const struct rhc *rhc, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc) -{ - if (pre->c.qminst != post->c.qminst || - pre->c.has_read != post->c.has_read || - pre->c.has_not_read != post->c.has_not_read) - return true; - else if (rhc->nqconds == 0) - return false; - else - return (trig_qc->dec_conds_invsample != trig_qc->inc_conds_invsample || - trig_qc->dec_conds_sample != trig_qc->inc_conds_sample || - trig_qc->dec_invsample_read != trig_qc->inc_invsample_read || - trig_qc->dec_sample_read != trig_qc->inc_sample_read); -} - -static bool add_sample (struct rhc *rhc, struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc) -{ - struct rhc_sample *s; - - /* Adding a sample always clears an invalid sample (because the information - contained in the invalid sample - the instance state and the generation - counts - are included in the sample). While this would be place to do it, - we do it later to avoid having to roll back on allocation failure */ - - /* We don't do backfilling in BY_SOURCE mode -- we could, but - choose not to -- and having already filtered out samples - preceding inst->latest, we can simply insert it without any - searching */ - if (inst->nvsamples == rhc->history_depth) - { - /* replace oldest sample; latest points to the latest one, the - list is circular from old -> new, so latest->next is the oldest */ - - inst_clear_invsample_if_exists (rhc, inst, trig_qc); - assert (inst->latest != NULL); - s = inst->latest->next; - assert (trig_qc->dec_conds_sample == 0); - ddsi_serdata_unref (s->sample); - - trig_qc->dec_sample_read = s->isread; - trig_qc->dec_conds_sample = s->conds; - if (s->isread) - { - inst->nvread--; - rhc->n_vread--; - } - } - else - { - /* Check if resource max_samples QoS exceeded */ - - if (rhc->reader && rhc->max_samples != DDS_LENGTH_UNLIMITED && rhc->n_vsamples >= (uint32_t) rhc->max_samples) - { - cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; - cb_data->extra = DDS_REJECTED_BY_SAMPLES_LIMIT; - cb_data->handle = inst->iid; - cb_data->add = true; - return false; - } - - /* Check if resource max_samples_per_instance QoS exceeded */ - - if (rhc->reader && rhc->max_samples_per_instance != DDS_LENGTH_UNLIMITED && inst->nvsamples >= (uint32_t) rhc->max_samples_per_instance) - { - cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; - cb_data->extra = DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT; - cb_data->handle = inst->iid; - cb_data->add = true; - return false; - } - - /* add new latest sample */ - - s = alloc_sample (inst); - inst_clear_invsample_if_exists (rhc, inst, trig_qc); - if (inst->latest == NULL) - { - s->next = s; - } - else - { - s->next = inst->latest->next; - inst->latest->next = s; - } - inst->nvsamples++; - rhc->n_vsamples++; - } - - s->sample = ddsi_serdata_ref (sample); /* drops const (tho refcount does change) */ - s->wr_iid = pwr_info->iid; - s->isread = false; - s->disposed_gen = inst->disposed_gen; - s->no_writers_gen = inst->no_writers_gen; - - s->conds = 0; - if (rhc->nqconds != 0) - { - for (dds_readcond *rc = rhc->conds; rc != NULL; rc = rc->m_next) - if (rc->m_query.m_filter != 0 && eval_predicate_sample (rhc, s->sample, rc->m_query.m_filter)) - s->conds |= rc->m_query.m_qcmask; - } - - trig_qc->inc_conds_sample = s->conds; - inst->latest = s; - return true; -} - -static bool content_filter_accepts (const struct ddsi_sertopic *sertopic, const struct ddsi_serdata *sample) -{ - bool ret = true; - const struct dds_topic *tp = sertopic->status_cb_entity; - if (tp->filter_fn) - { - char *tmp = ddsi_sertopic_alloc_sample (sertopic); - ddsi_serdata_to_sample (sample, tmp, NULL, NULL); - ret = (tp->filter_fn) (tmp, tp->filter_ctx); - ddsi_sertopic_free_sample (sertopic, tmp, DDS_FREE_ALL); - } - return ret; -} - -static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info) -{ - return (inst->wr_iid_islive && inst->wr_iid == pwr_info->iid) || memcmp (&pwr_info->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0; -} - -static int inst_accepts_sample (const struct rhc *rhc, const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, const bool has_data) -{ - if (rhc->by_source_ordering) - { - if (sample->timestamp.v > inst->tstamp.v) - { - /* ok */ - } - else if (sample->timestamp.v < inst->tstamp.v) - { - return 0; - } - else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) - { - /* ok */ - } - else - { - return 0; - } - } - if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != pwr_info->iid) - { - int32_t strength = pwr_info->ownership_strength; - if (strength > inst->strength) { - /* ok */ - } else if (strength < inst->strength) { - return 0; - } else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) { - /* ok */ - } else { - return 0; - } - } - if (has_data && !content_filter_accepts (rhc->topic, sample)) - { - return 0; - } - return 1; -} - -static void update_inst (struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, bool wr_iid_valid, nn_wctime_t tstamp) -{ - inst->tstamp = tstamp; - inst->wr_iid_islive = wr_iid_valid; - if (wr_iid_valid) - { - inst->wr_iid = pwr_info->iid; - if (inst->wr_iid != pwr_info->iid) - inst->wr_guid = pwr_info->guid; - } - inst->strength = pwr_info->ownership_strength; -} - -static void drop_instance_noupdate_no_writers (struct rhc *rhc, struct rhc_instance *inst) -{ - int ret; - assert (inst_is_empty (inst)); - - rhc->n_instances--; - - ret = ddsrt_hh_remove (rhc->instances, inst); - assert (ret); - (void) ret; - - free_empty_instance (inst); -} - -static void dds_rhc_register (struct rhc *rhc, struct rhc_instance *inst, uint64_t wr_iid, bool iid_update) -{ - const uint64_t inst_wr_iid = inst->wr_iid_islive ? inst->wr_iid : 0; - - TRACE (" register:"); - - /* Is an implicitly registering dispose semantically equivalent to - register ; dispose? If so, both no_writers_gen and disposed_gen - need to be incremented if the old instance state was DISPOSED, - else just disposed_gen. (Shudder.) Interpreting it as - equivalent. - - Is a dispose a sample? I don't think so (though a write dispose - is). Is a pure register a sample? Don't think so either. */ - if (inst_wr_iid == wr_iid) - { - /* Same writer as last time => we know it is registered already. - This is the fast path -- we don't have to check anything - else. */ - TRACE ("cached"); - assert (inst->wrcount > 0); - return; - } - - if (inst->wrcount == 0) - { - /* Currently no writers at all */ - assert (!inst->wr_iid_islive); - - /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) - { - inst->wr_iid = wr_iid; - inst->wr_iid_islive = 1; - } - inst->wrcount++; - inst->no_writers_gen++; - TRACE ("new1"); - - if (!inst_is_empty (inst) && !inst->isdisposed) - rhc->n_not_alive_no_writers--; - } - else if (inst_wr_iid == 0 && inst->wrcount == 1) - { - /* Writers exist, but wr_iid is null => someone unregistered. - - With wrcount 1, if wr_iid happens to be the remaining writer, - we remove the explicit registration and once again rely on - inst->wr_iid, but if wr_iid happens to be a new writer, we - increment the writer count & explicitly register the second - one, too. - - If I decide on a global table of registrations implemented - using concurrent hopscotch-hashing, then this should still - scale well because lwregs_add first calls lwregs_contains, - which is lock-free. (Not that it probably can't be optimised - by a combined add-if-unknown-delete-if-known operation -- but - the value of that is likely negligible because the - registrations should be fairly stable.) */ - if (lwregs_add (&rhc->registrations, inst->iid, wr_iid)) - { - inst->wrcount++; - TRACE ("new2iidnull"); - } - else - { - int x = lwregs_delete (&rhc->registrations, inst->iid, wr_iid); - assert (x); - (void) x; - TRACE ("restore"); - } - /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) - { - inst->wr_iid = wr_iid; - inst->wr_iid_islive = 1; - } - } - else - { - /* As above -- if using concurrent hopscotch hashing, if the - writer is already known, lwregs_add is lock-free */ - if (inst->wrcount == 1) - { - /* 2nd writer => properly register the one we knew about */ - TRACE ("rescue1"); - int x; - x = lwregs_add (&rhc->registrations, inst->iid, inst_wr_iid); - assert (x); - (void) x; - } - if (lwregs_add (&rhc->registrations, inst->iid, wr_iid)) - { - /* as soon as we reach at least two writers, we have to check - the result of lwregs_add to know whether this sample - registers a previously unknown writer or not */ - TRACE ("new3"); - inst->wrcount++; - } - else - { - TRACE ("known"); - } - assert (inst->wrcount >= 2); - /* the most recent writer gets the fast path */ - /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) - { - inst->wr_iid = wr_iid; - inst->wr_iid_islive = 1; - } - } -} - -static void account_for_empty_to_nonempty_transition (struct rhc *rhc, struct rhc_instance *inst) -{ - assert (inst_nsamples (inst) == 1); - add_inst_to_nonempty_list (rhc, inst); - rhc->n_new += inst->isnew; - if (inst->isdisposed) - rhc->n_not_alive_disposed++; - else if (inst->wrcount == 0) - rhc->n_not_alive_no_writers++; -} - -static int rhc_unregister_isreg_w_sideeffects (struct rhc *rhc, const struct rhc_instance *inst, uint64_t wr_iid) -{ - /* Returns 1 if last registration just disappeared */ - if (inst->wrcount == 0) - { - TRACE ("unknown(#0)"); - return 0; - } - else if (inst->wrcount == 1 && inst->wr_iid_islive) - { - assert(inst->wr_iid != 0); - if (wr_iid != inst->wr_iid) - { - TRACE ("unknown(cache)"); - return 0; - } - else - { - TRACE ("last(cache)"); - return 1; - } - } - else if (!lwregs_delete (&rhc->registrations, inst->iid, wr_iid)) - { - TRACE ("unknown(regs)"); - return 0; - } - else - { - TRACE ("delreg"); - /* If we transition from 2 to 1 writer, and we are deleting a - writer other than the one cached in the instance, that means - afterward there will be 1 writer, it will be cached, and its - registration record must go (invariant that with wrcount = 1 - and wr_iid != 0 the wr_iid is not in "registrations") */ - if (inst->wrcount == 2 && inst->wr_iid_islive && inst->wr_iid != wr_iid) - { - TRACE (",delreg(remain)"); - lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid); - } - return 1; - } -} - -static int rhc_unregister_updateinst (struct rhc *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda) -{ - assert (inst->wrcount > 0); - - if (--inst->wrcount > 0) - { - if (inst->wr_iid_islive && pwr_info->iid == inst->wr_iid) - { - /* Next register will have to do real work before we have a cached - wr_iid again */ - inst->wr_iid_islive = 0; - - /* Reset the ownership strength to allow samples to be read from other - writer(s) */ - inst->strength = 0; - TRACE (",clearcache"); - } - return 0; - } - else - { - if (!inst_is_empty (inst)) - { - /* Instance still has content - do not drop until application - takes the last sample. Set the invalid sample if the latest - sample has been read already, so that the application can - read the change to not-alive. (If the latest sample is still - unread, we don't bother, even though it means the application - won't see the timestamp for the unregister event. It shouldn't - care.) */ - if (inst->latest == NULL || inst->latest->isread) - { - inst_set_invsample (rhc, inst, trig_qc, nda); - update_inst (inst, pwr_info, false, tstamp); - } - if (!inst->isdisposed) - { - rhc->n_not_alive_no_writers++; - } - inst->wr_iid_islive = 0; - return 0; - } - else if (inst->isdisposed) - { - /* No content left, no registrations left, so drop */ - TRACE (",#0,empty,disposed,drop"); - drop_instance_noupdate_no_writers (rhc, inst); - return 1; - } - else - { - /* Add invalid samples for transition to no-writers */ - TRACE (",#0,empty,nowriters"); - assert (inst_is_empty (inst)); - inst_set_invsample (rhc, inst, trig_qc, nda); - update_inst (inst, pwr_info, false, tstamp); - account_for_empty_to_nonempty_transition (rhc, inst); - inst->wr_iid_islive = 0; - return 0; - } - } -} - -static bool dds_rhc_unregister (struct rhc *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) -{ - bool notify_data_available = false; - - /* 'post' always gets set; instance may have been freed upon return. */ - TRACE (" unregister:"); - if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, pwr_info->iid)) - { - /* other registrations remain */ - get_trigger_info_cmn (&post->c, inst); - } - else if (rhc_unregister_updateinst (rhc, inst, pwr_info, tstamp, trig_qc, ¬ify_data_available)) - { - /* instance dropped */ - init_trigger_info_cmn_nonmatch (&post->c); - } - else - { - /* no writers remain, but instance not empty */ - get_trigger_info_cmn (&post->c, inst); - } - return notify_data_available; -} - -static struct rhc_instance *alloc_new_instance (const struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) -{ - struct rhc_instance *inst; - - ddsi_tkmap_instance_ref (tk); - inst = ddsrt_malloc (sizeof (*inst)); - memset (inst, 0, sizeof (*inst)); - inst->iid = tk->m_iid; - inst->tk = tk; - inst->wrcount = (serdata->statusinfo & NN_STATUSINFO_UNREGISTER) ? 0 : 1; - inst->isdisposed = (serdata->statusinfo & NN_STATUSINFO_DISPOSE) != 0; - inst->isnew = 1; - inst->a_sample_free = 1; - inst->conds = 0; - inst->wr_iid = pwr_info->iid; - inst->wr_iid_islive = (inst->wrcount != 0); - inst->wr_guid = pwr_info->guid; - inst->tstamp = serdata->timestamp; - inst->strength = pwr_info->ownership_strength; - - if (rhc->nqconds != 0) - { - for (dds_readcond *c = rhc->conds; c != NULL; c = c->m_next) - { - assert ((dds_entity_kind (&c->m_entity) == DDS_KIND_COND_READ && c->m_query.m_filter == 0) || - (dds_entity_kind (&c->m_entity) == DDS_KIND_COND_QUERY && c->m_query.m_filter != 0)); - if (c->m_query.m_filter && eval_predicate_invsample (rhc, inst, c->m_query.m_filter)) - inst->conds |= c->m_query.m_qcmask; - } - } - - return inst; -} - -static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) -{ - struct rhc_instance *inst; - int ret; - - /* New instance for this reader. May still filter out key value. - - Doing the filtering here means avoiding filter processing in - the normal case of accepting data, accepting some extra - overhead in the case where the data would be filtered out. - Naturally using an avl tree is not so smart for these IIDs, and - if the AVL tree is replaced by a hash table, the overhead - trade-off should be quite nice with the filtering code right - here. - - Note: never instantiating based on a sample that's filtered out, - though one could argue that if it is rejected based on an - attribute (rather than a key), an empty instance should be - instantiated. */ - - if (has_data && !content_filter_accepts (rhc->topic, sample)) - { - return RHC_FILTERED; - } - /* Check if resource max_instances QoS exceeded */ - - if (rhc->reader && rhc->max_instances != DDS_LENGTH_UNLIMITED && rhc->n_instances >= (uint32_t) rhc->max_instances) - { - cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; - cb_data->extra = DDS_REJECTED_BY_INSTANCES_LIMIT; - cb_data->handle = tk->m_iid; - cb_data->add = true; - return RHC_REJECTED; - } - - inst = alloc_new_instance (rhc, pwr_info, sample, tk); - if (has_data) - { - if (!add_sample (rhc, inst, pwr_info, sample, cb_data, trig_qc)) - { - free_empty_instance (inst); - return RHC_REJECTED; - } - } - else - { - if (inst->isdisposed) { - bool nda_dummy = false; - inst_set_invsample (rhc, inst, trig_qc, &nda_dummy); - } - } - - account_for_empty_to_nonempty_transition (rhc, inst); - ret = ddsrt_hh_add (rhc->instances, inst); - assert (ret); - (void) ret; - rhc->n_instances++; - get_trigger_info_cmn (&post->c, inst); - - *out_inst = inst; - return RHC_STORED; -} - -/* - dds_rhc_store: DDSI up call into read cache to store new sample. Returns whether sample - delivered (true unless a reliable sample rejected). -*/ - -bool dds_rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) -{ - const uint64_t wr_iid = pwr_info->iid; - const unsigned statusinfo = sample->statusinfo; - const bool has_data = (sample->kind == SDK_DATA); - const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0; - struct rhc_instance dummy_instance; - struct rhc_instance *inst; - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - bool trigger_waitsets; - rhc_store_result_t stored; - status_cb_data_t cb_data; /* Callback data for reader status callback */ - bool delivered = true; - bool notify_data_available = false; - - TRACE ("rhc_store(%"PRIx64",%"PRIx64" si %x has_data %d:", tk->m_iid, wr_iid, statusinfo, has_data); - if (!has_data && statusinfo == 0) - { - /* Write with nothing but a key -- I guess that would be a - register, which we do implicitly. (Currently DDSI2 won't allow - it through anyway.) */ - TRACE (" ignore explicit register)\n"); - return delivered; - } - - dummy_instance.iid = tk->m_iid; - stored = RHC_FILTERED; - cb_data.raw_status_id = -1; - - init_trigger_info_qcond (&trig_qc); - - ddsrt_mutex_lock (&rhc->lock); - - inst = ddsrt_hh_lookup (rhc->instances, &dummy_instance); - if (inst == NULL) - { - /* New instance for this reader. If no data content -- not (also) - a write -- ignore it, I think we can get away with ignoring dispose or unregisters - on unknown instances. - */ - if (!has_data && !is_dispose) - { - TRACE (" disp/unreg on unknown instance"); - goto error_or_nochange; - } - else - { - TRACE (" new instance"); - stored = rhc_store_new_instance (&inst, rhc, pwr_info, sample, tk, has_data, &cb_data, &post, &trig_qc); - if (stored != RHC_STORED) - { - goto error_or_nochange; - } - init_trigger_info_cmn_nonmatch (&pre.c); - notify_data_available = true; - } - } - else if (!inst_accepts_sample (rhc, inst, pwr_info, sample, has_data)) - { - /* Rejected samples (and disposes) should still register the writer; - unregister *must* be processed, or we have a memory leak. (We - will raise a SAMPLE_REJECTED, and indicate that the system should - kill itself.) Not letting instances go to ALIVE or NEW based on - a rejected sample - (no one knows, it seemed) */ - TRACE (" instance rejects sample"); - - get_trigger_info_pre (&pre, inst); - if (has_data || is_dispose) - { - dds_rhc_register (rhc, inst, wr_iid, false); - } - if (statusinfo & NN_STATUSINFO_UNREGISTER) - { - if (dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc)) - notify_data_available = true; - } - else - { - get_trigger_info_cmn (&post.c, inst); - } - /* notify sample lost */ - - cb_data.raw_status_id = (int) DDS_SAMPLE_LOST_STATUS_ID; - cb_data.extra = 0; - cb_data.handle = 0; - cb_data.add = true; - goto error_or_nochange; - - /* FIXME: deadline (and other) QoS? */ - } - else - { - get_trigger_info_pre (&pre, inst); - - TRACE (" wc %"PRIu32, inst->wrcount); - - if (has_data || is_dispose) - { - /* View state must be NEW following receipt of a sample when - instance was NOT_ALIVE (whether DISPOSED or NO_WRITERS). - Once we start fiddling with the state, we can no longer - figure out whether it is alive or not, so determine whether - it is currently NOT_ALIVE. */ - const int not_alive = inst->wrcount == 0 || inst->isdisposed; - const bool old_isdisposed = inst->isdisposed; - const bool old_isnew = inst->isnew; - const bool was_empty = inst_is_empty (inst); - int inst_became_disposed = 0; - - /* Not just an unregister, so a write and/or a dispose (possibly - combined with an unregister). Write & dispose create a - registration and we always do that, even if we have to delete - it immediately afterward. It seems unlikely to be worth the - effort of optimising this, but it can be done. On failure - (i.e., out-of-memory), abort the operation and hope that the - caller can still notify the application. */ - - dds_rhc_register (rhc, inst, wr_iid, true); - - /* Sample arriving for a NOT_ALIVE instance => view state NEW */ - if (has_data && not_alive) - { - TRACE (" notalive->alive"); - inst->isnew = 1; - } - - /* Desired effect on instance state and disposed_gen: - op DISPOSED NOT_DISPOSED - W ND;gen++ ND - D D D - WD D;gen++ D - Simplest way is to toggle istate when it is currently DISPOSED - and the operation is WD. */ - if (has_data && inst->isdisposed) - { - TRACE (" disposed->notdisposed"); - inst->isdisposed = 0; - inst->disposed_gen++; - } - if (is_dispose) - { - inst->isdisposed = 1; - inst_became_disposed = !old_isdisposed; - TRACE (" dispose(%d)", inst_became_disposed); - } - - /* Only need to add a sample to the history if the input actually - is a sample. */ - if (has_data) - { - TRACE (" add_sample"); - if (!add_sample (rhc, inst, pwr_info, sample, &cb_data, &trig_qc)) - { - TRACE ("(reject)"); - stored = RHC_REJECTED; - - /* FIXME: fix the bad rejection handling, probably put back in a proper rollback, until then a band-aid like this will have to do: */ - inst->isnew = old_isnew; - inst->isdisposed = old_isdisposed; - if (old_isdisposed) - inst->disposed_gen--; - goto error_or_nochange; - } - notify_data_available = true; - } - - /* If instance became disposed, add an invalid sample if there are no samples left */ - if (inst_became_disposed && inst->latest == NULL) - inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); - - update_inst (inst, pwr_info, true, sample->timestamp); - - /* Can only add samples => only need to give special treatment - to instances that were empty before. It is, however, not - guaranteed that we end up with a non-empty instance: for - example, if the instance was disposed & empty, nothing - changes. */ - if (inst->latest || inst_became_disposed) - { - if (was_empty) - { - /* general function is slightly slower than a specialised - one, but perhaps it is wiser to use the general one */ - account_for_empty_to_nonempty_transition (rhc, inst); - } - else - { - rhc->n_not_alive_disposed += (uint32_t)(inst->isdisposed - old_isdisposed); - rhc->n_new += (uint32_t)(inst->isnew - old_isnew); - } - } - else - { - assert (inst_is_empty (inst) == was_empty); - } - } - - assert (rhc_check_counts_locked (rhc, false, false)); - - if (statusinfo & NN_STATUSINFO_UNREGISTER) - { - /* Either a pure unregister, or the instance rejected the sample - because of time stamps, content filter, or something else. If - the writer unregisters the instance, I think we should ignore - the acceptance filters and process it anyway. - - It is a bit unclear what - - write_w_timestamp(x,1) ; unregister_w_timestamp(x,0) - - actually means if BY_SOURCE ordering is selected: does that - mean an application reading "x" after the write and reading it - again after the unregister will see a change in the - no_writers_generation field? */ - dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc); - } - else - { - get_trigger_info_cmn (&post.c, inst); - } - } - - TRACE (")\n"); - - trigger_waitsets = trigger_info_differs (rhc, &pre, &post, &trig_qc) && update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst); - - assert (rhc_check_counts_locked (rhc, true, true)); - - ddsrt_mutex_unlock (&rhc->lock); - - if (rhc->reader) - { - if (notify_data_available) - dds_reader_data_available_cb (rhc->reader); - if (trigger_waitsets) - dds_entity_status_signal (&rhc->reader->m_entity); - } - - return delivered; - -error_or_nochange: - - if (rhc->reliable && (stored == RHC_REJECTED)) - { - delivered = false; - } - - ddsrt_mutex_unlock (&rhc->lock); - TRACE (")\n"); - - /* Make any reader status callback */ - - if (cb_data.raw_status_id >= 0 && rhc->reader) - dds_reader_status_cb (&rhc->reader->m_entity, &cb_data); - return delivered; -} - -void dds_rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) -{ - /* Only to be called when writer with ID WR_IID has died. - - If we require that it will NEVER be resurrected, i.e., that next - time a new WR_IID will be used for the same writer, then we have - all the time in the world to scan the cache & clean up and that - we don't have to keep it locked all the time (even if we do it - that way now). - - WR_IID was never reused while the built-in topics weren't getting - generated, but those really require the same instance id for the - same GUID if an instance still exists in some reader for that GUID. - So, if unregistration without locking the RHC is desired, entities - need to get two IIDs: the one visible to the application in the - built-in topics and in get_instance_handle, and one used internally - for tracking registrations and unregistrations. */ - bool trigger_waitsets = false; - bool notify_data_available = false; - struct rhc_instance *inst; - struct ddsrt_hh_iter iter; - const uint64_t wr_iid = pwr_info->iid; - const int auto_dispose = pwr_info->auto_dispose; - - ddsrt_mutex_lock (&rhc->lock); - TRACE ("rhc_unregister_wr_iid(%"PRIx64",%d:\n", wr_iid, auto_dispose); - for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) - { - if ((inst->wr_iid_islive && inst->wr_iid == wr_iid) || lwregs_contains (&rhc->registrations, inst->iid, wr_iid)) - { - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - TRACE (" %"PRIx64":", inst->iid); - - assert (inst->wrcount > 0); - if (auto_dispose && !inst->isdisposed) - { - inst->isdisposed = 1; - - /* Set invalid sample for disposing it (unregister may also set it for unregistering) */ - if (inst->latest) - { - assert (!inst->inv_exists); - rhc->n_not_alive_disposed++; - } - else - { - const bool was_empty = inst_is_empty (inst); - inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); - if (was_empty) - account_for_empty_to_nonempty_transition (rhc, inst); - else - rhc->n_not_alive_disposed++; - } - } - - dds_rhc_unregister (rhc, inst, pwr_info, inst->tstamp, &post, &trig_qc); - - TRACE ("\n"); - - notify_data_available = true; - if (trigger_info_differs (rhc, &pre, &post, &trig_qc) && update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst)) - trigger_waitsets = true; - assert (rhc_check_counts_locked (rhc, true, false)); - } - } - TRACE (")\n"); - - ddsrt_mutex_unlock (&rhc->lock); - - if (rhc->reader) - { - if (notify_data_available) - dds_reader_data_available_cb (rhc->reader); - if (trigger_waitsets) - dds_entity_status_signal (&rhc->reader->m_entity); - } -} - -void dds_rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid) -{ - struct rhc_instance *inst; - struct ddsrt_hh_iter iter; - ddsrt_mutex_lock (&rhc->lock); - TRACE ("rhc_relinquish_ownership(%"PRIx64":\n", wr_iid); - for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) - { - if (inst->wr_iid_islive && inst->wr_iid == wr_iid) - { - inst->wr_iid_islive = 0; - } - } - TRACE (")\n"); - assert (rhc_check_counts_locked (rhc, true, false)); - ddsrt_mutex_unlock (&rhc->lock); -} - -/* STATUSES: - - sample: ANY, READ, NOT_READ - view: ANY, NEW, NOT_NEW - instance: ANY, ALIVE, NOT_ALIVE, NOT_ALIVE_NO_WRITERS, NOT_ALIVE_DISPOSED -*/ - -static unsigned qmask_of_inst (const struct rhc_instance *inst) -{ - unsigned qm = inst->isnew ? DDS_NEW_VIEW_STATE : DDS_NOT_NEW_VIEW_STATE; - - if (inst->isdisposed) - qm |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; - else if (inst->wrcount > 0) - qm |= DDS_ALIVE_INSTANCE_STATE; - else - qm |= DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; - - return qm; -} - -static unsigned qmask_from_dcpsquery (unsigned sample_states, unsigned view_states, unsigned instance_states) -{ - unsigned qminv = 0; - - switch ((dds_sample_state_t) sample_states) - { - case DDS_SST_READ: - qminv |= DDS_NOT_READ_SAMPLE_STATE; - break; - case DDS_SST_NOT_READ: - qminv |= DDS_READ_SAMPLE_STATE; - break; - } - switch ((dds_view_state_t) view_states) - { - case DDS_VST_NEW: - qminv |= DDS_NOT_NEW_VIEW_STATE; - break; - case DDS_VST_OLD: - qminv |= DDS_NEW_VIEW_STATE; - break; - } - switch (instance_states) - { - case DDS_IST_ALIVE: - qminv |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE | DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; - break; - case DDS_IST_ALIVE | DDS_IST_NOT_ALIVE_DISPOSED: - qminv |= DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; - break; - case DDS_IST_ALIVE | DDS_IST_NOT_ALIVE_NO_WRITERS: - qminv |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; - break; - case DDS_IST_NOT_ALIVE_DISPOSED: - qminv |= DDS_ALIVE_INSTANCE_STATE | DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; - break; - case DDS_IST_NOT_ALIVE_DISPOSED | DDS_IST_NOT_ALIVE_NO_WRITERS: - qminv |= DDS_ALIVE_INSTANCE_STATE; - break; - case DDS_IST_NOT_ALIVE_NO_WRITERS: - qminv |= DDS_ALIVE_INSTANCE_STATE | DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; - break; - } - return qminv; -} - -static unsigned qmask_from_mask_n_cond(uint32_t mask, dds_readcond* cond) -{ - unsigned qminv; - if (mask == NO_STATE_MASK_SET) { - if (cond) { - /* No mask set, use the one from the condition. */ - qminv = cond->m_qminv; - } else { - /* No mask set and no condition: read all. */ - qminv = qmask_from_dcpsquery(DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE); - } - } else { - /* Merge given mask with the condition mask when needed. */ - qminv = qmask_from_dcpsquery(mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE); - if (cond != NULL) { - qminv &= cond->m_qminv; - } - } - return qminv; -} - -static void set_sample_info (dds_sample_info_t *si, const struct rhc_instance *inst, const struct rhc_sample *sample) -{ - si->sample_state = sample->isread ? DDS_SST_READ : DDS_SST_NOT_READ; - si->view_state = inst->isnew ? DDS_VST_NEW : DDS_VST_OLD; - si->instance_state = inst->isdisposed ? DDS_IST_NOT_ALIVE_DISPOSED : (inst->wrcount == 0) ? DDS_IST_NOT_ALIVE_NO_WRITERS : DDS_IST_ALIVE; - si->instance_handle = inst->iid; - si->publication_handle = sample->wr_iid; - si->disposed_generation_count = sample->disposed_gen; - si->no_writers_generation_count = sample->no_writers_gen; - si->sample_rank = 0; /* patch afterward: don't know last sample in returned set yet */ - si->generation_rank = 0; /* __/ */ - si->absolute_generation_rank = (inst->disposed_gen + inst->no_writers_gen) - (sample->disposed_gen + sample->no_writers_gen); - si->valid_data = true; - si->source_timestamp = sample->sample->timestamp.v; -} - -static void set_sample_info_invsample (dds_sample_info_t *si, const struct rhc_instance *inst) -{ - si->sample_state = inst->inv_isread ? DDS_SST_READ : DDS_SST_NOT_READ; - si->view_state = inst->isnew ? DDS_VST_NEW : DDS_VST_OLD; - si->instance_state = inst->isdisposed ? DDS_IST_NOT_ALIVE_DISPOSED : (inst->wrcount == 0) ? DDS_IST_NOT_ALIVE_NO_WRITERS : DDS_IST_ALIVE; - si->instance_handle = inst->iid; - si->publication_handle = inst->wr_iid; - si->disposed_generation_count = inst->disposed_gen; - si->no_writers_generation_count = inst->no_writers_gen; - si->sample_rank = 0; /* by construction always last in the set (but will get patched) */ - si->generation_rank = 0; /* __/ */ - si->absolute_generation_rank = 0; - si->valid_data = false; - si->source_timestamp = inst->tstamp.v; -} - -static void patch_generations (dds_sample_info_t *si, uint32_t last_of_inst) -{ - if (last_of_inst > 0) - { - const unsigned ref = - si[last_of_inst].disposed_generation_count + si[last_of_inst].no_writers_generation_count; - uint32_t i; - assert (si[last_of_inst].sample_rank == 0); - assert (si[last_of_inst].generation_rank == 0); - for (i = 0; i < last_of_inst; i++) - { - si[i].sample_rank = last_of_inst - i; - si[i].generation_rank = ref - (si[i].disposed_generation_count + si[i].no_writers_generation_count); - } - } -} - -static bool read_sample_update_conditions (struct rhc *rhc, struct trigger_info_pre *pre, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, struct rhc_instance *inst, dds_querycond_mask_t conds, bool sample_wasread) -{ - /* No query conditions that are dependent on sample states */ - if (rhc->qconds_samplest == 0) - return false; - - /* Some, but perhaps none that matches this sample */ - if ((conds & rhc->qconds_samplest) == 0) - return false; - - TRACE("read_sample_update_conditions\n"); - trig_qc->dec_conds_sample = trig_qc->inc_conds_sample = conds; - trig_qc->dec_sample_read = sample_wasread; - trig_qc->inc_sample_read = true; - get_trigger_info_cmn (&post->c, inst); - const bool trigger_waitsets = update_conditions_locked (rhc, false, pre, post, trig_qc, inst); - trig_qc->dec_conds_sample = trig_qc->inc_conds_sample = 0; - pre->c = post->c; - return trigger_waitsets; -} - -static bool take_sample_update_conditions (struct rhc *rhc, struct trigger_info_pre *pre, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, struct rhc_instance *inst, dds_querycond_mask_t conds, bool sample_wasread) -{ - /* Mostly the same as read_...: but we are deleting samples (so no "inc sample") and need to process all query conditions that match this sample. */ - if (rhc->nqconds == 0 || conds == 0) - return false; - - TRACE("take_sample_update_conditions\n"); - trig_qc->dec_conds_sample = conds; - trig_qc->dec_sample_read = sample_wasread; - get_trigger_info_cmn (&post->c, inst); - const bool trigger_waitsets = update_conditions_locked (rhc, false, pre, post, trig_qc, inst); - trig_qc->dec_conds_sample = 0; - pre->c = post->c; - return trigger_waitsets; -} - -static int dds_rhc_read_w_qminv (struct rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) -{ - bool trigger_waitsets = false; - uint32_t n = 0; - - if (lock) - { - ddsrt_mutex_lock (&rhc->lock); - } - - TRACE ("read_w_qminv(%p,%p,%p,%"PRIu32",%x,%p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void *) rhc, (void *) values, (void *) info_seq, max_samples, qminv, (void *) cond, - rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, - rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, - rhc->n_vread, rhc->n_invread); - - if (rhc->nonempty_instances) - { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance * inst = rhc->nonempty_instances->next; - struct rhc_instance * const end = inst; - do - { - if (handle == DDS_HANDLE_NIL || inst->iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - /* samples present & instance, view state matches */ - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - const unsigned nread = inst_nread (inst); - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end1 = sample; - do - { - if ((qmask_of_sample (sample) & qminv) == 0 && (qcmask == 0 || (sample->conds & qcmask))) - { - /* sample state matches too */ - set_sample_info (info_seq + n, inst, sample); - ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); - if (!sample->isread) - { - TRACE ("s"); - if (read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, false)) - trigger_waitsets = true; - sample->isread = true; - inst->nvread++; - rhc->n_vread++; - } - if (++n == max_samples) - { - break; - } - } - sample = sample->next; - } - while (sample != end1); - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask))) - { - set_sample_info_invsample (info_seq + n, inst); - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); - if (!inst->inv_isread) - { - TRACE ("i"); - if (read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, false)) - trigger_waitsets = true; - inst->inv_isread = 1; - rhc->n_invread++; - } - ++n; - } - - bool inst_became_old = false; - if (n > n_first && inst->isnew) - { - inst_became_old = true; - inst->isnew = 0; - rhc->n_new--; - } - if (nread != inst_nread (inst) || inst_became_old) - { - get_trigger_info_cmn (&post.c, inst); - assert (trig_qc.dec_conds_invsample == 0); - assert (trig_qc.dec_conds_sample == 0); - assert (trig_qc.inc_conds_invsample == 0); - assert (trig_qc.inc_conds_sample == 0); - if (update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst)) - trigger_waitsets = true; - } - - if (n > n_first) { - patch_generations (info_seq + n_first, n - n_first - 1); - } - } - if (inst->iid == handle) - { - break; - } - } - inst = inst->next; - } - while (inst != end && n < max_samples); - } - TRACE ("read: returning %"PRIu32"\n", n); - assert (rhc_check_counts_locked (rhc, true, false)); - ddsrt_mutex_unlock (&rhc->lock); - - if (trigger_waitsets) - dds_entity_status_signal (&rhc->reader->m_entity); - - assert (n <= INT_MAX); - return (int)n; -} - -static int dds_rhc_take_w_qminv (struct rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) -{ - bool trigger_waitsets = false; - uint64_t iid; - uint32_t n = 0; - - if (lock) - { - ddsrt_mutex_lock (&rhc->lock); - } - - TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, - rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, - rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, - rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - - if (rhc->nonempty_instances) - { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance *inst = rhc->nonempty_instances->next; - unsigned n_insts = rhc->n_nonempty_instances; - while (n_insts-- > 0 && n < max_samples) - { - struct rhc_instance * const inst1 = inst->next; - iid = inst->iid; - if (handle == DDS_HANDLE_NIL || iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - unsigned nvsamples = inst->nvsamples; - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *psample = inst->latest; - struct rhc_sample *sample = psample->next; - while (nvsamples--) - { - struct rhc_sample * const sample1 = sample->next; - - if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask != 0 && !(sample->conds & qcmask))) - { - /* sample mask doesn't match, or content predicate doesn't match */ - psample = sample; - } - else - { - if (take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread)) - trigger_waitsets = true; - - set_sample_info (info_seq + n, inst, sample); - ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); - rhc->n_vsamples--; - if (sample->isread) - { - inst->nvread--; - rhc->n_vread--; - } - - if (--inst->nvsamples > 0) - { - if (inst->latest == sample) - inst->latest = psample; - psample->next = sample1; - } - else - { - inst->latest = NULL; - } - - free_sample (inst, sample); - - if (++n == max_samples) - { - break; - } - } - sample = sample1; - } - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) - { - struct trigger_info_qcond dummy_trig_qc; -#ifndef NDEBUG - init_trigger_info_qcond (&dummy_trig_qc); -#endif - if (take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread)) - trigger_waitsets = true; - set_sample_info_invsample (info_seq + n, inst); - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); - inst_clear_invsample (rhc, inst, &dummy_trig_qc); - ++n; - } - - if (n > n_first && inst->isnew) - { - inst->isnew = 0; - rhc->n_new--; - } - - if (n > n_first) - { - /* if nsamples = 0, it won't match anything, so no need to do - anything here for drop_instance_noupdate_no_writers */ - get_trigger_info_cmn (&post.c, inst); - assert (trig_qc.dec_conds_invsample == 0); - assert (trig_qc.dec_conds_sample == 0); - assert (trig_qc.inc_conds_invsample == 0); - assert (trig_qc.inc_conds_sample == 0); - if (update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst)) - trigger_waitsets = true; - } - - if (inst_is_empty (inst)) - { - remove_inst_from_nonempty_list (rhc, inst); - - if (inst->isdisposed) - { - rhc->n_not_alive_disposed--; - } - if (inst->wrcount == 0) - { - TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); - if (!inst->isdisposed) - { - /* disposed has priority over no writers (why not just 2 bits?) */ - rhc->n_not_alive_no_writers--; - } - drop_instance_noupdate_no_writers (rhc, inst); - } - } - - if (n > n_first) - patch_generations (info_seq + n_first, n - n_first - 1); - } - if (iid == handle) - { - break; - } - } - inst = inst1; - } - } - TRACE ("take: returning %"PRIu32"\n", n); - assert (rhc_check_counts_locked (rhc, true, false)); - ddsrt_mutex_unlock (&rhc->lock); - - if (trigger_waitsets) - dds_entity_status_signal(&rhc->reader->m_entity); - - assert (n <= INT_MAX); - return (int)n; -} - -static int dds_rhc_takecdr_w_qminv (struct rhc *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) -{ - bool trigger_waitsets = false; - uint64_t iid; - uint32_t n = 0; - (void)cond; - - if (lock) - { - ddsrt_mutex_lock (&rhc->lock); - } - - TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, - rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, - rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, - rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - - if (rhc->nonempty_instances) - { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance *inst = rhc->nonempty_instances->next; - unsigned n_insts = rhc->n_nonempty_instances; - while (n_insts-- > 0 && n < max_samples) - { - struct rhc_instance * const inst1 = inst->next; - iid = inst->iid; - if (handle == DDS_HANDLE_NIL || iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - unsigned nvsamples = inst->nvsamples; - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *psample = inst->latest; - struct rhc_sample *sample = psample->next; - while (nvsamples--) - { - struct rhc_sample * const sample1 = sample->next; - - if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask && !(sample->conds & qcmask))) - { - psample = sample; - } - else - { - if (take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread)) - trigger_waitsets = true; - - set_sample_info (info_seq + n, inst, sample); - values[n] = ddsi_serdata_ref(sample->sample); - rhc->n_vsamples--; - if (sample->isread) - { - inst->nvread--; - rhc->n_vread--; - } - - if (--inst->nvsamples > 0) - psample->next = sample1; - else - inst->latest = NULL; - - free_sample (inst, sample); - - if (++n == max_samples) - { - break; - } - } - sample = sample1; - } - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) - { - struct trigger_info_qcond dummy_trig_qc; -#ifndef NDEBUG - init_trigger_info_qcond (&dummy_trig_qc); -#endif - if (take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread)) - trigger_waitsets = true; - set_sample_info_invsample (info_seq + n, inst); - values[n] = ddsi_serdata_ref(inst->tk->m_sample); - inst_clear_invsample (rhc, inst, &dummy_trig_qc); - ++n; - } - - if (n > n_first && inst->isnew) - { - inst->isnew = 0; - rhc->n_new--; - } - - if (n > n_first) - { - /* if nsamples = 0, it won't match anything, so no need to do - anything here for drop_instance_noupdate_no_writers */ - get_trigger_info_cmn (&post.c, inst); - if (update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst)) - trigger_waitsets = true; - } - - if (inst_is_empty (inst)) - { - remove_inst_from_nonempty_list (rhc, inst); - - if (inst->isdisposed) - { - rhc->n_not_alive_disposed--; - } - if (inst->wrcount == 0) - { - TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); - if (!inst->isdisposed) - { - /* disposed has priority over no writers (why not just 2 bits?) */ - rhc->n_not_alive_no_writers--; - } - drop_instance_noupdate_no_writers (rhc, inst); - } - } - - if (n > n_first) - patch_generations (info_seq + n_first, n - n_first - 1); - } - if (iid == handle) - { - break; - } - } - inst = inst1; - } - } - TRACE ("take: returning %"PRIu32"\n", n); - assert (rhc_check_counts_locked (rhc, true, false)); - ddsrt_mutex_unlock (&rhc->lock); - - if (trigger_waitsets) - dds_entity_status_signal (&rhc->reader->m_entity); - - assert (n <= INT_MAX); - return (int)n; -} - -/************************* - ****** WAITSET ****** - *************************/ - -static uint32_t rhc_get_cond_trigger (struct rhc_instance * const inst, const dds_readcond * const c) -{ - assert (!inst_is_empty (inst)); - bool m = ((qmask_of_inst (inst) & c->m_qminv) == 0); - switch (c->m_sample_states) - { - case DDS_SST_READ: - m = m && inst_has_read (inst); - break; - case DDS_SST_NOT_READ: - m = m && inst_has_unread (inst); - break; - case DDS_SST_READ | DDS_SST_NOT_READ: - case 0: - /* note: we get here only if inst not empty, so this is a no-op */ - m = m && !inst_is_empty (inst); - break; - default: - DDS_FATAL("update_readconditions: sample_states invalid: %"PRIx32"\n", c->m_sample_states); - } - return m ? 1 : 0; -} - -static bool cond_is_sample_state_dependent (const struct dds_readcond *cond) -{ - switch (cond->m_sample_states) - { - case DDS_SST_READ: - case DDS_SST_NOT_READ: - return true; - case DDS_SST_READ | DDS_SST_NOT_READ: - case 0: - return false; - default: - DDS_FATAL("update_readconditions: sample_states invalid: %"PRIx32"\n", cond->m_sample_states); - return false; - } -} - -bool dds_rhc_add_readcondition (dds_readcond *cond) -{ - /* On the assumption that a readcondition will be attached to a - waitset for nearly all of its life, we keep track of all - readconditions on a reader in one set, without distinguishing - between those attached to a waitset or not. */ - - struct rhc *rhc = cond->m_rhc; - struct ddsrt_hh_iter it; - - assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) || - (dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_QUERY && cond->m_query.m_filter != 0)); - assert (cond->m_entity.m_trigger == 0); - assert (cond->m_query.m_qcmask == 0); - - cond->m_qminv = qmask_from_dcpsquery (cond->m_sample_states, cond->m_view_states, cond->m_instance_states); - - ddsrt_mutex_lock (&rhc->lock); - - /* Allocate a slot in the condition bitmasks; return an error no more slots are available */ - if (cond->m_query.m_filter != 0) - { - dds_querycond_mask_t avail_qcmask = ~(dds_querycond_mask_t)0; - for (dds_readcond *rc = rhc->conds; rc != NULL; rc = rc->m_next) - { - assert ((rc->m_query.m_filter == 0 && rc->m_query.m_qcmask == 0) || (rc->m_query.m_filter != 0 && rc->m_query.m_qcmask != 0)); - avail_qcmask &= ~rc->m_query.m_qcmask; - } - if (avail_qcmask == 0) - { - /* no available indices */ - ddsrt_mutex_unlock (&rhc->lock); - return false; - } - - /* use the least significant bit set */ - cond->m_query.m_qcmask = avail_qcmask & (~avail_qcmask + 1); - } - - rhc->nconds++; - cond->m_next = rhc->conds; - rhc->conds = cond; - - if (cond->m_query.m_filter == 0) - { - /* Read condition is not cached inside the instances and samples, so it only needs - to be evaluated on the non-empty instances */ - if (rhc->nonempty_instances) - { - struct rhc_instance *inst = rhc->nonempty_instances; - do { - cond->m_entity.m_trigger += rhc_get_cond_trigger (inst, cond); - inst = inst->next; - } while (inst != rhc->nonempty_instances); - } - } - else - { - if (cond_is_sample_state_dependent (cond)) - rhc->qconds_samplest |= cond->m_query.m_qcmask; - if (rhc->nqconds++ == 0) - { - assert (rhc->qcond_eval_samplebuf == NULL); - rhc->qcond_eval_samplebuf = ddsi_sertopic_alloc_sample (rhc->topic); - } - - /* Attaching a query condition means clearing the allocated bit in all instances and - samples, except for those that match the predicate. */ - const dds_querycond_mask_t qcmask = cond->m_query.m_qcmask; - uint32_t trigger = 0; - for (struct rhc_instance *inst = ddsrt_hh_iter_first (rhc->instances, &it); inst != NULL; inst = ddsrt_hh_iter_next (&it)) - { - const bool instmatch = eval_predicate_invsample (rhc, inst, cond->m_query.m_filter);; - uint32_t matches = 0; - - inst->conds = (inst->conds & ~qcmask) | (instmatch ? qcmask : 0); - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - const bool m = eval_predicate_sample (rhc, sample->sample, cond->m_query.m_filter); - sample->conds = (sample->conds & ~qcmask) | (m ? qcmask : 0); - matches += m; - sample = sample->next; - } while (sample != end); - } - - if (!inst_is_empty (inst) && rhc_get_cond_trigger (inst, cond)) - trigger += (inst->inv_exists ? instmatch : 0) + matches; - } - cond->m_entity.m_trigger = trigger; - } - - if (cond->m_entity.m_trigger) - dds_entity_status_signal (&cond->m_entity); - - TRACE ("add_readcondition(%p, %"PRIx32", %"PRIx32", %"PRIx32") => %p qminv %"PRIx32" ; rhc %"PRIu32" conds\n", - (void *) rhc, cond->m_sample_states, cond->m_view_states, - cond->m_instance_states, (void *) cond, cond->m_qminv, rhc->nconds); - - ddsrt_mutex_unlock (&rhc->lock); - return true; -} - -void dds_rhc_remove_readcondition (dds_readcond *cond) -{ - struct rhc *rhc = cond->m_rhc; - dds_readcond **ptr; - ddsrt_mutex_lock (&rhc->lock); - ptr = &rhc->conds; - while (*ptr != cond) - ptr = &(*ptr)->m_next; - *ptr = (*ptr)->m_next; - rhc->nconds--; - if (cond->m_query.m_filter) - { - rhc->nqconds--; - rhc->qconds_samplest &= ~cond->m_query.m_qcmask; - cond->m_query.m_qcmask = 0; - if (rhc->nqconds == 0) - { - assert (rhc->qcond_eval_samplebuf != NULL); - ddsi_sertopic_free_sample (rhc->topic, rhc->qcond_eval_samplebuf, DDS_FREE_ALL); - rhc->qcond_eval_samplebuf = NULL; - } - } - ddsrt_mutex_unlock (&rhc->lock); -} - -static bool update_conditions_locked (struct rhc *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst) -{ - /* Pre: rhc->lock held; returns 1 if triggering required, else 0. */ - bool trigger = false; - dds_readcond *iter; - bool m_pre, m_post; - - TRACE ("update_conditions_locked(%p %p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32" read %"PRIu32"\n", - (void *) rhc, (void *) inst, rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, - rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_vread); - TRACE (" read -[%d,%d]+[%d,%d] qcmask -[%"PRIx32",%"PRIx32"]+[%"PRIx32",%"PRIx32"]\n", - trig_qc->dec_invsample_read, trig_qc->dec_sample_read, trig_qc->inc_invsample_read, trig_qc->inc_sample_read, - trig_qc->dec_conds_invsample, trig_qc->dec_conds_sample, trig_qc->inc_conds_invsample, trig_qc->inc_conds_sample); - - assert (rhc->n_nonempty_instances >= rhc->n_not_alive_disposed + rhc->n_not_alive_no_writers); - assert (rhc->n_nonempty_instances >= rhc->n_new); - assert (rhc->n_vsamples >= rhc->n_vread); - - iter = rhc->conds; - while (iter) - { - m_pre = ((pre->c.qminst & iter->m_qminv) == 0); - m_post = ((post->c.qminst & iter->m_qminv) == 0); - - /* Fast path out: instance did not and will not match based on instance, view states, so no - need to evaluate anything else */ - if (!m_pre && !m_post) - { - iter = iter->m_next; - continue; - } - - /* FIXME: use bitmask? */ - switch (iter->m_sample_states) - { - case DDS_SST_READ: - m_pre = m_pre && pre->c.has_read; - m_post = m_post && post->c.has_read; - break; - case DDS_SST_NOT_READ: - m_pre = m_pre && pre->c.has_not_read; - m_post = m_post && post->c.has_not_read; - break; - case DDS_SST_READ | DDS_SST_NOT_READ: - case 0: - m_pre = m_pre && (pre->c.has_read + pre->c.has_not_read); - m_post = m_post && (post->c.has_read + post->c.has_not_read); - break; - default: - DDS_FATAL ("update_readconditions: sample_states invalid: %"PRIx32"\n", iter->m_sample_states); - } - - TRACE (" cond %p %08"PRIx32": ", (void *) iter, iter->m_query.m_qcmask); - if (iter->m_query.m_filter == 0) - { - assert (dds_entity_kind (&iter->m_entity) == DDS_KIND_COND_READ); - if (m_pre == m_post) - TRACE ("no change"); - else if (m_pre < m_post) - { - TRACE ("now matches"); - trigger = (iter->m_entity.m_trigger++ == 0); - if (trigger) - TRACE (" (cond now triggers)"); - } - else - { - TRACE ("no longer matches"); - if (--iter->m_entity.m_trigger == 0) - TRACE (" (cond no longer triggers)"); - } - } - else if (m_pre || m_post) /* no need to look any further if both are false */ - { - assert (dds_entity_kind (&iter->m_entity) == DDS_KIND_COND_QUERY); - assert (iter->m_query.m_qcmask != 0); - const dds_querycond_mask_t qcmask = iter->m_query.m_qcmask; - int32_t mdelta = 0; - - switch (iter->m_sample_states) - { - case DDS_SST_READ: - if (trig_qc->dec_invsample_read) - mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; - if (trig_qc->dec_sample_read) - mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; - if (trig_qc->inc_invsample_read) - mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; - if (trig_qc->inc_sample_read) - mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; - break; - case DDS_SST_NOT_READ: - if (!trig_qc->dec_invsample_read) - mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; - if (!trig_qc->dec_sample_read) - mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; - if (!trig_qc->inc_invsample_read) - mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; - if (!trig_qc->inc_sample_read) - mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; - break; - case DDS_SST_READ | DDS_SST_NOT_READ: - case 0: - mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; - mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; - mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; - mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; - break; - default: - DDS_FATAL ("update_readconditions: sample_states invalid: %"PRIx32"\n", iter->m_sample_states); - } - - if (m_pre == m_post) - { - assert (m_pre); - /* there was a match at read-condition level - - therefore the matching samples in the instance are accounted for in the trigger count - - therefore an incremental update is required - there is always space for a valid and an invalid sample, both add and remove - inserting an update always has unread data added, but a read pretends it is a removal - of whatever and an insertion of read data */ - assert (mdelta >= 0 || iter->m_entity.m_trigger >= (uint32_t) -mdelta); - if (mdelta == 0) - TRACE ("no change @ %"PRIu32" (0)", iter->m_entity.m_trigger); - else - TRACE ("m=%"PRId32" @ %"PRIu32" (0)", mdelta, iter->m_entity.m_trigger + (uint32_t) mdelta); - /* even though it matches now and matched before, it is not a given that any of the samples - matched before, so m_trigger may still be 0 */ - if (mdelta > 0 && iter->m_entity.m_trigger == 0) - trigger = true; - iter->m_entity.m_trigger += (uint32_t) mdelta; - if (trigger) - TRACE (" (cond now triggers)"); - else if (mdelta < 0 && iter->m_entity.m_trigger == 0) - TRACE (" (cond no longer triggers)"); - } - else - { - /* There either was no match at read-condition level, now there is: scan all samples for matches; - or there was a match and now there is not: so also scan all samples for matches. The only - difference is in whether the number of matches should be added or subtracted. */ - int32_t mcurrent = 0; - if (inst->inv_exists) - mcurrent += (qmask_of_invsample (inst) & iter->m_qminv) == 0 && (inst->conds & qcmask) != 0; - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - mcurrent += (qmask_of_sample (sample) & iter->m_qminv) == 0 && (sample->conds & qcmask) != 0; - sample = sample->next; - } while (sample != end); - } - if (mdelta == 0 && mcurrent == 0) - TRACE ("no change @ %"PRIu32" (2)", iter->m_entity.m_trigger); - else if (m_pre < m_post) - { - /* No match previously, so the instance wasn't accounted for at all in the trigger value. - Therefore when inserting data, all that matters is how many currently match. - - When reading or taking it is evaluated incrementally _before_ changing the state of the - sample, so mrem reflects the state before the change, and the incremental change needs - to be taken into account. */ - const int32_t m = called_from_insert ? mcurrent : mcurrent + mdelta; - TRACE ("mdelta=%"PRId32" mcurrent=%"PRId32" => %"PRId32" => %"PRIu32" (2a)", mdelta, mcurrent, m, iter->m_entity.m_trigger + (uint32_t) m); - assert (m >= 0 || iter->m_entity.m_trigger >= (uint32_t) -m); - trigger = (iter->m_entity.m_trigger == 0) && m > 0; - iter->m_entity.m_trigger += (uint32_t) m; - if (trigger) - TRACE (" (cond now triggers)"); - } - else - { - /* Previously matched, but no longer, which means we need to subtract the current number - of matches as well as those that were removed just before, hence need the incremental - change as well */ - const int32_t m = mcurrent - mdelta; - TRACE ("mdelta=%"PRId32" mcurrent=%"PRId32" => %"PRId32" => %"PRIu32" (2b)", mdelta, mcurrent, m, iter->m_entity.m_trigger - (uint32_t) m); - assert (m < 0 || iter->m_entity.m_trigger >= (uint32_t) m); - iter->m_entity.m_trigger -= (uint32_t) m; - if (iter->m_entity.m_trigger == 0) - TRACE (" (cond no longer triggers)"); - } - } - } - - if (iter->m_entity.m_trigger) - dds_entity_status_signal (&iter->m_entity); - - TRACE ("\n"); - iter = iter->m_next; - } - return trigger; -} - - -/************************* - ****** READ/TAKE ****** - *************************/ - -int -dds_rhc_read( - struct rhc *rhc, - bool lock, - void ** values, - dds_sample_info_t *info_seq, - uint32_t max_samples, - uint32_t mask, - dds_instance_handle_t handle, - dds_readcond *cond) -{ - unsigned qminv = qmask_from_mask_n_cond(mask, cond); - return dds_rhc_read_w_qminv(rhc, lock, values, info_seq, max_samples, qminv, handle, cond); -} - -int -dds_rhc_take( - struct rhc *rhc, - bool lock, - void ** values, - dds_sample_info_t *info_seq, - uint32_t max_samples, - uint32_t mask, - dds_instance_handle_t handle, - dds_readcond *cond) -{ - unsigned qminv = qmask_from_mask_n_cond(mask, cond); - return dds_rhc_take_w_qminv(rhc, lock, values, info_seq, max_samples, qminv, handle, cond); -} - -int dds_rhc_takecdr -( - struct rhc *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, - unsigned sample_states, unsigned view_states, unsigned instance_states, dds_instance_handle_t handle) -{ - unsigned qminv = qmask_from_dcpsquery (sample_states, view_states, instance_states); - return dds_rhc_takecdr_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, NULL); -} - -/************************* - ****** CHECK ****** - *************************/ - -#ifndef NDEBUG -#define CHECK_MAX_CONDS 64 -static int rhc_check_counts_locked (struct rhc *rhc, bool check_conds, bool check_qcmask) -{ - if (!(config.enabled_xchecks & DDS_XCHECK_RHC)) - return 1; - - const uint32_t ncheck = rhc->nconds < CHECK_MAX_CONDS ? rhc->nconds : CHECK_MAX_CONDS; - unsigned n_instances = 0, n_nonempty_instances = 0; - unsigned n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0; - unsigned n_vsamples = 0, n_vread = 0; - unsigned n_invsamples = 0, n_invread = 0; - unsigned cond_match_count[CHECK_MAX_CONDS]; - dds_querycond_mask_t enabled_qcmask = 0; - struct rhc_instance *inst; - struct ddsrt_hh_iter iter; - dds_readcond *rciter; - uint32_t i; - - for (i = 0; i < CHECK_MAX_CONDS; i++) - cond_match_count[i] = 0; - - for (rciter = rhc->conds; rciter; rciter = rciter->m_next) - { - assert ((dds_entity_kind (&rciter->m_entity) == DDS_KIND_COND_READ && rciter->m_query.m_filter == 0) || - (dds_entity_kind (&rciter->m_entity) == DDS_KIND_COND_QUERY && rciter->m_query.m_filter != 0)); - assert ((rciter->m_query.m_filter != 0) == (rciter->m_query.m_qcmask != 0)); - assert (!(enabled_qcmask & rciter->m_query.m_qcmask)); - enabled_qcmask |= rciter->m_query.m_qcmask; - } - - for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) - { - unsigned n_vsamples_in_instance = 0, n_read_vsamples_in_instance = 0; - bool a_sample_free = true; - - n_instances++; - if (inst_is_empty (inst)) - continue; - - n_nonempty_instances++; - if (inst->isdisposed) - n_not_alive_disposed++; - else if (inst->wrcount == 0) - n_not_alive_no_writers++; - if (inst->isnew) - n_new++; - - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - if (sample == &inst->a_sample) - { - assert (a_sample_free); - a_sample_free = false; - } - n_vsamples++; - n_vsamples_in_instance++; - if (sample->isread) - { - n_vread++; - n_read_vsamples_in_instance++; - } - sample = sample->next; - } while (sample != end); - } - - if (inst->inv_exists) - { - n_invsamples++; - n_invread += inst->inv_isread; - } - - assert (n_read_vsamples_in_instance == inst->nvread); - assert (n_vsamples_in_instance == inst->nvsamples); - assert (a_sample_free == inst->a_sample_free); - - if (check_conds) - { - if (check_qcmask && rhc->nqconds > 0) - { - dds_querycond_mask_t qcmask; - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, rhc->qcond_eval_samplebuf, 0, 0); - qcmask = 0; - for (rciter = rhc->conds; rciter; rciter = rciter->m_next) - if (rciter->m_query.m_filter != 0 && rciter->m_query.m_filter (rhc->qcond_eval_samplebuf)) - qcmask |= rciter->m_query.m_qcmask; - assert ((inst->conds & enabled_qcmask) == qcmask); - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - ddsi_serdata_to_sample (sample->sample, rhc->qcond_eval_samplebuf, NULL, NULL); - qcmask = 0; - for (rciter = rhc->conds; rciter; rciter = rciter->m_next) - if (rciter->m_query.m_filter != 0 && rciter->m_query.m_filter (rhc->qcond_eval_samplebuf)) - qcmask |= rciter->m_query.m_qcmask; - assert ((sample->conds & enabled_qcmask) == qcmask); - sample = sample->next; - } while (sample != end); - } - } - - for (i = 0, rciter = rhc->conds; i < ncheck; i++, rciter = rciter->m_next) - { - if (!rhc_get_cond_trigger (inst, rciter)) - ; - else if (rciter->m_query.m_filter == 0) - cond_match_count[i]++; - else - { - if (inst->inv_exists) - cond_match_count[i] += (qmask_of_invsample (inst) & rciter->m_qminv) == 0 && (inst->conds & rciter->m_query.m_qcmask) != 0; - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - cond_match_count[i] += ((qmask_of_sample (sample) & rciter->m_qminv) == 0 && (sample->conds & rciter->m_query.m_qcmask) != 0); - sample = sample->next; - } while (sample != end); - } - } - } - } - } - - assert (rhc->n_instances == n_instances); - assert (rhc->n_nonempty_instances == n_nonempty_instances); - assert (rhc->n_not_alive_disposed == n_not_alive_disposed); - assert (rhc->n_not_alive_no_writers == n_not_alive_no_writers); - assert (rhc->n_new == n_new); - assert (rhc->n_vsamples == n_vsamples); - assert (rhc->n_vread == n_vread); - assert (rhc->n_invsamples == n_invsamples); - assert (rhc->n_invread == n_invread); - - if (check_conds) - { - for (i = 0, rciter = rhc->conds; i < ncheck; i++, rciter = rciter->m_next) - assert (cond_match_count[i] == rciter->m_entity.m_trigger); - } - - if (rhc->n_nonempty_instances == 0) - { - assert (rhc->nonempty_instances == NULL); - } - else - { - struct rhc_instance *prev, *end; - assert (rhc->nonempty_instances != NULL); - prev = rhc->nonempty_instances->prev; - end = rhc->nonempty_instances; - inst = rhc->nonempty_instances; - n_nonempty_instances = 0; - do { - assert (!inst_is_empty (inst)); - assert (prev->next == inst); - assert (inst->prev == prev); - prev = inst; - inst = inst->next; - n_nonempty_instances++; - } while (inst != end); - assert (rhc->n_nonempty_instances == n_nonempty_instances); - } - - return 1; -} -#undef CHECK_MAX_CONDS -#endif +extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); +extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); +extern inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid); +extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *qos); +extern inline void dds_rhc_free (struct dds_rhc *rhc); +extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); +extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); +extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); +extern inline bool dds_rhc_add_readcondition (struct dds_readcond *cond); +extern inline void dds_rhc_remove_readcondition (struct dds_readcond *cond); +extern inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc); diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c new file mode 100644 index 0000000..8de4585 --- /dev/null +++ b/src/core/ddsc/src/dds_rhc_default.c @@ -0,0 +1,2819 @@ +/* + * 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 +#include +#include + +#if HAVE_VALGRIND && ! defined (NDEBUG) +#include +#define USE_VALGRIND 1 +#else +#define USE_VALGRIND 0 +#endif + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" + +#include "dds__entity.h" +#include "dds__reader.h" +#include "dds__rhc.h" +#include "dds__rhc_default.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/avl.h" +#include "dds/ddsi/q_rhc.h" +#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/q_unused.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/q_radmin.h" /* sampleinfo */ +#include "dds/ddsi/q_entity.h" /* proxy_writer_info */ +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/sysdeps.h" + +/* INSTANCE MANAGEMENT + =================== + + Instances are created implicitly by "write" and "dispose", unregistered by + "unregister". Valid samples are added only by write operations (possibly + a combined with dispose and/or unregister), invalid samples only by dispose + and unregister operations, and only when there is no sample or the latest + available sample is read. (This might be a bit funny in the oddish case + where someone would take only the latest of multiple valid samples.) + + There is at most one invalid sample per instance, its sample info is taken + straight from the instance when it is returned to the reader and its + presence and sample_state are represented by two bits. Any incoming sample + (or "incoming invalid sample") will cause an existing invalid sample to be + dropped. Thus, invalid samples are used solely to signal an instance state + change when there are no samples. + + (Note: this can fairly easily be changed to let an invalid sample always + be generated on dispose/unregister.) + + The instances and the RHC as a whole keep track of the number of valid + samples and the number of read valid samples, as well as the same for the + invalid ones, with the twist that the "inv_exists" and "inv_isread" booleans + in the RHC serve as flags and as counters at the same time. + + Instances are dropped when the number of samples (valid & invalid combined) + and the number of registrations both go to 0. The number of registrations + is kept track of in "wrcount", and a unique identifier for the most recent + writer is typically in "wr_iid". Typically, because an unregister by + "wr_iid" clears it. The actual set of registrations is in principle a set + of tuples stored in "registrations", but excluded from it + are those instances that have "wrcount" = 1 and "wr_iid" != 0. The typical + case is a single active writer for an instance, and this means the typical + case has no tuples in "registrations". + + It is unfortunate that this model complicates the transitions from 1 writer + to 2 writers, and from 2 writers back to 1 writer. This seems a reasonable + price to pay for the significant performance gain from not having to do + anything in the case of a single (or single dominant) writer. + + (Note: "registrations" may perhaps be moved to a global registration table + of tuples, using a lock-free hash table, but that + doesn't affect the model.) + + The unique identifiers for instances and writers are approximately uniformly + drawn from the set of positive unsigned 64-bit integers. This means they + are excellent hash keys, and both the instance hash table and the writer + registrations hash table use these directly. + + QOS SUPPORT + =========== + + History is implemented as a (circular) linked list, but the invalid samples + model implemented here allows this to trivially be changed to an array of + samples, and this is probably profitable for shallow histories. Currently + the instance has a single sample embedded in particular to optimise the + KEEP_LAST with depth=1 case. + + BY_SOURCE ordering is implemented differently from OpenSplice and does not + perform back-filling of the history. The arguments against that can be + found in JIRA, but in short: (1) not backfilling is significantly simpler + (and thus faster), (2) backfilling potentially requires rewriting the + states of samples already read, (3) it is as much "eventually consistent", + the only difference is that the model implemented here considers the + dataspace to fundamentally be "keep last 1" and always move forward (source + timestamp increases), and the per-reader history to be a record of sampling + that dataspace by the reader, whereas with backfilling the model is that + the eventual consistency applies to the full history. + + (As it happens, the model implemented here is that also used by RTI and + probably other implementations -- OpenSplice is the odd one out in this + regard.) + + Exclusive ownership is implemented by dropping all data from all writers + other than "wr_iid", unless "wr_iid" is 0 or the strength of the arriving + sample is higher than the current strength of the instance (in "strength"). + The writer id is only reset by unregistering, in which case it is natural + that ownership is up for grabs again. QoS changes (not supported in this + DDSI implementation, but still) will be done by also reseting "wr_iid" + when an exclusive ownership writer lowers its strength. + + Lifespan, time base filter and deadline, are based on the instance + timestamp ("tstamp"). This time stamp needs to be changed to either source + or reception timestamp, depending on the ordering chosen. + + READ CONDITIONS + =============== + + Read conditions are currently *always* attached to the reader, creating a + read condition and not attaching it to a waitset is a bit of a waste of + resources. This can be changed, of course, but it is doubtful many read + conditions get created without actually being used. + + The "trigger" of a read condition counts the number of instances + matching its condition and is synchronously updated whenever the state + of instances and/or samples changes. The instance/sample states are + reduced to a triplet of a bitmask representing the instance and view + states, whether or not the instance has unread samples, and whether or not + it has read ones. (Invalid samples included.) Two of these triplets, + pre-change and post-change are passed to "update_conditions_locked", + which then runs over the array of attached read conditions and updates + the trigger. It returns whether or not a trigger changed + from 0 to 1, as this indicates the attached waitsets must be signalled. + The actual signalling of the waitsets then takes places later, by calling + "signal_conditions" after releasing the RHC lock. +*/ + +/* FIXME: tkmap should perhaps retain data with timestamp set to invalid + An invalid timestamp is (logically) unordered with respect to valid + timestamps, and that would mean BY_SOURCE order could be respected + even when generating an invalid sample for an unregister message using + the tkmap data. */ + +#define MAX_ATTACHED_QUERYCONDS (CHAR_BIT * sizeof (dds_querycond_mask_t)) +#define MAX_FAST_TRIGGERS 32 + +#define INCLUDE_TRACE 1 +#if INCLUDE_TRACE +#define TRACE(...) DDS_CLOG (DDS_LC_RHC, &rhc->gv->logconfig, __VA_ARGS__) +#else +#define TRACE(...) ((void)0) +#endif + +/****************************** + ****** LIVE WRITERS ****** + ******************************/ + +struct lwreg +{ + uint64_t iid; + uint64_t wr_iid; +}; + +struct lwregs +{ + struct ddsrt_ehh * regs; +}; + +static uint32_t lwreg_hash (const void *vl) +{ + const struct lwreg * l = vl; + return (uint32_t) (l->iid ^ l->wr_iid); +} + +static int lwreg_equals (const void *va, const void *vb) +{ + const struct lwreg * a = va; + const struct lwreg * b = vb; + return a->iid == b->iid && a->wr_iid == b->wr_iid; +} + +static void lwregs_init (struct lwregs *rt) +{ + rt->regs = NULL; +} + +static void lwregs_fini (struct lwregs *rt) +{ + if (rt->regs) + ddsrt_ehh_free (rt->regs); +} + +static int lwregs_contains (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) +{ + struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; + return rt->regs != NULL && ddsrt_ehh_lookup (rt->regs, &dummy) != NULL; +} + +static int lwregs_add (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) +{ + struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; + if (rt->regs == NULL) + rt->regs = ddsrt_ehh_new (sizeof (struct lwreg), 1, lwreg_hash, lwreg_equals); + return ddsrt_ehh_add (rt->regs, &dummy); +} + +static int lwregs_delete (struct lwregs *rt, uint64_t iid, uint64_t wr_iid) +{ + struct lwreg dummy = { .iid = iid, .wr_iid = wr_iid }; + return rt->regs != NULL && ddsrt_ehh_remove (rt->regs, &dummy); +} + +#if 0 +void lwregs_dump (struct lwregs *rt) +{ + struct ddsrt_ehh_iter it; + for (struct lwreg *r = ddsrt_ehh_iter_first(rt->regs, &it); r; r = ddsrt_ehh_iter_next(&it)) + printf("iid=%"PRIu64" wr_iid=%"PRIu64"\n", r->iid, r->wr_iid); +} +#endif + +/************************* + ****** RHC ****** + *************************/ + +struct rhc_sample { + struct ddsi_serdata *sample; /* serialised data (either just_key or real data) */ + struct rhc_sample *next; /* next sample in time ordering, or oldest sample if most recent */ + uint64_t wr_iid; /* unique id for writer of this sample (perhaps better in serdata) */ + dds_querycond_mask_t conds; /* matching query conditions */ + bool isread; /* READ or NOT_READ sample state */ + uint32_t disposed_gen; /* snapshot of instance counter at time of insertion */ + uint32_t no_writers_gen; /* __/ */ +}; + +struct rhc_instance { + uint64_t iid; /* unique instance id, key of table, also serves as instance handle */ + uint64_t wr_iid; /* unique of id of writer of latest sample or 0; if wrcount = 0 it is the wr_iid that caused */ + struct rhc_sample *latest; /* latest received sample; circular list old->new; null if no sample */ + uint32_t nvsamples; /* number of "valid" samples in instance */ + uint32_t nvread; /* number of READ "valid" samples in instance (0 <= nvread <= nvsamples) */ + dds_querycond_mask_t conds; /* matching query conditions */ + uint32_t wrcount; /* number of live writers */ + unsigned isnew : 1; /* NEW or NOT_NEW view state */ + unsigned a_sample_free : 1; /* whether or not a_sample is in use */ + unsigned isdisposed : 1; /* DISPOSED or NOT_DISPOSED (if not disposed, wrcount determines ALIVE/NOT_ALIVE_NO_WRITERS) */ + unsigned wr_iid_islive : 1; /* whether wr_iid is of a live writer */ + unsigned inv_exists : 1; /* whether or not state change occurred since last sample (i.e., must return invalid sample) */ + unsigned inv_isread : 1; /* whether or not that state change has been read before */ + uint32_t disposed_gen; /* bloody generation counters - worst invention of mankind */ + uint32_t no_writers_gen; /* __/ */ + int32_t strength; /* "current" ownership strength */ + nn_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */ + nn_wctime_t tstamp; /* source time stamp of last update */ + struct rhc_instance *next; /* next non-empty instance in arbitrary ordering */ + struct rhc_instance *prev; + struct ddsi_tkmap_instance *tk; /* backref into TK for unref'ing */ + struct rhc_sample a_sample; /* pre-allocated storage for 1 sample */ +}; + +typedef enum rhc_store_result { + RHC_STORED, + RHC_FILTERED, + RHC_REJECTED +} rhc_store_result_t; + +struct dds_rhc_default { + struct dds_rhc common; + struct ddsrt_hh *instances; + struct rhc_instance *nonempty_instances; /* circular, points to most recently added one, NULL if none */ + struct lwregs registrations; /* should be a global one (with lock-free lookups) */ + + /* Instance/Sample maximums from resource limits QoS */ + + int32_t max_instances; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ + int32_t max_samples; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ + int32_t max_samples_per_instance; /* FIXME: probably better as uint32_t with MAX_UINT32 for unlimited */ + + uint32_t n_instances; /* # instances, including empty [NOT USED] */ + uint32_t n_nonempty_instances; /* # non-empty instances */ + uint32_t n_not_alive_disposed; /* # disposed, non-empty instances [NOT USED] */ + uint32_t n_not_alive_no_writers; /* # not-alive-no-writers, non-empty instances [NOT USED] */ + uint32_t n_new; /* # new, non-empty instances [NOT USED] */ + uint32_t n_vsamples; /* # "valid" samples over all instances */ + uint32_t n_vread; /* # read "valid" samples over all instances [NOT USED] */ + uint32_t n_invsamples; /* # invalid samples over all instances [NOT USED] */ + uint32_t n_invread; /* # read invalid samples over all instances [NOT USED] */ + + bool by_source_ordering; /* true if BY_SOURCE, false if BY_RECEPTION */ + bool exclusive_ownership; /* true if EXCLUSIVE, false if SHARED */ + bool reliable; /* true if reliability RELIABLE */ + bool xchecks; /* whether to do expensive checking if checking at all */ + + dds_reader *reader; /* reader -- may be NULL (used by rhc_torture) */ + struct ddsi_tkmap *tkmap; /* back pointer to tkmap */ + struct q_globals *gv; /* globals -- so far only for log config */ + const struct ddsi_sertopic *topic; /* topic description */ + uint32_t history_depth; /* depth, 1 for KEEP_LAST_1, 2**32-1 for KEEP_ALL */ + + ddsrt_mutex_t lock; + dds_readcond * conds; /* List of associated read conditions */ + uint32_t nconds; /* Number of associated read conditions */ + uint32_t nqconds; /* Number of associated query conditions */ + dds_querycond_mask_t qconds_samplest; /* Mask of associated query conditions that check the sample state */ + void *qcond_eval_samplebuf; /* Temporary storage for evaluating query conditions, NULL if no qconds */ +}; + +struct trigger_info_cmn { + unsigned qminst; + bool has_read; + bool has_not_read; +}; + +struct trigger_info_pre { + struct trigger_info_cmn c; +}; + +struct trigger_info_qcond { + /* 0 or inst->conds depending on whether an invalid/valid sample was pushed out/added; + inc_xxx_read is there so read can indicate a sample changed from unread to read */ + bool dec_invsample_read; + bool dec_sample_read; + bool inc_invsample_read; + bool inc_sample_read; + dds_querycond_mask_t dec_conds_invsample; + dds_querycond_mask_t dec_conds_sample; + dds_querycond_mask_t inc_conds_invsample; + dds_querycond_mask_t inc_conds_sample; +}; + +struct trigger_info_post { + struct trigger_info_cmn c; +}; + +static void dds_rhc_default_free (struct dds_rhc_default *rhc); +static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); +static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); +static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid); +static void dds_rhc_default_set_qos (struct dds_rhc_default *rhc, const struct dds_qos *qos); +static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); +static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); +static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); +static bool dds_rhc_default_add_readcondition (dds_readcond *cond); +static void dds_rhc_default_remove_readcondition (dds_readcond *cond); +static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc); + +static void dds_rhc_default_free_wrap (struct rhc *rhc) { + dds_rhc_default_free ((struct dds_rhc_default *) rhc); +} +static bool dds_rhc_default_store_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) { + return dds_rhc_default_store ((struct dds_rhc_default *) rhc, pwr_info, sample, tk); +} +static void dds_rhc_default_unregister_wr_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) { + dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, pwr_info); +} +static void dds_rhc_default_relinquish_ownership_wrap (struct rhc * __restrict rhc, const uint64_t wr_iid) { + dds_rhc_default_relinquish_ownership ((struct dds_rhc_default *) rhc, wr_iid); +} +static void dds_rhc_default_set_qos_wrap (struct rhc *rhc, const struct dds_qos *qos) { + dds_rhc_default_set_qos ((struct dds_rhc_default *) rhc, qos); +} +static int dds_rhc_default_read_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { + return dds_rhc_default_read ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, mask, handle, cond); +} +static int dds_rhc_default_take_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { + return dds_rhc_default_take ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, mask, handle, cond); +} +static int dds_rhc_default_takecdr_wrap (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { + return dds_rhc_default_takecdr ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); +} +static bool dds_rhc_default_add_readcondition_wrap (dds_readcond *cond) { + return dds_rhc_default_add_readcondition (cond); +} +static void dds_rhc_default_remove_readcondition_wrap (dds_readcond *cond) { + dds_rhc_default_remove_readcondition (cond); +} +static uint32_t dds_rhc_default_lock_samples_wrap (struct dds_rhc *rhc) { + return dds_rhc_default_lock_samples ((struct dds_rhc_default *) rhc); +} + +static const struct dds_rhc_ops dds_rhc_default_ops = { + .rhc_ops = { + .store = dds_rhc_default_store_wrap, + .unregister_wr = dds_rhc_default_unregister_wr_wrap, + .relinquish_ownership = dds_rhc_default_relinquish_ownership_wrap, + .set_qos = dds_rhc_default_set_qos_wrap, + .free = dds_rhc_default_free_wrap + }, + .read = dds_rhc_default_read_wrap, + .take = dds_rhc_default_take_wrap, + .takecdr = dds_rhc_default_takecdr_wrap, + .add_readcondition = dds_rhc_default_add_readcondition_wrap, + .remove_readcondition = dds_rhc_default_remove_readcondition_wrap, + .lock_samples = dds_rhc_default_lock_samples_wrap +}; + +static unsigned qmask_of_sample (const struct rhc_sample *s) +{ + return s->isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; +} + +static unsigned qmask_of_invsample (const struct rhc_instance *i) +{ + return i->inv_isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; +} + +static uint32_t inst_nsamples (const struct rhc_instance *i) +{ + return i->nvsamples + i->inv_exists; +} + +static uint32_t inst_nread (const struct rhc_instance *i) +{ + return i->nvread + (uint32_t) (i->inv_exists & i->inv_isread); +} + +static bool inst_is_empty (const struct rhc_instance *i) +{ + return inst_nsamples (i) == 0; +} + +static bool inst_has_read (const struct rhc_instance *i) +{ + return inst_nread (i) > 0; +} + +static bool inst_has_unread (const struct rhc_instance *i) +{ + return inst_nread (i) < inst_nsamples (i); +} + +static void topicless_to_clean_invsample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim) +{ + /* ddsi_serdata_topicless_to_sample just deals with the key value, without paying any attention to attributes; + but that makes life harder for the user: the attributes of an invalid sample would be garbage, but would + nonetheless have to be freed in the end. Zero'ing it explicitly solves that problem. */ + ddsi_sertopic_free_sample (topic, sample, DDS_FREE_CONTENTS); + ddsi_sertopic_zero_sample (topic, sample); + ddsi_serdata_topicless_to_sample (topic, d, sample, bufptr, buflim); +} + +static unsigned qmask_of_inst (const struct rhc_instance *inst); +static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst, struct dds_entity *triggers[], size_t *ntriggers); +#ifndef NDEBUG +static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_conds, bool check_qcmask); +#endif + +static uint32_t instance_iid_hash (const void *va) +{ + const struct rhc_instance *a = va; + return (uint32_t) a->iid; +} + +static int instance_iid_eq (const void *va, const void *vb) +{ + const struct rhc_instance *a = va; + const struct rhc_instance *b = vb; + return (a->iid == b->iid); +} + +static void add_inst_to_nonempty_list (struct dds_rhc_default *rhc, struct rhc_instance *inst) +{ + if (rhc->nonempty_instances == NULL) + { + inst->next = inst->prev = inst; + } + else + { + struct rhc_instance * const hd = rhc->nonempty_instances; +#ifndef NDEBUG + { + const struct rhc_instance *x = hd; + do { assert (x != inst); x = x->next; } while (x != hd); + } +#endif + inst->next = hd->next; + inst->prev = hd; + hd->next = inst; + inst->next->prev = inst; + } + rhc->nonempty_instances = inst; + rhc->n_nonempty_instances++; +} + +static void remove_inst_from_nonempty_list (struct dds_rhc_default *rhc, struct rhc_instance *inst) +{ + assert (inst_is_empty (inst)); +#ifndef NDEBUG + { + const struct rhc_instance *x = rhc->nonempty_instances; + assert (x); + do { if (x == inst) break; x = x->next; } while (x != rhc->nonempty_instances); + assert (x == inst); + } +#endif + + if (inst->next == inst) + { + rhc->nonempty_instances = NULL; + } + else + { + struct rhc_instance * const inst_prev = inst->prev; + struct rhc_instance * const inst_next = inst->next; + inst_prev->next = inst_next; + inst_next->prev = inst_prev; + if (rhc->nonempty_instances == inst) + rhc->nonempty_instances = inst_prev; + } + assert (rhc->n_nonempty_instances > 0); + rhc->n_nonempty_instances--; +} + +struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_globals *gv, const struct ddsi_sertopic *topic, bool xchecks) +{ + struct dds_rhc_default *rhc = ddsrt_malloc (sizeof (*rhc)); + memset (rhc, 0, sizeof (*rhc)); + rhc->common.common.ops = &dds_rhc_default_ops; + + lwregs_init (&rhc->registrations); + ddsrt_mutex_init (&rhc->lock); + rhc->instances = ddsrt_hh_new (1, instance_iid_hash, instance_iid_eq); + rhc->topic = topic; + rhc->reader = reader; + rhc->tkmap = gv->m_tkmap; + rhc->gv = gv; + rhc->xchecks = xchecks; + + return &rhc->common; +} + +struct dds_rhc *dds_rhc_default_new (dds_reader *reader, const struct ddsi_sertopic *topic) +{ + return dds_rhc_default_new_xchecks (reader, &reader->m_entity.m_domain->gv, topic, (reader->m_entity.m_domain->gv.config.enabled_xchecks & DDS_XCHECK_RHC) != 0); +} + +static void dds_rhc_default_set_qos (struct dds_rhc_default * rhc, const dds_qos_t * qos) +{ + /* Set read related QoS */ + + rhc->max_samples = qos->resource_limits.max_samples; + rhc->max_instances = qos->resource_limits.max_instances; + rhc->max_samples_per_instance = qos->resource_limits.max_samples_per_instance; + rhc->by_source_ordering = (qos->destination_order.kind == DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); + rhc->exclusive_ownership = (qos->ownership.kind == DDS_OWNERSHIP_EXCLUSIVE); + rhc->reliable = (qos->reliability.kind == DDS_RELIABILITY_RELIABLE); + assert(qos->history.kind != DDS_HISTORY_KEEP_LAST || qos->history.depth > 0); + rhc->history_depth = (qos->history.kind == DDS_HISTORY_KEEP_LAST) ? (uint32_t)qos->history.depth : ~0u; +} + +static bool eval_predicate_sample (const struct dds_rhc_default *rhc, const struct ddsi_serdata *sample, bool (*pred) (const void *sample)) +{ + ddsi_serdata_to_sample (sample, rhc->qcond_eval_samplebuf, NULL, NULL); + bool ret = pred (rhc->qcond_eval_samplebuf); + return ret; +} + +static bool eval_predicate_invsample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, bool (*pred) (const void *sample)) +{ + topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, rhc->qcond_eval_samplebuf, NULL, NULL); + bool ret = pred (rhc->qcond_eval_samplebuf); + return ret; +} + +static struct rhc_sample *alloc_sample (struct rhc_instance *inst) +{ + if (inst->a_sample_free) + { + inst->a_sample_free = 0; +#if USE_VALGRIND + VALGRIND_MAKE_MEM_UNDEFINED (&inst->a_sample, sizeof (inst->a_sample)); +#endif + return &inst->a_sample; + } + else + { + /* This instead of sizeof(rhc_sample) gets us type checking */ + struct rhc_sample *s; + s = ddsrt_malloc (sizeof (*s)); + return s; + } +} + +static void free_sample (struct rhc_instance *inst, struct rhc_sample *s) +{ + ddsi_serdata_unref (s->sample); + if (s == &inst->a_sample) + { + assert (!inst->a_sample_free); +#if USE_VALGRIND + VALGRIND_MAKE_MEM_NOACCESS (&inst->a_sample, sizeof (inst->a_sample)); +#endif + inst->a_sample_free = 1; + } + else + { + ddsrt_free (s); + } +} + +static void inst_clear_invsample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc) +{ + assert (inst->inv_exists); + assert (trig_qc->dec_conds_invsample == 0); + inst->inv_exists = 0; + trig_qc->dec_conds_invsample = inst->conds; + if (inst->inv_isread) + { + trig_qc->dec_invsample_read = true; + rhc->n_invread--; + } + rhc->n_invsamples--; +} + +static void inst_clear_invsample_if_exists (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc) +{ + if (inst->inv_exists) + inst_clear_invsample (rhc, inst, trig_qc); +} + +static void inst_set_invsample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc, bool *nda) +{ + if (!inst->inv_exists || inst->inv_isread) + { + /* Obviously optimisable, but that is perhaps not worth the bother */ + inst_clear_invsample_if_exists (rhc, inst, trig_qc); + assert (trig_qc->inc_conds_invsample == 0); + trig_qc->inc_conds_invsample = inst->conds; + inst->inv_exists = 1; + inst->inv_isread = 0; + rhc->n_invsamples++; + *nda = true; + } +} + +static void free_empty_instance (struct rhc_instance *inst, struct dds_rhc_default *rhc) +{ + assert (inst_is_empty (inst)); + ddsi_tkmap_instance_unref (rhc->tkmap, inst->tk); + ddsrt_free (inst); +} + +static void free_instance_rhc_free (struct rhc_instance *inst, struct dds_rhc_default *rhc) +{ + struct rhc_sample *s = inst->latest; + const bool was_empty = inst_is_empty (inst); + struct trigger_info_qcond dummy_trig_qc; + if (s) + { + do { + struct rhc_sample * const s1 = s->next; + free_sample (inst, s); + s = s1; + } while (s != inst->latest); + rhc->n_vsamples -= inst->nvsamples; + rhc->n_vread -= inst->nvread; + inst->nvsamples = 0; + inst->nvread = 0; + } +#ifndef NDEBUG + memset (&dummy_trig_qc, 0, sizeof (dummy_trig_qc)); +#endif + inst_clear_invsample_if_exists (rhc, inst, &dummy_trig_qc); + if (!was_empty) + { + remove_inst_from_nonempty_list (rhc, inst); + } + ddsi_tkmap_instance_unref (rhc->tkmap, inst->tk); + ddsrt_free (inst); +} + +static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc) +{ + uint32_t no; + ddsrt_mutex_lock (&rhc->lock); + no = rhc->n_vsamples + rhc->n_invsamples; + if (no == 0) + { + ddsrt_mutex_unlock (&rhc->lock); + } + return no; +} + +static void free_instance_rhc_free_wrap (void *vnode, void *varg) +{ + free_instance_rhc_free (vnode, varg); +} + +static void dds_rhc_default_free (struct dds_rhc_default *rhc) +{ + assert (rhc_check_counts_locked (rhc, true, true)); + ddsrt_hh_enum (rhc->instances, free_instance_rhc_free_wrap, rhc); + assert (rhc->nonempty_instances == NULL); + ddsrt_hh_free (rhc->instances); + lwregs_fini (&rhc->registrations); + if (rhc->qcond_eval_samplebuf != NULL) + ddsi_sertopic_free_sample (rhc->topic, rhc->qcond_eval_samplebuf, DDS_FREE_ALL); + ddsrt_mutex_destroy (&rhc->lock); + ddsrt_free (rhc); +} + +static void init_trigger_info_cmn_nonmatch (struct trigger_info_cmn *info) +{ + info->qminst = ~0u; + info->has_read = false; + info->has_not_read = false; +} + +static void get_trigger_info_cmn (struct trigger_info_cmn *info, struct rhc_instance *inst) +{ + info->qminst = qmask_of_inst (inst); + info->has_read = inst_has_read (inst); + info->has_not_read = inst_has_unread (inst); +} + +static void get_trigger_info_pre (struct trigger_info_pre *info, struct rhc_instance *inst) +{ + get_trigger_info_cmn (&info->c, inst); +} + +static void init_trigger_info_qcond (struct trigger_info_qcond *qc) +{ + qc->dec_invsample_read = false; + qc->dec_sample_read = false; + qc->inc_invsample_read = false; + qc->inc_sample_read = false; + qc->dec_conds_invsample = 0; + qc->dec_conds_sample = 0; + qc->inc_conds_invsample = 0; + qc->inc_conds_sample = 0; +} + +static bool trigger_info_differs (const struct dds_rhc_default *rhc, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc) +{ + if (pre->c.qminst != post->c.qminst || + pre->c.has_read != post->c.has_read || + pre->c.has_not_read != post->c.has_not_read) + return true; + else if (rhc->nqconds == 0) + return false; + else + return (trig_qc->dec_conds_invsample != trig_qc->inc_conds_invsample || + trig_qc->dec_conds_sample != trig_qc->inc_conds_sample || + trig_qc->dec_invsample_read != trig_qc->inc_invsample_read || + trig_qc->dec_sample_read != trig_qc->inc_sample_read); +} + +static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc) +{ + struct rhc_sample *s; + + /* Adding a sample always clears an invalid sample (because the information + contained in the invalid sample - the instance state and the generation + counts - are included in the sample). While this would be place to do it, + we do it later to avoid having to roll back on allocation failure */ + + /* We don't do backfilling in BY_SOURCE mode -- we could, but + choose not to -- and having already filtered out samples + preceding inst->latest, we can simply insert it without any + searching */ + if (inst->nvsamples == rhc->history_depth) + { + /* replace oldest sample; latest points to the latest one, the + list is circular from old -> new, so latest->next is the oldest */ + + inst_clear_invsample_if_exists (rhc, inst, trig_qc); + assert (inst->latest != NULL); + s = inst->latest->next; + assert (trig_qc->dec_conds_sample == 0); + ddsi_serdata_unref (s->sample); + + trig_qc->dec_sample_read = s->isread; + trig_qc->dec_conds_sample = s->conds; + if (s->isread) + { + inst->nvread--; + rhc->n_vread--; + } + } + else + { + /* Check if resource max_samples QoS exceeded */ + + if (rhc->reader && rhc->max_samples != DDS_LENGTH_UNLIMITED && rhc->n_vsamples >= (uint32_t) rhc->max_samples) + { + cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; + cb_data->extra = DDS_REJECTED_BY_SAMPLES_LIMIT; + cb_data->handle = inst->iid; + cb_data->add = true; + return false; + } + + /* Check if resource max_samples_per_instance QoS exceeded */ + + if (rhc->reader && rhc->max_samples_per_instance != DDS_LENGTH_UNLIMITED && inst->nvsamples >= (uint32_t) rhc->max_samples_per_instance) + { + cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; + cb_data->extra = DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT; + cb_data->handle = inst->iid; + cb_data->add = true; + return false; + } + + /* add new latest sample */ + + s = alloc_sample (inst); + inst_clear_invsample_if_exists (rhc, inst, trig_qc); + if (inst->latest == NULL) + { + s->next = s; + } + else + { + s->next = inst->latest->next; + inst->latest->next = s; + } + inst->nvsamples++; + rhc->n_vsamples++; + } + + s->sample = ddsi_serdata_ref (sample); /* drops const (tho refcount does change) */ + s->wr_iid = pwr_info->iid; + s->isread = false; + s->disposed_gen = inst->disposed_gen; + s->no_writers_gen = inst->no_writers_gen; + + s->conds = 0; + if (rhc->nqconds != 0) + { + for (dds_readcond *rc = rhc->conds; rc != NULL; rc = rc->m_next) + if (rc->m_query.m_filter != 0 && eval_predicate_sample (rhc, s->sample, rc->m_query.m_filter)) + s->conds |= rc->m_query.m_qcmask; + } + + trig_qc->inc_conds_sample = s->conds; + inst->latest = s; + return true; +} + +static bool content_filter_accepts (const dds_reader *reader, const struct ddsi_serdata *sample) +{ + bool ret = true; + if (reader) + { + const struct dds_topic *tp = reader->m_topic; + if (tp->filter_fn) + { + char *tmp = ddsi_sertopic_alloc_sample (tp->m_stopic); + ddsi_serdata_to_sample (sample, tmp, NULL, NULL); + ret = (tp->filter_fn) (tmp, tp->filter_ctx); + ddsi_sertopic_free_sample (tp->m_stopic, tmp, DDS_FREE_ALL); + } + } + return ret; +} + +static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info) +{ + return (inst->wr_iid_islive && inst->wr_iid == pwr_info->iid) || memcmp (&pwr_info->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0; +} + +static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, const bool has_data) +{ + if (rhc->by_source_ordering) + { + if (sample->timestamp.v > inst->tstamp.v) + { + /* ok */ + } + else if (sample->timestamp.v < inst->tstamp.v) + { + return 0; + } + else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) + { + /* ok */ + } + else + { + return 0; + } + } + if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != pwr_info->iid) + { + int32_t strength = pwr_info->ownership_strength; + if (strength > inst->strength) { + /* ok */ + } else if (strength < inst->strength) { + return 0; + } else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) { + /* ok */ + } else { + return 0; + } + } + if (has_data && !content_filter_accepts (rhc->reader, sample)) + { + return 0; + } + return 1; +} + +static void update_inst (struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, bool wr_iid_valid, nn_wctime_t tstamp) +{ + inst->tstamp = tstamp; + inst->wr_iid_islive = wr_iid_valid; + if (wr_iid_valid) + { + inst->wr_iid = pwr_info->iid; + if (inst->wr_iid != pwr_info->iid) + inst->wr_guid = pwr_info->guid; + } + inst->strength = pwr_info->ownership_strength; +} + +static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst) +{ + int ret; + assert (inst_is_empty (inst)); + + rhc->n_instances--; + + ret = ddsrt_hh_remove (rhc->instances, inst); + assert (ret); + (void) ret; + + free_empty_instance (inst, rhc); +} + +static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance *inst, uint64_t wr_iid, bool iid_update) +{ + const uint64_t inst_wr_iid = inst->wr_iid_islive ? inst->wr_iid : 0; + + TRACE (" register:"); + + /* Is an implicitly registering dispose semantically equivalent to + register ; dispose? If so, both no_writers_gen and disposed_gen + need to be incremented if the old instance state was DISPOSED, + else just disposed_gen. (Shudder.) Interpreting it as + equivalent. + + Is a dispose a sample? I don't think so (though a write dispose + is). Is a pure register a sample? Don't think so either. */ + if (inst_wr_iid == wr_iid) + { + /* Same writer as last time => we know it is registered already. + This is the fast path -- we don't have to check anything + else. */ + TRACE ("cached"); + assert (inst->wrcount > 0); + return; + } + + if (inst->wrcount == 0) + { + /* Currently no writers at all */ + assert (!inst->wr_iid_islive); + + /* to avoid wr_iid update when register is called for sample rejected */ + if (iid_update) + { + inst->wr_iid = wr_iid; + inst->wr_iid_islive = 1; + } + inst->wrcount++; + inst->no_writers_gen++; + TRACE ("new1"); + + if (!inst_is_empty (inst) && !inst->isdisposed) + rhc->n_not_alive_no_writers--; + } + else if (inst_wr_iid == 0 && inst->wrcount == 1) + { + /* Writers exist, but wr_iid is null => someone unregistered. + + With wrcount 1, if wr_iid happens to be the remaining writer, + we remove the explicit registration and once again rely on + inst->wr_iid, but if wr_iid happens to be a new writer, we + increment the writer count & explicitly register the second + one, too. + + If I decide on a global table of registrations implemented + using concurrent hopscotch-hashing, then this should still + scale well because lwregs_add first calls lwregs_contains, + which is lock-free. (Not that it probably can't be optimised + by a combined add-if-unknown-delete-if-known operation -- but + the value of that is likely negligible because the + registrations should be fairly stable.) */ + if (lwregs_add (&rhc->registrations, inst->iid, wr_iid)) + { + inst->wrcount++; + TRACE ("new2iidnull"); + } + else + { + int x = lwregs_delete (&rhc->registrations, inst->iid, wr_iid); + assert (x); + (void) x; + TRACE ("restore"); + } + /* to avoid wr_iid update when register is called for sample rejected */ + if (iid_update) + { + inst->wr_iid = wr_iid; + inst->wr_iid_islive = 1; + } + } + else + { + /* As above -- if using concurrent hopscotch hashing, if the + writer is already known, lwregs_add is lock-free */ + if (inst->wrcount == 1) + { + /* 2nd writer => properly register the one we knew about */ + TRACE ("rescue1"); + int x; + x = lwregs_add (&rhc->registrations, inst->iid, inst_wr_iid); + assert (x); + (void) x; + } + if (lwregs_add (&rhc->registrations, inst->iid, wr_iid)) + { + /* as soon as we reach at least two writers, we have to check + the result of lwregs_add to know whether this sample + registers a previously unknown writer or not */ + TRACE ("new3"); + inst->wrcount++; + } + else + { + TRACE ("known"); + } + assert (inst->wrcount >= 2); + /* the most recent writer gets the fast path */ + /* to avoid wr_iid update when register is called for sample rejected */ + if (iid_update) + { + inst->wr_iid = wr_iid; + inst->wr_iid_islive = 1; + } + } +} + +static void account_for_empty_to_nonempty_transition (struct dds_rhc_default *rhc, struct rhc_instance *inst) +{ + assert (inst_nsamples (inst) == 1); + add_inst_to_nonempty_list (rhc, inst); + rhc->n_new += inst->isnew; + if (inst->isdisposed) + rhc->n_not_alive_disposed++; + else if (inst->wrcount == 0) + rhc->n_not_alive_no_writers++; +} + +static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, const struct rhc_instance *inst, uint64_t wr_iid) +{ + /* Returns 1 if last registration just disappeared */ + if (inst->wrcount == 0) + { + TRACE ("unknown(#0)"); + return 0; + } + else if (inst->wrcount == 1 && inst->wr_iid_islive) + { + assert(inst->wr_iid != 0); + if (wr_iid != inst->wr_iid) + { + TRACE ("unknown(cache)"); + return 0; + } + else + { + TRACE ("last(cache)"); + return 1; + } + } + else if (!lwregs_delete (&rhc->registrations, inst->iid, wr_iid)) + { + TRACE ("unknown(regs)"); + return 0; + } + else + { + TRACE ("delreg"); + /* If we transition from 2 to 1 writer, and we are deleting a + writer other than the one cached in the instance, that means + afterward there will be 1 writer, it will be cached, and its + registration record must go (invariant that with wrcount = 1 + and wr_iid != 0 the wr_iid is not in "registrations") */ + if (inst->wrcount == 2 && inst->wr_iid_islive && inst->wr_iid != wr_iid) + { + TRACE (",delreg(remain)"); + lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid); + } + return 1; + } +} + +static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda) +{ + assert (inst->wrcount > 0); + + if (--inst->wrcount > 0) + { + if (inst->wr_iid_islive && pwr_info->iid == inst->wr_iid) + { + /* Next register will have to do real work before we have a cached + wr_iid again */ + inst->wr_iid_islive = 0; + + /* Reset the ownership strength to allow samples to be read from other + writer(s) */ + inst->strength = 0; + TRACE (",clearcache"); + } + return 0; + } + else + { + if (!inst_is_empty (inst)) + { + /* Instance still has content - do not drop until application + takes the last sample. Set the invalid sample if the latest + sample has been read already, so that the application can + read the change to not-alive. (If the latest sample is still + unread, we don't bother, even though it means the application + won't see the timestamp for the unregister event. It shouldn't + care.) */ + if (inst->latest == NULL || inst->latest->isread) + { + inst_set_invsample (rhc, inst, trig_qc, nda); + update_inst (inst, pwr_info, false, tstamp); + } + if (!inst->isdisposed) + { + rhc->n_not_alive_no_writers++; + } + inst->wr_iid_islive = 0; + return 0; + } + else if (inst->isdisposed) + { + /* No content left, no registrations left, so drop */ + TRACE (",#0,empty,disposed,drop"); + drop_instance_noupdate_no_writers (rhc, inst); + return 1; + } + else + { + /* Add invalid samples for transition to no-writers */ + TRACE (",#0,empty,nowriters"); + assert (inst_is_empty (inst)); + inst_set_invsample (rhc, inst, trig_qc, nda); + update_inst (inst, pwr_info, false, tstamp); + account_for_empty_to_nonempty_transition (rhc, inst); + inst->wr_iid_islive = 0; + return 0; + } + } +} + +static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) +{ + bool notify_data_available = false; + + /* 'post' always gets set; instance may have been freed upon return. */ + TRACE (" unregister:"); + if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, pwr_info->iid)) + { + /* other registrations remain */ + get_trigger_info_cmn (&post->c, inst); + } + else if (rhc_unregister_updateinst (rhc, inst, pwr_info, tstamp, trig_qc, ¬ify_data_available)) + { + /* instance dropped */ + init_trigger_info_cmn_nonmatch (&post->c); + } + else + { + /* no writers remain, but instance not empty */ + get_trigger_info_cmn (&post->c, inst); + } + return notify_data_available; +} + +static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) +{ + struct rhc_instance *inst; + + ddsi_tkmap_instance_ref (tk); + inst = ddsrt_malloc (sizeof (*inst)); + memset (inst, 0, sizeof (*inst)); + inst->iid = tk->m_iid; + inst->tk = tk; + inst->wrcount = (serdata->statusinfo & NN_STATUSINFO_UNREGISTER) ? 0 : 1; + inst->isdisposed = (serdata->statusinfo & NN_STATUSINFO_DISPOSE) != 0; + inst->isnew = 1; + inst->a_sample_free = 1; + inst->conds = 0; + inst->wr_iid = pwr_info->iid; + inst->wr_iid_islive = (inst->wrcount != 0); + inst->wr_guid = pwr_info->guid; + inst->tstamp = serdata->timestamp; + inst->strength = pwr_info->ownership_strength; + + if (rhc->nqconds != 0) + { + for (dds_readcond *c = rhc->conds; c != NULL; c = c->m_next) + { + assert ((dds_entity_kind (&c->m_entity) == DDS_KIND_COND_READ && c->m_query.m_filter == 0) || + (dds_entity_kind (&c->m_entity) == DDS_KIND_COND_QUERY && c->m_query.m_filter != 0)); + if (c->m_query.m_filter && eval_predicate_invsample (rhc, inst, c->m_query.m_filter)) + inst->conds |= c->m_query.m_qcmask; + } + } + + return inst; +} + +static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) +{ + struct rhc_instance *inst; + int ret; + + /* New instance for this reader. May still filter out key value. + + Doing the filtering here means avoiding filter processing in + the normal case of accepting data, accepting some extra + overhead in the case where the data would be filtered out. + Naturally using an avl tree is not so smart for these IIDs, and + if the AVL tree is replaced by a hash table, the overhead + trade-off should be quite nice with the filtering code right + here. + + Note: never instantiating based on a sample that's filtered out, + though one could argue that if it is rejected based on an + attribute (rather than a key), an empty instance should be + instantiated. */ + + if (has_data && !content_filter_accepts (rhc->reader, sample)) + { + return RHC_FILTERED; + } + /* Check if resource max_instances QoS exceeded */ + + if (rhc->reader && rhc->max_instances != DDS_LENGTH_UNLIMITED && rhc->n_instances >= (uint32_t) rhc->max_instances) + { + cb_data->raw_status_id = (int) DDS_SAMPLE_REJECTED_STATUS_ID; + cb_data->extra = DDS_REJECTED_BY_INSTANCES_LIMIT; + cb_data->handle = tk->m_iid; + cb_data->add = true; + return RHC_REJECTED; + } + + inst = alloc_new_instance (rhc, pwr_info, sample, tk); + if (has_data) + { + if (!add_sample (rhc, inst, pwr_info, sample, cb_data, trig_qc)) + { + free_empty_instance (inst, rhc); + return RHC_REJECTED; + } + } + else + { + if (inst->isdisposed) { + bool nda_dummy = false; + inst_set_invsample (rhc, inst, trig_qc, &nda_dummy); + } + } + + account_for_empty_to_nonempty_transition (rhc, inst); + ret = ddsrt_hh_add (rhc->instances, inst); + assert (ret); + (void) ret; + rhc->n_instances++; + get_trigger_info_cmn (&post->c, inst); + + *out_inst = inst; + return RHC_STORED; +} + +/* + dds_rhc_store: DDSI up call into read cache to store new sample. Returns whether sample + delivered (true unless a reliable sample rejected). +*/ + +static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) +{ + const uint64_t wr_iid = pwr_info->iid; + const unsigned statusinfo = sample->statusinfo; + const bool has_data = (sample->kind == SDK_DATA); + const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0; + struct rhc_instance dummy_instance; + struct rhc_instance *inst; + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + rhc_store_result_t stored; + status_cb_data_t cb_data; /* Callback data for reader status callback */ + bool delivered = true; + bool notify_data_available = false; + + TRACE ("rhc_store(%"PRIx64",%"PRIx64" si %x has_data %d:", tk->m_iid, wr_iid, statusinfo, has_data); + if (!has_data && statusinfo == 0) + { + /* Write with nothing but a key -- I guess that would be a + register, which we do implicitly. (Currently DDSI2 won't allow + it through anyway.) */ + TRACE (" ignore explicit register)\n"); + return delivered; + } + + dummy_instance.iid = tk->m_iid; + stored = RHC_FILTERED; + cb_data.raw_status_id = -1; + + init_trigger_info_qcond (&trig_qc); + + ddsrt_mutex_lock (&rhc->lock); + + inst = ddsrt_hh_lookup (rhc->instances, &dummy_instance); + if (inst == NULL) + { + /* New instance for this reader. If no data content -- not (also) + a write -- ignore it, I think we can get away with ignoring dispose or unregisters + on unknown instances. + */ + if (!has_data && !is_dispose) + { + TRACE (" disp/unreg on unknown instance"); + goto error_or_nochange; + } + else + { + TRACE (" new instance"); + stored = rhc_store_new_instance (&inst, rhc, pwr_info, sample, tk, has_data, &cb_data, &post, &trig_qc); + if (stored != RHC_STORED) + { + goto error_or_nochange; + } + init_trigger_info_cmn_nonmatch (&pre.c); + notify_data_available = true; + } + } + else if (!inst_accepts_sample (rhc, inst, pwr_info, sample, has_data)) + { + /* Rejected samples (and disposes) should still register the writer; + unregister *must* be processed, or we have a memory leak. (We + will raise a SAMPLE_REJECTED, and indicate that the system should + kill itself.) Not letting instances go to ALIVE or NEW based on + a rejected sample - (no one knows, it seemed) */ + TRACE (" instance rejects sample"); + + get_trigger_info_pre (&pre, inst); + if (has_data || is_dispose) + { + dds_rhc_register (rhc, inst, wr_iid, false); + } + if (statusinfo & NN_STATUSINFO_UNREGISTER) + { + if (dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc)) + notify_data_available = true; + } + else + { + get_trigger_info_cmn (&post.c, inst); + } + /* notify sample lost */ + + cb_data.raw_status_id = (int) DDS_SAMPLE_LOST_STATUS_ID; + cb_data.extra = 0; + cb_data.handle = 0; + cb_data.add = true; + goto error_or_nochange; + + /* FIXME: deadline (and other) QoS? */ + } + else + { + get_trigger_info_pre (&pre, inst); + + TRACE (" wc %"PRIu32, inst->wrcount); + + if (has_data || is_dispose) + { + /* View state must be NEW following receipt of a sample when + instance was NOT_ALIVE (whether DISPOSED or NO_WRITERS). + Once we start fiddling with the state, we can no longer + figure out whether it is alive or not, so determine whether + it is currently NOT_ALIVE. */ + const int not_alive = inst->wrcount == 0 || inst->isdisposed; + const bool old_isdisposed = inst->isdisposed; + const bool old_isnew = inst->isnew; + const bool was_empty = inst_is_empty (inst); + int inst_became_disposed = 0; + + /* Not just an unregister, so a write and/or a dispose (possibly + combined with an unregister). Write & dispose create a + registration and we always do that, even if we have to delete + it immediately afterward. It seems unlikely to be worth the + effort of optimising this, but it can be done. On failure + (i.e., out-of-memory), abort the operation and hope that the + caller can still notify the application. */ + + dds_rhc_register (rhc, inst, wr_iid, true); + + /* Sample arriving for a NOT_ALIVE instance => view state NEW */ + if (has_data && not_alive) + { + TRACE (" notalive->alive"); + inst->isnew = 1; + } + + /* Desired effect on instance state and disposed_gen: + op DISPOSED NOT_DISPOSED + W ND;gen++ ND + D D D + WD D;gen++ D + Simplest way is to toggle istate when it is currently DISPOSED + and the operation is WD. */ + if (has_data && inst->isdisposed) + { + TRACE (" disposed->notdisposed"); + inst->isdisposed = 0; + inst->disposed_gen++; + } + if (is_dispose) + { + inst->isdisposed = 1; + inst_became_disposed = !old_isdisposed; + TRACE (" dispose(%d)", inst_became_disposed); + } + + /* Only need to add a sample to the history if the input actually + is a sample. */ + if (has_data) + { + TRACE (" add_sample"); + if (!add_sample (rhc, inst, pwr_info, sample, &cb_data, &trig_qc)) + { + TRACE ("(reject)"); + stored = RHC_REJECTED; + + /* FIXME: fix the bad rejection handling, probably put back in a proper rollback, until then a band-aid like this will have to do: */ + inst->isnew = old_isnew; + inst->isdisposed = old_isdisposed; + if (old_isdisposed) + inst->disposed_gen--; + goto error_or_nochange; + } + notify_data_available = true; + } + + /* If instance became disposed, add an invalid sample if there are no samples left */ + if (inst_became_disposed && inst->latest == NULL) + inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); + + update_inst (inst, pwr_info, true, sample->timestamp); + + /* Can only add samples => only need to give special treatment + to instances that were empty before. It is, however, not + guaranteed that we end up with a non-empty instance: for + example, if the instance was disposed & empty, nothing + changes. */ + if (inst->latest || inst_became_disposed) + { + if (was_empty) + { + /* general function is slightly slower than a specialised + one, but perhaps it is wiser to use the general one */ + account_for_empty_to_nonempty_transition (rhc, inst); + } + else + { + rhc->n_not_alive_disposed += (uint32_t)(inst->isdisposed - old_isdisposed); + rhc->n_new += (uint32_t)(inst->isnew - old_isnew); + } + } + else + { + assert (inst_is_empty (inst) == was_empty); + } + } + + assert (rhc_check_counts_locked (rhc, false, false)); + + if (statusinfo & NN_STATUSINFO_UNREGISTER) + { + /* Either a pure unregister, or the instance rejected the sample + because of time stamps, content filter, or something else. If + the writer unregisters the instance, I think we should ignore + the acceptance filters and process it anyway. + + It is a bit unclear what + + write_w_timestamp(x,1) ; unregister_w_timestamp(x,0) + + actually means if BY_SOURCE ordering is selected: does that + mean an application reading "x" after the write and reading it + again after the unregister will see a change in the + no_writers_generation field? */ + dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc); + } + else + { + get_trigger_info_cmn (&post.c, inst); + } + } + + TRACE (")\n"); + + dds_entity *triggers[MAX_FAST_TRIGGERS]; + size_t ntriggers = 0; + if (trigger_info_differs (rhc, &pre, &post, &trig_qc)) + update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst, triggers, &ntriggers); + + assert (rhc_check_counts_locked (rhc, true, true)); + + ddsrt_mutex_unlock (&rhc->lock); + + if (rhc->reader) + { + if (notify_data_available) + dds_reader_data_available_cb (rhc->reader); + for (size_t i = 0; i < ntriggers; i++) + dds_entity_status_signal (triggers[i], 0); + } + + return delivered; + +error_or_nochange: + + if (rhc->reliable && (stored == RHC_REJECTED)) + { + delivered = false; + } + + ddsrt_mutex_unlock (&rhc->lock); + TRACE (")\n"); + + /* Make any reader status callback */ + + if (cb_data.raw_status_id >= 0 && rhc->reader) + dds_reader_status_cb (&rhc->reader->m_entity, &cb_data); + return delivered; +} + +static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) +{ + /* Only to be called when writer with ID WR_IID has died. + + If we require that it will NEVER be resurrected, i.e., that next + time a new WR_IID will be used for the same writer, then we have + all the time in the world to scan the cache & clean up and that + we don't have to keep it locked all the time (even if we do it + that way now). + + WR_IID was never reused while the built-in topics weren't getting + generated, but those really require the same instance id for the + same GUID if an instance still exists in some reader for that GUID. + So, if unregistration without locking the RHC is desired, entities + need to get two IIDs: the one visible to the application in the + built-in topics and in get_instance_handle, and one used internally + for tracking registrations and unregistrations. */ + bool notify_data_available = false; + struct rhc_instance *inst; + struct ddsrt_hh_iter iter; + const uint64_t wr_iid = pwr_info->iid; + const int auto_dispose = pwr_info->auto_dispose; + + size_t ntriggers = SIZE_MAX; + + ddsrt_mutex_lock (&rhc->lock); + TRACE ("rhc_unregister_wr_iid(%"PRIx64",%d:\n", wr_iid, auto_dispose); + for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) + { + if ((inst->wr_iid_islive && inst->wr_iid == wr_iid) || lwregs_contains (&rhc->registrations, inst->iid, wr_iid)) + { + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + TRACE (" %"PRIx64":", inst->iid); + + assert (inst->wrcount > 0); + if (auto_dispose && !inst->isdisposed) + { + inst->isdisposed = 1; + + /* Set invalid sample for disposing it (unregister may also set it for unregistering) */ + if (inst->latest) + { + assert (!inst->inv_exists); + rhc->n_not_alive_disposed++; + } + else + { + const bool was_empty = inst_is_empty (inst); + inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); + if (was_empty) + account_for_empty_to_nonempty_transition (rhc, inst); + else + rhc->n_not_alive_disposed++; + } + } + + dds_rhc_unregister (rhc, inst, pwr_info, inst->tstamp, &post, &trig_qc); + + TRACE ("\n"); + + notify_data_available = true; + if (trigger_info_differs (rhc, &pre, &post, &trig_qc)) + update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst, NULL, &ntriggers); + assert (rhc_check_counts_locked (rhc, true, false)); + } + } + TRACE (")\n"); + + ddsrt_mutex_unlock (&rhc->lock); + + if (rhc->reader) + { + if (notify_data_available) + dds_reader_data_available_cb (rhc->reader); + } +} + +static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid) +{ + struct rhc_instance *inst; + struct ddsrt_hh_iter iter; + ddsrt_mutex_lock (&rhc->lock); + TRACE ("rhc_relinquish_ownership(%"PRIx64":\n", wr_iid); + for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) + { + if (inst->wr_iid_islive && inst->wr_iid == wr_iid) + { + inst->wr_iid_islive = 0; + } + } + TRACE (")\n"); + assert (rhc_check_counts_locked (rhc, true, false)); + ddsrt_mutex_unlock (&rhc->lock); +} + +/* STATUSES: + + sample: ANY, READ, NOT_READ + view: ANY, NEW, NOT_NEW + instance: ANY, ALIVE, NOT_ALIVE, NOT_ALIVE_NO_WRITERS, NOT_ALIVE_DISPOSED +*/ + +static unsigned qmask_of_inst (const struct rhc_instance *inst) +{ + unsigned qm = inst->isnew ? DDS_NEW_VIEW_STATE : DDS_NOT_NEW_VIEW_STATE; + + if (inst->isdisposed) + qm |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; + else if (inst->wrcount > 0) + qm |= DDS_ALIVE_INSTANCE_STATE; + else + qm |= DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; + + return qm; +} + +static uint32_t qmask_from_dcpsquery (uint32_t sample_states, uint32_t view_states, uint32_t instance_states) +{ + uint32_t qminv = 0; + + switch ((dds_sample_state_t) sample_states) + { + case DDS_SST_READ: + qminv |= DDS_NOT_READ_SAMPLE_STATE; + break; + case DDS_SST_NOT_READ: + qminv |= DDS_READ_SAMPLE_STATE; + break; + } + switch ((dds_view_state_t) view_states) + { + case DDS_VST_NEW: + qminv |= DDS_NOT_NEW_VIEW_STATE; + break; + case DDS_VST_OLD: + qminv |= DDS_NEW_VIEW_STATE; + break; + } + switch (instance_states) + { + case DDS_IST_ALIVE: + qminv |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE | DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; + break; + case DDS_IST_ALIVE | DDS_IST_NOT_ALIVE_DISPOSED: + qminv |= DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; + break; + case DDS_IST_ALIVE | DDS_IST_NOT_ALIVE_NO_WRITERS: + qminv |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; + break; + case DDS_IST_NOT_ALIVE_DISPOSED: + qminv |= DDS_ALIVE_INSTANCE_STATE | DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; + break; + case DDS_IST_NOT_ALIVE_DISPOSED | DDS_IST_NOT_ALIVE_NO_WRITERS: + qminv |= DDS_ALIVE_INSTANCE_STATE; + break; + case DDS_IST_NOT_ALIVE_NO_WRITERS: + qminv |= DDS_ALIVE_INSTANCE_STATE | DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; + break; + } + return qminv; +} + +static unsigned qmask_from_mask_n_cond (uint32_t mask, dds_readcond* cond) +{ + unsigned qminv; + if (mask == NO_STATE_MASK_SET) { + if (cond) { + /* No mask set, use the one from the condition. */ + qminv = cond->m_qminv; + } else { + /* No mask set and no condition: read all. */ + qminv = qmask_from_dcpsquery(DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE); + } + } else { + /* Merge given mask with the condition mask when needed. */ + qminv = qmask_from_dcpsquery(mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE); + if (cond != NULL) { + qminv &= cond->m_qminv; + } + } + return qminv; +} + +static void set_sample_info (dds_sample_info_t *si, const struct rhc_instance *inst, const struct rhc_sample *sample) +{ + si->sample_state = sample->isread ? DDS_SST_READ : DDS_SST_NOT_READ; + si->view_state = inst->isnew ? DDS_VST_NEW : DDS_VST_OLD; + si->instance_state = inst->isdisposed ? DDS_IST_NOT_ALIVE_DISPOSED : (inst->wrcount == 0) ? DDS_IST_NOT_ALIVE_NO_WRITERS : DDS_IST_ALIVE; + si->instance_handle = inst->iid; + si->publication_handle = sample->wr_iid; + si->disposed_generation_count = sample->disposed_gen; + si->no_writers_generation_count = sample->no_writers_gen; + si->sample_rank = 0; /* patch afterward: don't know last sample in returned set yet */ + si->generation_rank = 0; /* __/ */ + si->absolute_generation_rank = (inst->disposed_gen + inst->no_writers_gen) - (sample->disposed_gen + sample->no_writers_gen); + si->valid_data = true; + si->source_timestamp = sample->sample->timestamp.v; +} + +static void set_sample_info_invsample (dds_sample_info_t *si, const struct rhc_instance *inst) +{ + si->sample_state = inst->inv_isread ? DDS_SST_READ : DDS_SST_NOT_READ; + si->view_state = inst->isnew ? DDS_VST_NEW : DDS_VST_OLD; + si->instance_state = inst->isdisposed ? DDS_IST_NOT_ALIVE_DISPOSED : (inst->wrcount == 0) ? DDS_IST_NOT_ALIVE_NO_WRITERS : DDS_IST_ALIVE; + si->instance_handle = inst->iid; + si->publication_handle = inst->wr_iid; + si->disposed_generation_count = inst->disposed_gen; + si->no_writers_generation_count = inst->no_writers_gen; + si->sample_rank = 0; /* by construction always last in the set (but will get patched) */ + si->generation_rank = 0; /* __/ */ + si->absolute_generation_rank = 0; + si->valid_data = false; + si->source_timestamp = inst->tstamp.v; +} + +static void patch_generations (dds_sample_info_t *si, uint32_t last_of_inst) +{ + if (last_of_inst > 0) + { + const unsigned ref = + si[last_of_inst].disposed_generation_count + si[last_of_inst].no_writers_generation_count; + uint32_t i; + assert (si[last_of_inst].sample_rank == 0); + assert (si[last_of_inst].generation_rank == 0); + for (i = 0; i < last_of_inst; i++) + { + si[i].sample_rank = last_of_inst - i; + si[i].generation_rank = ref - (si[i].disposed_generation_count + si[i].no_writers_generation_count); + } + } +} + +static bool read_sample_update_conditions (struct dds_rhc_default *rhc, struct trigger_info_pre *pre, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, struct rhc_instance *inst, dds_querycond_mask_t conds, bool sample_wasread) +{ + /* No query conditions that are dependent on sample states */ + if (rhc->qconds_samplest == 0) + return false; + + /* Some, but perhaps none that matches this sample */ + if ((conds & rhc->qconds_samplest) == 0) + return false; + + TRACE("read_sample_update_conditions\n"); + trig_qc->dec_conds_sample = trig_qc->inc_conds_sample = conds; + trig_qc->dec_sample_read = sample_wasread; + trig_qc->inc_sample_read = true; + get_trigger_info_cmn (&post->c, inst); + size_t ntriggers = SIZE_MAX; + update_conditions_locked (rhc, false, pre, post, trig_qc, inst, NULL, &ntriggers); + trig_qc->dec_conds_sample = trig_qc->inc_conds_sample = 0; + pre->c = post->c; + return false; +} + +static bool take_sample_update_conditions (struct dds_rhc_default *rhc, struct trigger_info_pre *pre, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, struct rhc_instance *inst, dds_querycond_mask_t conds, bool sample_wasread) +{ + /* Mostly the same as read_...: but we are deleting samples (so no "inc sample") and need to process all query conditions that match this sample. */ + if (rhc->nqconds == 0 || conds == 0) + return false; + + TRACE("take_sample_update_conditions\n"); + trig_qc->dec_conds_sample = conds; + trig_qc->dec_sample_read = sample_wasread; + get_trigger_info_cmn (&post->c, inst); + size_t ntriggers = SIZE_MAX; + update_conditions_locked (rhc, false, pre, post, trig_qc, inst, NULL, &ntriggers); + trig_qc->dec_conds_sample = 0; + pre->c = post->c; + return false; +} + +static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + uint32_t n = 0; + + if (lock) + { + ddsrt_mutex_lock (&rhc->lock); + } + + TRACE ("read_w_qminv(%p,%p,%p,%"PRIu32",%x,%p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", + (void *) rhc, (void *) values, (void *) info_seq, max_samples, qminv, (void *) cond, + rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, + rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, + rhc->n_vread, rhc->n_invread); + + if (rhc->nonempty_instances) + { + const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; + struct rhc_instance * inst = rhc->nonempty_instances->next; + struct rhc_instance * const end = inst; + do + { + if (handle == DDS_HANDLE_NIL || inst->iid == handle) + { + if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) + { + /* samples present & instance, view state matches */ + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + const unsigned nread = inst_nread (inst); + const uint32_t n_first = n; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end1 = sample; + do + { + if ((qmask_of_sample (sample) & qminv) == 0 && (qcmask == 0 || (sample->conds & qcmask))) + { + /* sample state matches too */ + set_sample_info (info_seq + n, inst, sample); + ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); + if (!sample->isread) + { + TRACE ("s"); + read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, false); + sample->isread = true; + inst->nvread++; + rhc->n_vread++; + } + if (++n == max_samples) + { + break; + } + } + sample = sample->next; + } + while (sample != end1); + } + + if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask))) + { + set_sample_info_invsample (info_seq + n, inst); + topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); + if (!inst->inv_isread) + { + TRACE ("i"); + read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, false); + inst->inv_isread = 1; + rhc->n_invread++; + } + ++n; + } + + bool inst_became_old = false; + if (n > n_first && inst->isnew) + { + inst_became_old = true; + inst->isnew = 0; + rhc->n_new--; + } + if (nread != inst_nread (inst) || inst_became_old) + { + size_t ntriggers = SIZE_MAX; + get_trigger_info_cmn (&post.c, inst); + assert (trig_qc.dec_conds_invsample == 0); + assert (trig_qc.dec_conds_sample == 0); + assert (trig_qc.inc_conds_invsample == 0); + assert (trig_qc.inc_conds_sample == 0); + update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); + } + + if (n > n_first) { + patch_generations (info_seq + n_first, n - n_first - 1); + } + } + if (inst->iid == handle) + { + break; + } + } + inst = inst->next; + } + while (inst != end && n < max_samples); + } + TRACE ("read: returning %"PRIu32"\n", n); + assert (rhc_check_counts_locked (rhc, true, false)); + ddsrt_mutex_unlock (&rhc->lock); + assert (n <= INT_MAX); + return (int)n; +} + +static int dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + uint64_t iid; + uint32_t n = 0; + size_t ntriggers = SIZE_MAX; + + if (lock) + { + ddsrt_mutex_lock (&rhc->lock); + } + + TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", + (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, + rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, + rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, + rhc->n_invsamples, rhc->n_vread, rhc->n_invread); + + if (rhc->nonempty_instances) + { + const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; + struct rhc_instance *inst = rhc->nonempty_instances->next; + unsigned n_insts = rhc->n_nonempty_instances; + while (n_insts-- > 0 && n < max_samples) + { + struct rhc_instance * const inst1 = inst->next; + iid = inst->iid; + if (handle == DDS_HANDLE_NIL || iid == handle) + { + if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) + { + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + unsigned nvsamples = inst->nvsamples; + const uint32_t n_first = n; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + if (inst->latest) + { + struct rhc_sample *psample = inst->latest; + struct rhc_sample *sample = psample->next; + while (nvsamples--) + { + struct rhc_sample * const sample1 = sample->next; + + if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask != 0 && !(sample->conds & qcmask))) + { + /* sample mask doesn't match, or content predicate doesn't match */ + psample = sample; + } + else + { + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread); + + set_sample_info (info_seq + n, inst, sample); + ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); + rhc->n_vsamples--; + if (sample->isread) + { + inst->nvread--; + rhc->n_vread--; + } + + if (--inst->nvsamples > 0) + { + if (inst->latest == sample) + inst->latest = psample; + psample->next = sample1; + } + else + { + inst->latest = NULL; + } + + free_sample (inst, sample); + + if (++n == max_samples) + { + break; + } + } + sample = sample1; + } + } + + if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) + { + struct trigger_info_qcond dummy_trig_qc; +#ifndef NDEBUG + init_trigger_info_qcond (&dummy_trig_qc); +#endif + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread); + set_sample_info_invsample (info_seq + n, inst); + topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); + inst_clear_invsample (rhc, inst, &dummy_trig_qc); + ++n; + } + + if (n > n_first && inst->isnew) + { + inst->isnew = 0; + rhc->n_new--; + } + + if (n > n_first) + { + /* if nsamples = 0, it won't match anything, so no need to do + anything here for drop_instance_noupdate_no_writers */ + get_trigger_info_cmn (&post.c, inst); + assert (trig_qc.dec_conds_invsample == 0); + assert (trig_qc.dec_conds_sample == 0); + assert (trig_qc.inc_conds_invsample == 0); + assert (trig_qc.inc_conds_sample == 0); + update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); + } + + if (inst_is_empty (inst)) + { + remove_inst_from_nonempty_list (rhc, inst); + + if (inst->isdisposed) + { + rhc->n_not_alive_disposed--; + } + if (inst->wrcount == 0) + { + TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); + if (!inst->isdisposed) + { + /* disposed has priority over no writers (why not just 2 bits?) */ + rhc->n_not_alive_no_writers--; + } + drop_instance_noupdate_no_writers (rhc, inst); + } + } + + if (n > n_first) + patch_generations (info_seq + n_first, n - n_first - 1); + } + if (iid == handle) + { + break; + } + } + inst = inst1; + } + } + TRACE ("take: returning %"PRIu32"\n", n); + assert (rhc_check_counts_locked (rhc, true, false)); + ddsrt_mutex_unlock (&rhc->lock); + assert (n <= INT_MAX); + return (int)n; +} + +static int dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + uint64_t iid; + uint32_t n = 0; + (void)cond; + + if (lock) + { + ddsrt_mutex_lock (&rhc->lock); + } + + TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", + (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, + rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, + rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, + rhc->n_invsamples, rhc->n_vread, rhc->n_invread); + + if (rhc->nonempty_instances) + { + const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; + struct rhc_instance *inst = rhc->nonempty_instances->next; + unsigned n_insts = rhc->n_nonempty_instances; + while (n_insts-- > 0 && n < max_samples) + { + struct rhc_instance * const inst1 = inst->next; + iid = inst->iid; + if (handle == DDS_HANDLE_NIL || iid == handle) + { + if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) + { + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + unsigned nvsamples = inst->nvsamples; + const uint32_t n_first = n; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + if (inst->latest) + { + struct rhc_sample *psample = inst->latest; + struct rhc_sample *sample = psample->next; + while (nvsamples--) + { + struct rhc_sample * const sample1 = sample->next; + + if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask && !(sample->conds & qcmask))) + { + psample = sample; + } + else + { + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread); + set_sample_info (info_seq + n, inst, sample); + values[n] = ddsi_serdata_ref(sample->sample); + rhc->n_vsamples--; + if (sample->isread) + { + inst->nvread--; + rhc->n_vread--; + } + + if (--inst->nvsamples > 0) + psample->next = sample1; + else + inst->latest = NULL; + + free_sample (inst, sample); + + if (++n == max_samples) + { + break; + } + } + sample = sample1; + } + } + + if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) + { + struct trigger_info_qcond dummy_trig_qc; +#ifndef NDEBUG + init_trigger_info_qcond (&dummy_trig_qc); +#endif + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread); + set_sample_info_invsample (info_seq + n, inst); + values[n] = ddsi_serdata_ref(inst->tk->m_sample); + inst_clear_invsample (rhc, inst, &dummy_trig_qc); + ++n; + } + + if (n > n_first && inst->isnew) + { + inst->isnew = 0; + rhc->n_new--; + } + + if (n > n_first) + { + /* if nsamples = 0, it won't match anything, so no need to do + anything here for drop_instance_noupdate_no_writers */ + size_t ntriggers = SIZE_MAX; + get_trigger_info_cmn (&post.c, inst); + update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); + } + + if (inst_is_empty (inst)) + { + remove_inst_from_nonempty_list (rhc, inst); + + if (inst->isdisposed) + { + rhc->n_not_alive_disposed--; + } + if (inst->wrcount == 0) + { + TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); + if (!inst->isdisposed) + { + /* disposed has priority over no writers (why not just 2 bits?) */ + rhc->n_not_alive_no_writers--; + } + drop_instance_noupdate_no_writers (rhc, inst); + } + } + + if (n > n_first) + patch_generations (info_seq + n_first, n - n_first - 1); + } + if (iid == handle) + { + break; + } + } + inst = inst1; + } + } + TRACE ("take: returning %"PRIu32"\n", n); + assert (rhc_check_counts_locked (rhc, true, false)); + ddsrt_mutex_unlock (&rhc->lock); + assert (n <= INT_MAX); + return (int)n; +} + +/************************* + ****** WAITSET ****** + *************************/ + +static uint32_t rhc_get_cond_trigger (struct rhc_instance * const inst, const dds_readcond * const c) +{ + assert (!inst_is_empty (inst)); + bool m = ((qmask_of_inst (inst) & c->m_qminv) == 0); + switch (c->m_sample_states) + { + case DDS_SST_READ: + m = m && inst_has_read (inst); + break; + case DDS_SST_NOT_READ: + m = m && inst_has_unread (inst); + break; + case DDS_SST_READ | DDS_SST_NOT_READ: + case 0: + /* note: we get here only if inst not empty, so this is a no-op */ + m = m && !inst_is_empty (inst); + break; + default: + DDS_FATAL("update_readconditions: sample_states invalid: %"PRIx32"\n", c->m_sample_states); + } + return m ? 1 : 0; +} + +static bool cond_is_sample_state_dependent (const struct dds_readcond *cond) +{ + switch (cond->m_sample_states) + { + case DDS_SST_READ: + case DDS_SST_NOT_READ: + return true; + case DDS_SST_READ | DDS_SST_NOT_READ: + case 0: + return false; + default: + DDS_FATAL("update_readconditions: sample_states invalid: %"PRIx32"\n", cond->m_sample_states); + return false; + } +} + +static bool dds_rhc_default_add_readcondition (dds_readcond *cond) +{ + /* On the assumption that a readcondition will be attached to a + waitset for nearly all of its life, we keep track of all + readconditions on a reader in one set, without distinguishing + between those attached to a waitset or not. */ + struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc; + struct ddsrt_hh_iter it; + + assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) || + (dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_QUERY && cond->m_query.m_filter != 0)); + assert (ddsrt_atomic_ld32 (&cond->m_entity.m_status.m_trigger) == 0); + assert (cond->m_query.m_qcmask == 0); + + cond->m_qminv = qmask_from_dcpsquery (cond->m_sample_states, cond->m_view_states, cond->m_instance_states); + + ddsrt_mutex_lock (&rhc->lock); + + /* Allocate a slot in the condition bitmasks; return an error no more slots are available */ + if (cond->m_query.m_filter != 0) + { + dds_querycond_mask_t avail_qcmask = ~(dds_querycond_mask_t)0; + for (dds_readcond *rc = rhc->conds; rc != NULL; rc = rc->m_next) + { + assert ((rc->m_query.m_filter == 0 && rc->m_query.m_qcmask == 0) || (rc->m_query.m_filter != 0 && rc->m_query.m_qcmask != 0)); + avail_qcmask &= ~rc->m_query.m_qcmask; + } + if (avail_qcmask == 0) + { + /* no available indices */ + ddsrt_mutex_unlock (&rhc->lock); + return false; + } + + /* use the least significant bit set */ + cond->m_query.m_qcmask = avail_qcmask & (~avail_qcmask + 1); + } + + rhc->nconds++; + cond->m_next = rhc->conds; + rhc->conds = cond; + + uint32_t trigger = 0; + if (cond->m_query.m_filter == 0) + { + /* Read condition is not cached inside the instances and samples, so it only needs + to be evaluated on the non-empty instances */ + if (rhc->nonempty_instances) + { + struct rhc_instance *inst = rhc->nonempty_instances; + do { + trigger += rhc_get_cond_trigger (inst, cond); + inst = inst->next; + } while (inst != rhc->nonempty_instances); + } + } + else + { + if (cond_is_sample_state_dependent (cond)) + rhc->qconds_samplest |= cond->m_query.m_qcmask; + if (rhc->nqconds++ == 0) + { + assert (rhc->qcond_eval_samplebuf == NULL); + rhc->qcond_eval_samplebuf = ddsi_sertopic_alloc_sample (rhc->topic); + } + + /* Attaching a query condition means clearing the allocated bit in all instances and + samples, except for those that match the predicate. */ + const dds_querycond_mask_t qcmask = cond->m_query.m_qcmask; + for (struct rhc_instance *inst = ddsrt_hh_iter_first (rhc->instances, &it); inst != NULL; inst = ddsrt_hh_iter_next (&it)) + { + const bool instmatch = eval_predicate_invsample (rhc, inst, cond->m_query.m_filter);; + uint32_t matches = 0; + + inst->conds = (inst->conds & ~qcmask) | (instmatch ? qcmask : 0); + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + const bool m = eval_predicate_sample (rhc, sample->sample, cond->m_query.m_filter); + sample->conds = (sample->conds & ~qcmask) | (m ? qcmask : 0); + matches += m; + sample = sample->next; + } while (sample != end); + } + + if (!inst_is_empty (inst) && rhc_get_cond_trigger (inst, cond)) + trigger += (inst->inv_exists ? instmatch : 0) + matches; + } + } + + if (trigger) + { + ddsrt_atomic_st32 (&cond->m_entity.m_status.m_trigger, trigger); + dds_entity_status_signal (&cond->m_entity, DDS_DATA_AVAILABLE_STATUS); + } + + TRACE ("add_readcondition(%p, %"PRIx32", %"PRIx32", %"PRIx32") => %p qminv %"PRIx32" ; rhc %"PRIu32" conds\n", + (void *) rhc, cond->m_sample_states, cond->m_view_states, + cond->m_instance_states, (void *) cond, cond->m_qminv, rhc->nconds); + + ddsrt_mutex_unlock (&rhc->lock); + return true; +} + +static void dds_rhc_default_remove_readcondition (dds_readcond *cond) +{ + struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc; + dds_readcond **ptr; + ddsrt_mutex_lock (&rhc->lock); + ptr = &rhc->conds; + while (*ptr != cond) + ptr = &(*ptr)->m_next; + *ptr = (*ptr)->m_next; + rhc->nconds--; + if (cond->m_query.m_filter) + { + rhc->nqconds--; + rhc->qconds_samplest &= ~cond->m_query.m_qcmask; + cond->m_query.m_qcmask = 0; + if (rhc->nqconds == 0) + { + assert (rhc->qcond_eval_samplebuf != NULL); + ddsi_sertopic_free_sample (rhc->topic, rhc->qcond_eval_samplebuf, DDS_FREE_ALL); + rhc->qcond_eval_samplebuf = NULL; + } + } + ddsrt_mutex_unlock (&rhc->lock); +} + +static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst, struct dds_entity *triggers[], size_t *ntriggers) +{ + /* Pre: rhc->lock held; returns 1 if triggering required, else 0. */ + bool trigger = false; + dds_readcond *iter; + bool m_pre, m_post; + + TRACE ("update_conditions_locked(%p %p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32" read %"PRIu32"\n", + (void *) rhc, (void *) inst, rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, + rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_vread); + TRACE (" read -[%d,%d]+[%d,%d] qcmask -[%"PRIx32",%"PRIx32"]+[%"PRIx32",%"PRIx32"]\n", + trig_qc->dec_invsample_read, trig_qc->dec_sample_read, trig_qc->inc_invsample_read, trig_qc->inc_sample_read, + trig_qc->dec_conds_invsample, trig_qc->dec_conds_sample, trig_qc->inc_conds_invsample, trig_qc->inc_conds_sample); + + assert (rhc->n_nonempty_instances >= rhc->n_not_alive_disposed + rhc->n_not_alive_no_writers); + assert (rhc->n_nonempty_instances >= rhc->n_new); + assert (rhc->n_vsamples >= rhc->n_vread); + + iter = rhc->conds; + while (iter) + { + m_pre = ((pre->c.qminst & iter->m_qminv) == 0); + m_post = ((post->c.qminst & iter->m_qminv) == 0); + + /* Fast path out: instance did not and will not match based on instance, view states, so no + need to evaluate anything else */ + if (!m_pre && !m_post) + { + iter = iter->m_next; + continue; + } + + /* FIXME: use bitmask? */ + switch (iter->m_sample_states) + { + case DDS_SST_READ: + m_pre = m_pre && pre->c.has_read; + m_post = m_post && post->c.has_read; + break; + case DDS_SST_NOT_READ: + m_pre = m_pre && pre->c.has_not_read; + m_post = m_post && post->c.has_not_read; + break; + case DDS_SST_READ | DDS_SST_NOT_READ: + case 0: + m_pre = m_pre && (pre->c.has_read + pre->c.has_not_read); + m_post = m_post && (post->c.has_read + post->c.has_not_read); + break; + default: + DDS_FATAL ("update_readconditions: sample_states invalid: %"PRIx32"\n", iter->m_sample_states); + } + + TRACE (" cond %p %08"PRIx32": ", (void *) iter, iter->m_query.m_qcmask); + if (iter->m_query.m_filter == 0) + { + assert (dds_entity_kind (&iter->m_entity) == DDS_KIND_COND_READ); + if (m_pre == m_post) + TRACE ("no change"); + else if (m_pre < m_post) + { + TRACE ("now matches"); + trigger = (ddsrt_atomic_inc32_ov (&iter->m_entity.m_status.m_trigger) == 0); + if (trigger) + TRACE (" (cond now triggers)"); + } + else + { + TRACE ("no longer matches"); + if (ddsrt_atomic_dec32_nv (&iter->m_entity.m_status.m_trigger) == 0) + TRACE (" (cond no longer triggers)"); + } + } + else if (m_pre || m_post) /* no need to look any further if both are false */ + { + assert (dds_entity_kind (&iter->m_entity) == DDS_KIND_COND_QUERY); + assert (iter->m_query.m_qcmask != 0); + const dds_querycond_mask_t qcmask = iter->m_query.m_qcmask; + int32_t mdelta = 0; + + switch (iter->m_sample_states) + { + case DDS_SST_READ: + if (trig_qc->dec_invsample_read) + mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; + if (trig_qc->dec_sample_read) + mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; + if (trig_qc->inc_invsample_read) + mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; + if (trig_qc->inc_sample_read) + mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; + break; + case DDS_SST_NOT_READ: + if (!trig_qc->dec_invsample_read) + mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; + if (!trig_qc->dec_sample_read) + mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; + if (!trig_qc->inc_invsample_read) + mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; + if (!trig_qc->inc_sample_read) + mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; + break; + case DDS_SST_READ | DDS_SST_NOT_READ: + case 0: + mdelta -= (trig_qc->dec_conds_invsample & qcmask) != 0; + mdelta -= (trig_qc->dec_conds_sample & qcmask) != 0; + mdelta += (trig_qc->inc_conds_invsample & qcmask) != 0; + mdelta += (trig_qc->inc_conds_sample & qcmask) != 0; + break; + default: + DDS_FATAL ("update_readconditions: sample_states invalid: %"PRIx32"\n", iter->m_sample_states); + } + + if (m_pre == m_post) + { + assert (m_pre); + /* there was a match at read-condition level + - therefore the matching samples in the instance are accounted for in the trigger count + - therefore an incremental update is required + there is always space for a valid and an invalid sample, both add and remove + inserting an update always has unread data added, but a read pretends it is a removal + of whatever and an insertion of read data */ + assert (mdelta >= 0 || ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) >= (uint32_t) -mdelta); + if (mdelta == 0) + TRACE ("no change @ %"PRIu32" (0)", ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger)); + else + TRACE ("m=%"PRId32" @ %"PRIu32" (0)", mdelta, ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) + (uint32_t) mdelta); + /* even though it matches now and matched before, it is not a given that any of the samples + matched before, so m_trigger may still be 0 */ + const uint32_t ov = ddsrt_atomic_add32_ov (&iter->m_entity.m_status.m_trigger, (uint32_t) mdelta); + if (mdelta > 0 && ov == 0) + trigger = true; + if (trigger) + TRACE (" (cond now triggers)"); + else if (mdelta < 0 && ov == (uint32_t) -mdelta) + TRACE (" (cond no longer triggers)"); + } + else + { + /* There either was no match at read-condition level, now there is: scan all samples for matches; + or there was a match and now there is not: so also scan all samples for matches. The only + difference is in whether the number of matches should be added or subtracted. */ + int32_t mcurrent = 0; + if (inst->inv_exists) + mcurrent += (qmask_of_invsample (inst) & iter->m_qminv) == 0 && (inst->conds & qcmask) != 0; + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + mcurrent += (qmask_of_sample (sample) & iter->m_qminv) == 0 && (sample->conds & qcmask) != 0; + sample = sample->next; + } while (sample != end); + } + if (mdelta == 0 && mcurrent == 0) + TRACE ("no change @ %"PRIu32" (2)", ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger)); + else if (m_pre < m_post) + { + /* No match previously, so the instance wasn't accounted for at all in the trigger value. + Therefore when inserting data, all that matters is how many currently match. + + When reading or taking it is evaluated incrementally _before_ changing the state of the + sample, so mrem reflects the state before the change, and the incremental change needs + to be taken into account. */ + const int32_t m = called_from_insert ? mcurrent : mcurrent + mdelta; + TRACE ("mdelta=%"PRId32" mcurrent=%"PRId32" => %"PRId32" => %"PRIu32" (2a)", mdelta, mcurrent, m, ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) + (uint32_t) m); + assert (m >= 0 || ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) >= (uint32_t) -m); + trigger = (ddsrt_atomic_add32_ov (&iter->m_entity.m_status.m_trigger, (uint32_t) m) == 0 && m > 0); + if (trigger) + TRACE (" (cond now triggers)"); + } + else + { + /* Previously matched, but no longer, which means we need to subtract the current number + of matches as well as those that were removed just before, hence need the incremental + change as well */ + const int32_t m = mcurrent - mdelta; + TRACE ("mdelta=%"PRId32" mcurrent=%"PRId32" => %"PRId32" => %"PRIu32" (2b)", mdelta, mcurrent, m, ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) - (uint32_t) m); + assert (m < 0 || ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger) >= (uint32_t) m); + if (ddsrt_atomic_sub32_nv (&iter->m_entity.m_status.m_trigger, (uint32_t) m) == 0) + TRACE (" (cond no longer triggers)"); + } + } + } + + if (trigger) + { + if (*ntriggers < MAX_FAST_TRIGGERS) + triggers[(*ntriggers)++] = &iter->m_entity; + else + dds_entity_status_signal (&iter->m_entity, DDS_DATA_AVAILABLE_STATUS); + } + TRACE ("\n"); + iter = iter->m_next; + } + return trigger; +} + + +/************************* + ****** READ/TAKE ****** + *************************/ + +static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) +{ + unsigned qminv = qmask_from_mask_n_cond (mask, cond); + return dds_rhc_read_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); +} + +static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) +{ + unsigned qminv = qmask_from_mask_n_cond(mask, cond); + return dds_rhc_take_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); +} + +static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) +{ + unsigned qminv = qmask_from_dcpsquery (sample_states, view_states, instance_states); + return dds_rhc_takecdr_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, NULL); +} + +/************************* + ****** CHECK ****** + *************************/ + +#ifndef NDEBUG +#define CHECK_MAX_CONDS 64 +static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_conds, bool check_qcmask) +{ + if (!rhc->xchecks) + return 1; + + const uint32_t ncheck = rhc->nconds < CHECK_MAX_CONDS ? rhc->nconds : CHECK_MAX_CONDS; + unsigned n_instances = 0, n_nonempty_instances = 0; + unsigned n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0; + unsigned n_vsamples = 0, n_vread = 0; + unsigned n_invsamples = 0, n_invread = 0; + unsigned cond_match_count[CHECK_MAX_CONDS]; + dds_querycond_mask_t enabled_qcmask = 0; + struct rhc_instance *inst; + struct ddsrt_hh_iter iter; + dds_readcond *rciter; + uint32_t i; + + for (i = 0; i < CHECK_MAX_CONDS; i++) + cond_match_count[i] = 0; + + for (rciter = rhc->conds; rciter; rciter = rciter->m_next) + { + assert ((dds_entity_kind (&rciter->m_entity) == DDS_KIND_COND_READ && rciter->m_query.m_filter == 0) || + (dds_entity_kind (&rciter->m_entity) == DDS_KIND_COND_QUERY && rciter->m_query.m_filter != 0)); + assert ((rciter->m_query.m_filter != 0) == (rciter->m_query.m_qcmask != 0)); + assert (!(enabled_qcmask & rciter->m_query.m_qcmask)); + enabled_qcmask |= rciter->m_query.m_qcmask; + } + + for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) + { + unsigned n_vsamples_in_instance = 0, n_read_vsamples_in_instance = 0; + bool a_sample_free = true; + + n_instances++; + if (inst_is_empty (inst)) + continue; + + n_nonempty_instances++; + if (inst->isdisposed) + n_not_alive_disposed++; + else if (inst->wrcount == 0) + n_not_alive_no_writers++; + if (inst->isnew) + n_new++; + + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + if (sample == &inst->a_sample) + { + assert (a_sample_free); + a_sample_free = false; + } + n_vsamples++; + n_vsamples_in_instance++; + if (sample->isread) + { + n_vread++; + n_read_vsamples_in_instance++; + } + sample = sample->next; + } while (sample != end); + } + + if (inst->inv_exists) + { + n_invsamples++; + n_invread += inst->inv_isread; + } + + assert (n_read_vsamples_in_instance == inst->nvread); + assert (n_vsamples_in_instance == inst->nvsamples); + assert (a_sample_free == inst->a_sample_free); + + if (check_conds) + { + if (check_qcmask && rhc->nqconds > 0) + { + dds_querycond_mask_t qcmask; + topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, rhc->qcond_eval_samplebuf, 0, 0); + qcmask = 0; + for (rciter = rhc->conds; rciter; rciter = rciter->m_next) + if (rciter->m_query.m_filter != 0 && rciter->m_query.m_filter (rhc->qcond_eval_samplebuf)) + qcmask |= rciter->m_query.m_qcmask; + assert ((inst->conds & enabled_qcmask) == qcmask); + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + ddsi_serdata_to_sample (sample->sample, rhc->qcond_eval_samplebuf, NULL, NULL); + qcmask = 0; + for (rciter = rhc->conds; rciter; rciter = rciter->m_next) + if (rciter->m_query.m_filter != 0 && rciter->m_query.m_filter (rhc->qcond_eval_samplebuf)) + qcmask |= rciter->m_query.m_qcmask; + assert ((sample->conds & enabled_qcmask) == qcmask); + sample = sample->next; + } while (sample != end); + } + } + + for (i = 0, rciter = rhc->conds; i < ncheck; i++, rciter = rciter->m_next) + { + if (!rhc_get_cond_trigger (inst, rciter)) + ; + else if (rciter->m_query.m_filter == 0) + cond_match_count[i]++; + else + { + if (inst->inv_exists) + cond_match_count[i] += (qmask_of_invsample (inst) & rciter->m_qminv) == 0 && (inst->conds & rciter->m_query.m_qcmask) != 0; + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + cond_match_count[i] += ((qmask_of_sample (sample) & rciter->m_qminv) == 0 && (sample->conds & rciter->m_query.m_qcmask) != 0); + sample = sample->next; + } while (sample != end); + } + } + } + } + } + + assert (rhc->n_instances == n_instances); + assert (rhc->n_nonempty_instances == n_nonempty_instances); + assert (rhc->n_not_alive_disposed == n_not_alive_disposed); + assert (rhc->n_not_alive_no_writers == n_not_alive_no_writers); + assert (rhc->n_new == n_new); + assert (rhc->n_vsamples == n_vsamples); + assert (rhc->n_vread == n_vread); + assert (rhc->n_invsamples == n_invsamples); + assert (rhc->n_invread == n_invread); + + if (check_conds) + { + for (i = 0, rciter = rhc->conds; i < ncheck; i++, rciter = rciter->m_next) + { + assert (cond_match_count[i] == ddsrt_atomic_ld32 (&rciter->m_entity.m_status.m_trigger)); + } + } + + if (rhc->n_nonempty_instances == 0) + { + assert (rhc->nonempty_instances == NULL); + } + else + { + struct rhc_instance *prev, *end; + assert (rhc->nonempty_instances != NULL); + prev = rhc->nonempty_instances->prev; + end = rhc->nonempty_instances; + inst = rhc->nonempty_instances; + n_nonempty_instances = 0; + do { + assert (!inst_is_empty (inst)); + assert (prev->next == inst); + assert (inst->prev == prev); + prev = inst; + inst = inst->next; + n_nonempty_instances++; + } while (inst != end); + assert (rhc->n_nonempty_instances == n_nonempty_instances); + } + + return 1; +} +#undef CHECK_MAX_CONDS +#endif diff --git a/src/core/ddsc/src/dds_serdata_builtintopic.c b/src/core/ddsc/src/dds_serdata_builtintopic.c index 5cbd47b..1a97a40 100644 --- a/src/core/ddsc/src/dds_serdata_builtintopic.c +++ b/src/core/ddsc/src/dds_serdata_builtintopic.c @@ -19,7 +19,7 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" -#include "dds__key.h" +#include "dds/ddsi/q_plist.h" #include "dds__stream.h" #include "dds__serdata_builtintopic.h" #include "dds/ddsi/ddsi_tkmap.h" @@ -126,16 +126,17 @@ static void from_entity_pwr (struct ddsi_serdata_builtintopic *d, const struct p assert (d->xqos.present & QP_TYPE_NAME); } -struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) { /* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */ const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn; /* keyhash must in host format (which the GUIDs always are internally) */ - const struct entity_common *entity = ephash_lookup_guid_untyped ((const nn_guid_t *) keyhash->value); + struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const nn_guid_t *) keyhash->value); struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY); memcpy (&d->key, keyhash->value, sizeof (d->key)); if (entity) { + ddsrt_mutex_lock (&entity->qos_lock); switch (entity->kind) { case EK_PARTICIPANT: @@ -163,6 +164,7 @@ struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertop from_entity_pwr (d, (const struct proxy_writer *) entity); break; } + ddsrt_mutex_unlock (&entity->qos_lock); } return fix_serdata_builtin(d, tp->c.serdata_basehash); } @@ -187,24 +189,16 @@ static char *dds_string_dup_reuse (char *old, const char *src) return memcpy (new, src, size); } -static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const nn_xqos_t *src) +static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const dds_qos_t *src) { if (old == NULL) - { old = ddsrt_malloc (sizeof (*old)); - nn_xqos_init_empty (old); - old->present |= QP_TOPIC_NAME | QP_TYPE_NAME; - nn_xqos_mergein_missing (old, src); - old->present &= ~(QP_TOPIC_NAME | QP_TYPE_NAME); - } else { nn_xqos_fini (old); - nn_xqos_init_empty (old); - old->present |= QP_TOPIC_NAME | QP_TYPE_NAME; - nn_xqos_mergein_missing (old, src); - old->present &= ~(QP_TOPIC_NAME | QP_TYPE_NAME); } + nn_xqos_init_empty (old); + nn_xqos_mergein_missing (old, src, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); return old; } diff --git a/src/core/ddsc/src/dds_sertopic_builtintopic.c b/src/core/ddsc/src/dds_sertopic_builtintopic.c index b38deba..3479fa4 100644 --- a/src/core/ddsc/src/dds_sertopic_builtintopic.c +++ b/src/core/ddsc/src/dds_sertopic_builtintopic.c @@ -26,30 +26,18 @@ /* FIXME: sertopic /= ddstopic so a lot of stuff needs to be moved here from dds_topic.c and the free function needs to be implemented properly */ -struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename) +struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename, struct q_globals *gv) { struct ddsi_sertopic_builtintopic *tp = ddsrt_malloc (sizeof (*tp)); - tp->c.iid = ddsi_iid_gen(); - tp->c.name = dds_string_dup (name); - tp->c.type_name = dds_string_dup (typename); - const size_t name_typename_size = strlen (tp->c.name) + 1 + strlen (tp->c.type_name) + 1; - tp->c.name_type_name = dds_alloc (name_typename_size); - snprintf (tp->c.name_type_name, name_typename_size, "%s/%s", tp->c.name, tp->c.type_name); - tp->c.ops = &ddsi_sertopic_ops_builtintopic; - tp->c.serdata_ops = &ddsi_serdata_ops_builtintopic; - tp->c.serdata_basehash = ddsi_sertopic_compute_serdata_basehash (tp->c.serdata_ops); - tp->c.status_cb = 0; - tp->c.status_cb_entity = NULL; - ddsrt_atomic_st32 (&tp->c.refc, 1); + ddsi_sertopic_init (&tp->c, name, typename, &ddsi_sertopic_ops_builtintopic, &ddsi_serdata_ops_builtintopic, false); tp->type = type; + tp->gv = gv; return &tp->c; } static void sertopic_builtin_free (struct ddsi_sertopic *tp) { - ddsrt_free (tp->name_type_name); - ddsrt_free (tp->name); - ddsrt_free (tp->type_name); + ddsi_sertopic_fini (tp); ddsrt_free (tp); } @@ -95,7 +83,7 @@ static void sertopic_builtin_realloc_samples (void **ptrs, const struct ddsi_ser { const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)sertopic_common; const size_t size = get_size (tp->type); - char *new = dds_realloc (old, size * count); + char *new = (oldcount == count) ? old : dds_realloc (old, size * count); if (new && count > oldcount) memset (new + size * oldcount, 0, size * (count - oldcount)); for (size_t i = 0; i < count; i++) diff --git a/src/core/ddsc/src/dds_stream.c b/src/core/ddsc/src/dds_stream.c index 9d7505c..c2264c0 100644 --- a/src/core/ddsc/src/dds_stream.c +++ b/src/core/ddsc/src/dds_stream.c @@ -14,1660 +14,1670 @@ #include "dds/ddsrt/endian.h" #include "dds/ddsrt/md5.h" +#include "dds/ddsrt/heap.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds__stream.h" -#include "dds__key.h" #include "dds__alloc.h" -//#define OP_DEBUG_READ 1 -//#define OP_DEBUG_WRITE 1 -//#define OP_DEBUG_KEY 1 - -#if defined OP_DEBUG_WRITE || defined OP_DEBUG_READ || defined OP_DEBUG_KEY -static const char * stream_op_type[11] = -{ - NULL, "1Byte", "2Byte", "4Byte", "8Byte", "String", - "BString", "Sequence", "Array", "Union", "Struct" -}; -#endif - #if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN #define DDS_ENDIAN true #else #define DDS_ENDIAN false #endif -const uint32_t dds_op_size[5] = { 0, 1u, 2u, 4u, 8u }; +static void dds_stream_write (dds_ostream_t * __restrict os, const char * __restrict data, const uint32_t * __restrict ops); +static void dds_stream_read (dds_istream_t * __restrict is, char * __restrict data, const uint32_t * __restrict ops); -static void dds_stream_write (dds_stream_t * os, const char * data, const uint32_t * ops); -static void dds_stream_read (dds_stream_t * is, char * data, const uint32_t * ops); - -#define DDS_SWAP16(v) \ - ((uint16_t)(((v) >> 8) | ((v) << 8))) -#define DDS_SWAP32(v) \ - (((v) >> 24) | \ - (((v) & 0x00ff0000) >> 8) | \ - (((v) & 0x0000ff00) << 8) | \ - ((v) << 24)) -#define DDS_SWAP64(v) \ - (((v)) >> 56) | \ - ((((v)) & 0x00ff000000000000) >> 40) | \ - ((((v)) & 0x0000ff0000000000) >> 24) | \ - ((((v)) & 0x000000ff00000000) >> 8) | \ - ((((v)) & 0x00000000ff000000) << 8) | \ - ((((v)) & 0x0000000000ff0000) << 24) | \ - ((((v)) & 0x000000000000ff00) << 40) | \ - (((v)) << 56) - -#define DDS_CDR_ALIGN2(s) ((s)->m_index = ((s)->m_index + 1U) & ~1U) -#define DDS_CDR_ALIGN4(s) ((s)->m_index = ((s)->m_index + 3U) & ~3U) -#define DDS_CDR_ALIGN8(s) ((s)->m_index = ((s)->m_index + 7U) & ~7U) -#define DDS_CDR_ALIGNTO(s,n) ((s)->m_index = ((s)->m_index + (n-1)) & ~(n-1)) -#define DDS_CDR_ALIGNED(s,n) ((n) && ((s)->m_index % (n)) == 0) - -#define DDS_CDR_ADDRESS(c, type) ((type*) &((c)->m_buffer.p8[(c)->m_index])) -#define DDS_CDR_RESET(c) \ - (c)->m_index = 0ul; \ - (c)->m_failed = false; -#define DDS_CDR_RESIZE(c,l) if (((c)->m_size < ((l) + (c)->m_index))) dds_stream_grow (c, l) -#define DDS_CDR_REINIT(c,s) \ - DDS_CDR_RESET(c); \ - (c)->m_endian = DDS_ENDIAN; \ - if ((c)->m_size < (s)) dds_stream_grow (c, s) - -#ifndef NDEBUG -#define DDS_IS_OK(s,n) (!((s)->m_failed = ((s)->m_index + (n)) > (s)->m_size)) -#else -#define DDS_IS_OK(s,n) (true) -#endif - -#define DDS_IS_GET1(s) (s)->m_buffer.p8[(s)->m_index++] - -#define DDS_IS_GET2(s,v) \ - (v) = *DDS_CDR_ADDRESS ((s), uint16_t); \ - if ((s)->m_endian != DDS_ENDIAN) (v) = DDS_SWAP16 ((v)); \ - (s)->m_index += 2 - -#define DDS_IS_GET4(s,v,t) \ - (v) = *DDS_CDR_ADDRESS ((s), t); \ - if ((s)->m_endian != DDS_ENDIAN) (v) = (t)(DDS_SWAP32 ((uint32_t) (v))); \ - (s)->m_index += 4; - -#define DDS_IS_GET8(s,v,t) \ - (v) = *DDS_CDR_ADDRESS ((s), t); \ - if ((s)->m_endian != DDS_ENDIAN) (v) = (t)(DDS_SWAP64 ((uint64_t) (v))); \ - (s)->m_index += 8 - -#define DDS_IS_GET_BYTES(s,b,l) \ - memcpy (b, DDS_CDR_ADDRESS ((s), void), l); \ - (s)->m_index += (l) - -#define DDS_OS_PUT1(s,v) \ - DDS_CDR_RESIZE (s, 1u); \ - *DDS_CDR_ADDRESS (s, uint8_t) = v; \ - (s)->m_index += 1 - -#define DDS_OS_PUT2(s,v) \ - DDS_CDR_ALIGN2 (s); \ - DDS_CDR_RESIZE (s, 2u); \ - *DDS_CDR_ADDRESS (s, uint16_t) = ((s)->m_endian == DDS_ENDIAN) ? \ - v : DDS_SWAP16 ((uint16_t) (v)); \ - (s)->m_index += 2 - -#define DDS_OS_PUT4(s,v,t) \ - DDS_CDR_ALIGN4 (s); \ - DDS_CDR_RESIZE (s, 4u); \ - *DDS_CDR_ADDRESS (s, t) = ((s)->m_endian == DDS_ENDIAN) ? \ - v : DDS_SWAP32 ((uint32_t) (v)); \ - (s)->m_index += 4 - -#define DDS_OS_PUT8(s,v,t) \ - DDS_CDR_ALIGN8 (s); \ - DDS_CDR_RESIZE (s, 8u); \ - *DDS_CDR_ADDRESS (s, t) = ((s)->m_endian == DDS_ENDIAN) ? \ - v : DDS_SWAP64 ((uint64_t) (v)); \ - (s)->m_index += 8 - -#define DDS_OS_PUT_BYTES(s,b,l) \ - DDS_CDR_RESIZE (s, l); \ - memcpy (DDS_CDR_ADDRESS (s, void), b, l); \ - (s)->m_index += (l) - -bool dds_stream_endian (void) -{ - return DDS_ENDIAN; -} - -size_t dds_stream_check_optimize (const dds_topic_descriptor_t * desc) -{ - dds_stream_t os; - void * sample = dds_alloc (desc->m_size); - uint8_t * ptr1; - uint8_t * ptr2; - uint32_t size = desc->m_size; - uint8_t val = 1; - - dds_stream_init (&os, size); - ptr1 = (uint8_t*) sample; - ptr2 = os.m_buffer.p8; - while (size--) - { - *ptr1++ = val; - *ptr2++ = val++; - } - - dds_stream_write (&os, sample, desc->m_ops); - size = (memcmp (sample, os.m_buffer.p8, desc->m_size) == 0) ? os.m_index : 0; - - dds_sample_free_contents (sample, desc->m_ops); - dds_free (sample); - dds_stream_fini (&os); - DDS_TRACE("Marshalling for type: %s is%s optimised\n", desc->m_typename, size ? "" : " not"); - return size; -} - -dds_stream_t * dds_stream_create (uint32_t size) -{ - dds_stream_t * stream = (dds_stream_t*) dds_alloc (sizeof (*stream)); - dds_stream_init (stream, size); - return stream; -} - -void dds_stream_delete (dds_stream_t * st) -{ - dds_stream_fini (st); - dds_free (st); -} - -void dds_stream_fini (dds_stream_t * st) -{ - if (st->m_size) - { - dds_free (st->m_buffer.p8); - } -} - -void dds_stream_init (dds_stream_t * st, uint32_t size) -{ - memset (st, 0, sizeof (*st)); - DDS_CDR_REINIT (st, size); -} - -void dds_stream_reset (dds_stream_t * st) -{ - DDS_CDR_RESET (st); -} - -void dds_stream_grow (dds_stream_t * st, uint32_t size) +static void dds_ostream_grow (dds_ostream_t * __restrict st, uint32_t size) { uint32_t needed = size + st->m_index; /* Reallocate on 4k boundry */ uint32_t newSize = (needed & ~(uint32_t)0xfff) + 0x1000; - uint8_t * old = st->m_buffer.p8; + uint8_t *old = st->m_buffer; - st->m_buffer.p8 = dds_realloc (old, newSize); - memset (st->m_buffer.p8 + st->m_size, 0, newSize - st->m_size); + st->m_buffer = ddsrt_realloc (old, newSize); st->m_size = newSize; } -bool dds_stream_read_bool (dds_stream_t * is) +static void dds_cdr_resize (dds_ostream_t * __restrict s, uint32_t l) { - return (dds_stream_read_uint8 (is) != 0); + if (s->m_size < l + s->m_index) + dds_ostream_grow (s, l); } -uint8_t dds_stream_read_uint8 (dds_stream_t * is) +void dds_ostream_init (dds_ostream_t * __restrict st, uint32_t size) { - return DDS_IS_OK (is, 1) ? DDS_IS_GET1 (is) : 0; + memset (st, 0, sizeof (*st)); + st->m_index = 0; + dds_cdr_resize (st, size); } -uint16_t dds_stream_read_uint16 (dds_stream_t * is) +void dds_ostreamBE_init (dds_ostreamBE_t * __restrict st, uint32_t size) { - uint16_t val = 0; - DDS_CDR_ALIGN2 (is); - if (DDS_IS_OK (is, 2)) + dds_ostream_init (&st->x, size); +} + +void dds_ostream_fini (dds_ostream_t * __restrict st) +{ + if (st->m_size) + dds_free (st->m_buffer); +} + +void dds_ostreamBE_fini (dds_ostreamBE_t * __restrict st) +{ + dds_ostream_fini (&st->x); +} + +static void dds_cdr_alignto (dds_istream_t * __restrict s, uint32_t a) +{ + s->m_index = (s->m_index + a - 1) & ~(a - 1); + assert (s->m_index < s->m_size); +} + +static uint32_t dds_cdr_alignto_clear_and_resize (dds_ostream_t * __restrict s, uint32_t a, uint32_t extra) +{ + const uint32_t m = s->m_index % a; + if (m == 0) { - DDS_IS_GET2 (is, val); - } - return val; -} - -uint32_t dds_stream_read_uint32 (dds_stream_t * is) -{ - uint32_t val = 0; - DDS_CDR_ALIGN4 (is); - if (DDS_IS_OK (is, 4)) - { - DDS_IS_GET4 (is, val, uint32_t); - } - return val; -} - -uint64_t dds_stream_read_uint64 (dds_stream_t * is) -{ - uint64_t val = 0; - DDS_CDR_ALIGN8 (is); - if (DDS_IS_OK (is, 8)) - { - DDS_IS_GET8 (is, val, uint64_t); - } - return val; -} - -extern inline char dds_stream_read_char (dds_stream_t *is); -extern inline int8_t dds_stream_read_int8 (dds_stream_t *is); -extern inline int16_t dds_stream_read_int16 (dds_stream_t *is); -extern inline int32_t dds_stream_read_int32 (dds_stream_t *is); -extern inline int64_t dds_stream_read_int64 (dds_stream_t *is); - -float dds_stream_read_float (dds_stream_t * is) -{ - float val = 0.0; - DDS_CDR_ALIGN4 (is); - if (DDS_IS_OK (is, 4)) - { - DDS_IS_GET4 (is, val, float); - } - return val; -} - -double dds_stream_read_double (dds_stream_t * is) -{ - double val = 0.0; - DDS_CDR_ALIGN8 (is); - if (DDS_IS_OK (is, 8)) - { - DDS_IS_GET8 (is, val, double); - } - return val; -} - -char * dds_stream_reuse_string - (dds_stream_t * is, char * str, const uint32_t bound) -{ - uint32_t length; - void * src; - - DDS_CDR_ALIGN4 (is); - if (DDS_IS_OK (is, 4)) - { - DDS_IS_GET4 (is, length, uint32_t); - if (DDS_IS_OK (is, length)) - { - src = DDS_CDR_ADDRESS (is, void); - if (bound) - { - memcpy (str, src, length > bound ? bound : length); - } - else - { - if ((str == NULL) || (strlen (str) + 1 < length)) - { - str = dds_realloc (str, length); - } - memcpy (str, src, length); - } - is->m_index += length; - } - } - - return str; -} - -char * dds_stream_read_string (dds_stream_t * is) -{ - return dds_stream_reuse_string (is, NULL, 0); -} - -void dds_stream_swap (void * buff, uint32_t size, uint32_t num) -{ - assert (size == 2 || size == 4 || size == 8); - - switch (size) - { - case 2: - { - uint16_t * ptr = (uint16_t*) buff; - while (num--) - { - *ptr = DDS_SWAP16 (*ptr); - ptr++; - } - break; - } - case 4: - { - uint32_t * ptr = (uint32_t*) buff; - while (num--) - { - *ptr = DDS_SWAP32 (*ptr); - ptr++; - } - break; - } - default: - { - uint64_t * ptr = (uint64_t*) buff; - while (num--) - { - *ptr = DDS_SWAP64 (*ptr); - ptr++; - } - break; - } - } -} - -static void dds_stream_read_fixed_buffer - (dds_stream_t * is, void * buff, uint32_t len, const uint32_t size, const bool swap) -{ - if (size && len) - { - DDS_CDR_ALIGNTO (is, size); - DDS_IS_GET_BYTES (is, buff, len * size); - if (swap && (size > 1)) - { - dds_stream_swap (buff, size, len); - } - } -} - -void dds_stream_read_buffer (dds_stream_t * is, uint8_t * buffer, uint32_t len) -{ - if (DDS_IS_OK (is, len)) - { - DDS_IS_GET_BYTES (is, buffer, len); - } -} - -void dds_stream_read_sample (dds_stream_t * is, void * data, const struct ddsi_sertopic_default * topic) -{ - const struct dds_topic_descriptor * desc = topic->type; - /* Check if can copy directly from stream buffer */ - if (topic->opt_size && DDS_IS_OK (is, desc->m_size) && (is->m_endian == DDS_ENDIAN)) - { - DDS_IS_GET_BYTES (is, data, desc->m_size); + dds_cdr_resize (s, extra); + return 0; } else { - dds_stream_read (is, data, desc->m_ops); + const uint32_t pad = a - m; + dds_cdr_resize (s, pad + extra); + for (uint32_t i = 0; i < pad; i++) + s->m_buffer[s->m_index++] = 0; + return pad; } } -void dds_stream_write_bool (dds_stream_t * os, bool val) +static uint32_t dds_cdr_alignto_clear_and_resize_be (dds_ostreamBE_t * __restrict s, uint32_t a, uint32_t extra) { - dds_stream_write_uint8 (os, val ? 1 : 0); + return dds_cdr_alignto_clear_and_resize (&s->x, a, extra); } -void dds_stream_write_uint8 (dds_stream_t * os, uint8_t val) +static uint8_t dds_is_get1 (dds_istream_t * __restrict s) { - DDS_OS_PUT1 (os, val); + assert (s->m_index < s->m_size); + uint8_t v = *(s->m_buffer + s->m_index); + s->m_index++; + return v; } -void dds_stream_write_uint16 (dds_stream_t * os, uint16_t val) +static uint16_t dds_is_get2 (dds_istream_t * __restrict s) { - DDS_OS_PUT2 (os, val); + dds_cdr_alignto (s, 2); + uint16_t v = * ((uint16_t *) (s->m_buffer + s->m_index)); + s->m_index += 2; + return v; } -void dds_stream_write_uint32 (dds_stream_t * os, uint32_t val) +static uint32_t dds_is_get4 (dds_istream_t * __restrict s) { - DDS_OS_PUT4 (os, val, uint32_t); + dds_cdr_alignto (s, 4); + uint32_t v = * ((uint32_t *) (s->m_buffer + s->m_index)); + s->m_index += 4; + return v; } -void dds_stream_write_uint64 (dds_stream_t * os, uint64_t val) +static uint64_t dds_is_get8 (dds_istream_t * __restrict s) { - DDS_OS_PUT8 (os, val, uint64_t); + dds_cdr_alignto (s, 8); + uint64_t v = * ((uint64_t *) (s->m_buffer + s->m_index)); + s->m_index += 8; + return v; } -extern inline void dds_stream_write_char (dds_stream_t * os, char val); -extern inline void dds_stream_write_int8 (dds_stream_t * os, int8_t val); -extern inline void dds_stream_write_int16 (dds_stream_t * os, int16_t val); -extern inline void dds_stream_write_int32 (dds_stream_t * os, int32_t val); -extern inline void dds_stream_write_int64 (dds_stream_t * os, int64_t val); - -void dds_stream_write_float (dds_stream_t * os, float val) +static void dds_is_get_bytes (dds_istream_t * __restrict s, void * __restrict b, uint32_t num, uint32_t elem_size) { - union { float f; uint32_t u; } u; - u.f = val; - dds_stream_write_uint32 (os, u.u); + dds_cdr_alignto (s, elem_size); + memcpy (b, s->m_buffer + s->m_index, num * elem_size); + s->m_index += num * elem_size; } -void dds_stream_write_double (dds_stream_t * os, double val) +static void dds_os_put1 (dds_ostream_t * __restrict s, uint8_t v) { - union { double f; uint64_t u; } u; - u.f = val; - dds_stream_write_uint64 (os, u.u); + dds_cdr_resize (s, 1); + *((uint8_t *) (s->m_buffer + s->m_index)) = v; + s->m_index += 1; } -void dds_stream_write_string (dds_stream_t * os, const char * val) +static void dds_os_put2 (dds_ostream_t * __restrict s, uint16_t v) +{ + dds_cdr_alignto_clear_and_resize (s, 2, 2); + *((uint16_t *) (s->m_buffer + s->m_index)) = v; + s->m_index += 2; +} + +static void dds_os_put4 (dds_ostream_t * __restrict s, uint32_t v) +{ + dds_cdr_alignto_clear_and_resize (s, 4, 4); + *((uint32_t *) (s->m_buffer + s->m_index)) = v; + s->m_index += 4; +} + +static void dds_os_put8 (dds_ostream_t * __restrict s, uint64_t v) +{ + dds_cdr_alignto_clear_and_resize (s, 8, 8); + *((uint64_t *) (s->m_buffer + s->m_index)) = v; + s->m_index += 8; +} + +static void dds_os_put1be (dds_ostreamBE_t * __restrict s, uint8_t v) +{ + dds_os_put1 (&s->x, v); +} + +static void dds_os_put2be (dds_ostreamBE_t * __restrict s, uint16_t v) +{ + dds_os_put2 (&s->x, toBE2u (v)); +} + +static void dds_os_put4be (dds_ostreamBE_t * __restrict s, uint32_t v) +{ + dds_os_put4 (&s->x, toBE4u (v)); +} + +static void dds_os_put8be (dds_ostreamBE_t * __restrict s, uint64_t v) +{ + dds_os_put8 (&s->x, toBE8u (v)); +} + +static void dds_os_put_bytes (dds_ostream_t * __restrict s, const void * __restrict b, uint32_t l) +{ + dds_cdr_resize (s, l); + memcpy (s->m_buffer + s->m_index, b, l); + s->m_index += l; +} + +static void dds_os_put_bytes_aligned (dds_ostream_t * __restrict s, const void * __restrict b, uint32_t n, uint32_t a) +{ + const uint32_t l = n * a; + dds_cdr_alignto_clear_and_resize (s, a, l); + memcpy (s->m_buffer + s->m_index, b, l); + s->m_index += l; +} + +static uint32_t get_type_size (enum dds_stream_typecode type) +{ + DDSRT_STATIC_ASSERT (DDS_OP_VAL_1BY == 1 && DDS_OP_VAL_2BY == 2 && DDS_OP_VAL_4BY == 3 && DDS_OP_VAL_8BY == 4); + assert (type == DDS_OP_VAL_1BY || type == DDS_OP_VAL_2BY || type == DDS_OP_VAL_4BY || type == DDS_OP_VAL_8BY); + return (uint32_t)1 << ((uint32_t) type - 1); +} + +static size_t dds_stream_check_optimize1 (const dds_topic_descriptor_t * __restrict desc) +{ + const uint32_t *ops = desc->m_ops; + uint32_t insn; + while ((insn = *ops) != DDS_OP_RTS) + { + if (DDS_OP (insn) != DDS_OP_ADR) + return 0; + + switch (DDS_OP_TYPE (insn)) + { + case DDS_OP_VAL_1BY: + case DDS_OP_VAL_2BY: + case DDS_OP_VAL_4BY: + case DDS_OP_VAL_8BY: + if ((ops[1] % get_type_size (DDS_OP_TYPE (insn))) != 0) + return 0; + ops += 2; + break; + + case DDS_OP_VAL_ARR: + switch (DDS_OP_SUBTYPE (insn)) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: + if ((ops[1] % get_type_size (DDS_OP_SUBTYPE (insn))) != 0) + return 0; + ops += 3; + break; + default: + return 0; + } + break; + + default: + return 0; + } + } + + return desc->m_size; +} + +size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc) +{ + return dds_stream_check_optimize1 (desc); +} + +static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound) +{ + const uint32_t length = dds_is_get4 (is); + const void *src = is->m_buffer + is->m_index; + if (bound) + { + /* FIXME: validation now rejects data containing an oversize bounded string, + so this check is superfluous, but perhaps rejecting such a sample is the + wrong thing to do */ + assert (str != NULL); + memcpy (str, src, length > bound ? bound : length); + } + else + { + if (str == NULL || strlen (str) + 1 < length) + str = dds_realloc (str, length); + memcpy (str, src, length); + } + is->m_index += length; + return str; +} + +static void dds_stream_skip_forward (dds_istream_t * __restrict is, uint32_t len, const uint32_t elem_size) +{ + if (elem_size && len) + is->m_index += len * elem_size; +} + +static void dds_stream_skip_string (dds_istream_t * __restrict is) +{ + const uint32_t length = dds_is_get4 (is); + dds_stream_skip_forward (is, length, 1); +} + +static void dds_stream_write_string (dds_ostream_t * __restrict os, const char * __restrict val) { uint32_t size = 1; if (val) { - size += (uint32_t)strlen (val); /* Type casting is done for the warning of conversion from 'size_t' to 'uint32_t', which may cause possible loss of data */ + /* Type casting is done for the warning of conversion from 'size_t' to 'uint32_t', which may cause possible loss of data */ + size += (uint32_t) strlen (val); } - DDS_OS_PUT4 (os, size, uint32_t); + dds_os_put4 (os, size); if (val) { - DDS_OS_PUT_BYTES (os, (uint8_t*) val, size); + dds_os_put_bytes (os, val, size); } else { - DDS_OS_PUT1 (os, 0U); + dds_os_put1 (os, 0); } } -void dds_stream_write_buffer (dds_stream_t * os, uint32_t len, const uint8_t * buffer) +static void dds_streamBE_write_string (dds_ostreamBE_t * __restrict os, const char * __restrict val) { - DDS_OS_PUT_BYTES (os, buffer, len); -} + uint32_t size = 1; -void *dds_stream_address (dds_stream_t * s) -{ - return DDS_CDR_ADDRESS(s, void); -} - -void *dds_stream_alignto (dds_stream_t * s, uint32_t a) -{ - DDS_CDR_ALIGNTO (s, a); - return DDS_CDR_ADDRESS (s, void); -} - -static void dds_stream_write -( - dds_stream_t * os, - const char * data, - const uint32_t * ops -) -{ - uint32_t align; - uint32_t op; - uint32_t type; - uint32_t subtype; - uint32_t num; - const char * addr; - - while ((op = *ops) != DDS_OP_RTS) + if (val) { - switch (DDS_OP_MASK & op) - { - case DDS_OP_ADR: - { - type = DDS_OP_TYPE (op); -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-ADR: %s offset %d\n", stream_op_type[type], ops[1]); -#endif - addr = data + ops[1]; - ops += 2; - switch (type) - { - case DDS_OP_VAL_1BY: - { - DDS_OS_PUT1 (os, *(uint8_t*) addr); - break; - } - case DDS_OP_VAL_2BY: - { - DDS_OS_PUT2 (os, *(uint16_t*) addr); - break; - } - case DDS_OP_VAL_4BY: - { - DDS_OS_PUT4 (os, *(uint32_t*) addr, uint32_t); - break; - } - case DDS_OP_VAL_8BY: - { - DDS_OS_PUT8 (os, *(uint64_t*) addr, uint64_t); - break; - } - case DDS_OP_VAL_STR: - { -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-STR: %s\n", *((char**) addr)); -#endif - dds_stream_write_string (os, *((char**) addr)); - break; - } - case DDS_OP_VAL_SEQ: - { - dds_sequence_t * seq = (dds_sequence_t*) addr; - subtype = DDS_OP_SUBTYPE (op); - num = seq->_length; - -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-SEQ: %s <%d>\n", stream_op_type[subtype], num); -#endif - DDS_OS_PUT4 (os, num, uint32_t); - if (num || (subtype > DDS_OP_VAL_STR)) - { - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - { - num = num * dds_op_size[subtype]; - DDS_OS_PUT_BYTES (os, seq->_buffer, num); - break; - } - case DDS_OP_VAL_8BY: - { - DDS_CDR_ALIGN8 (os); - DDS_OS_PUT_BYTES (os, seq->_buffer, num * 8u); - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr = (char**) seq->_buffer; - while (num--) - { -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-SEQ STR: %s\n", *ptr); -#endif - dds_stream_write_string (os, *ptr); - ptr++; - } - break; - } - case DDS_OP_VAL_BST: - { - char * ptr = (char*) seq->_buffer; - align = *ops++; - while (num--) - { -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-SEQ BST[%d]: %s\n", align, ptr); -#endif - dds_stream_write_string (os, ptr); - ptr += align; - } - break; - } - default: - { - const uint32_t elem_size = *ops++; - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (*ops) - 3; - const uint32_t jmp = DDS_OP_ADR_JMP (*ops); - char * ptr = (char*) seq->_buffer; - while (num--) - { - dds_stream_write (os, ptr, jsr_ops); - ptr += elem_size; - } - ops += jmp ? (jmp - 3) : 1; - break; - } - } - } - break; - } - case DDS_OP_VAL_ARR: - { - subtype = DDS_OP_SUBTYPE (op); - num = *ops++; - -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-ARR: %s [%d]\n", stream_op_type[subtype], num); -#endif - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - DDS_CDR_ALIGNTO (os, align); - DDS_OS_PUT_BYTES (os, addr, num * align); - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr = (char**) addr; - while (num--) - { - dds_stream_write_string (os, *ptr); - ptr++; - } - break; - } - case DDS_OP_VAL_BST: - { - char * ptr = (char*) addr; - align = ops[1]; - while (num--) - { - dds_stream_write_string (os, ptr); - ptr += align; - } - ops += 2; - break; - } - default: - { - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (*ops) - 3; - const uint32_t jmp = DDS_OP_ADR_JMP (*ops); - const uint32_t elem_size = ops[1]; - - while (num--) - { - dds_stream_write (os, addr, jsr_ops); - addr += elem_size; - } - ops += jmp ? (jmp - 3) : 2; - break; - } - } - break; - } - case DDS_OP_VAL_UNI: - { - const bool has_default = op & DDS_OP_FLAG_DEF; - subtype = DDS_OP_SUBTYPE (op); - num = ops[0]; - const uint32_t * jeq_op = ops + DDS_OP_ADR_JSR (ops[1]) - 2; - uint32_t disc = 0; - - assert (subtype <= DDS_OP_VAL_4BY); - - /* Write discriminant */ - - switch (subtype) - { - case DDS_OP_VAL_1BY: - { - uint8_t d8 = *((uint8_t*) addr); - DDS_OS_PUT1 (os, d8); - disc = d8; - break; - } - case DDS_OP_VAL_2BY: - { - uint16_t d16 = *((uint16_t*) addr); - DDS_OS_PUT2 (os, d16); - disc = d16; - break; - } - case DDS_OP_VAL_4BY: - { - disc = *((uint32_t*) addr); - DDS_OS_PUT4 (os, disc, uint32_t); - break; - } - default: assert (0); - } -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-UNI: switch %s case %d/%d\n", stream_op_type[subtype], disc, num); -#endif - - /* Write case matching discriminant */ - - while (num--) - { - assert ((DDS_OP_MASK & jeq_op[0]) == DDS_OP_JEQ); - - /* Select matching or default case */ - - if ((jeq_op[1] == disc) || (has_default && (num == 0))) - { - subtype = DDS_JEQ_TYPE (jeq_op[0]); - addr = data + jeq_op[2]; - -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-UNI: case type %s\n", stream_op_type[subtype]); -#endif - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - DDS_CDR_ALIGNTO (os, align); - DDS_OS_PUT_BYTES (os, addr, align); - break; - } - case DDS_OP_VAL_STR: - { - dds_stream_write_string (os, *(char**) addr); - break; - } - case DDS_OP_VAL_BST: - { - dds_stream_write_string (os, (char*) addr); - break; - } - default: - { - dds_stream_write (os, addr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); - break; - } - } - break; - } - jeq_op += 3; - } - - /* Jump to next instruction */ - - ops += DDS_OP_ADR_JMP (ops[1]) - 2; - break; - } - case DDS_OP_VAL_BST: - { -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-BST: %s\n", (char*) addr); -#endif - dds_stream_write_string (os, (char*) addr); - ops++; - break; - } - default: assert (0); - } - break; - } - case DDS_OP_JSR: /* Implies nested type */ - { -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-JSR: %d\n", DDS_OP_JUMP (op)); -#endif - dds_stream_write (os, data, ops + DDS_OP_JUMP (op)); - ops++; - break; - } - default: assert (0); - } + /* Type casting is done for the warning of conversion from 'size_t' to 'uint32_t', which may cause possible loss of data */ + size += (uint32_t) strlen (val); } -#ifdef OP_DEBUG_WRITE - DDS_TRACE("W-RTS:\n"); -#endif -} -static void dds_stream_read (dds_stream_t * is, char * data, const uint32_t * ops) -{ - uint32_t align; - uint32_t op; - uint32_t type; - uint32_t subtype; - uint32_t num; - char * addr; + dds_os_put4be (os, size); - while ((op = *ops) != DDS_OP_RTS) + if (val) { - switch (DDS_OP_MASK & op) - { - case DDS_OP_ADR: - { - type = DDS_OP_TYPE (op); -#ifdef OP_DEBUG_READ - DDS_TRACE("R-ADR: %s offset %d\n", stream_op_type[type], ops[1]); -#endif - addr = data + ops[1]; - ops += 2; - switch (type) - { - case DDS_OP_VAL_1BY: - { - *(uint8_t*) addr = dds_stream_read_uint8 (is); - break; - } - case DDS_OP_VAL_2BY: - { - *(uint16_t*) addr = dds_stream_read_uint16 (is); - break; - } - case DDS_OP_VAL_4BY: - { - *(uint32_t*) addr = dds_stream_read_uint32 (is); - break; - } - case DDS_OP_VAL_8BY: - { - *(uint64_t*) addr = dds_stream_read_uint64 (is); - break; - } - case DDS_OP_VAL_STR: - { -#ifdef OP_DEBUG_READ - DDS_TRACE("R-STR: @ %p\n", addr); -#endif - *(char**) addr = dds_stream_reuse_string (is, *((char**) addr), 0); - break; - } - case DDS_OP_VAL_SEQ: - { - dds_sequence_t * seq = (dds_sequence_t*) addr; - subtype = DDS_OP_SUBTYPE (op); - num = dds_stream_read_uint32 (is); - -#ifdef OP_DEBUG_READ - DDS_TRACE("R-SEQ: %s <%d>\n", stream_op_type[subtype], num); -#endif - /* Maintain max sequence length (may not have been set by caller) */ - - if (seq->_length > seq->_maximum) - { - seq->_maximum = seq->_length; - } - - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - - /* Reuse sequence buffer if big enough */ - - if (num > seq->_length) - { - if (seq->_release && seq->_length) - { - seq->_buffer = dds_realloc_zero (seq->_buffer, num * align); - } - else - { - seq->_buffer = dds_alloc (num * align); - } - seq->_release = true; - seq->_maximum = num; - } - seq->_length = num; - dds_stream_read_fixed_buffer (is, seq->_buffer, seq->_length, align, is->m_endian != DDS_ENDIAN); - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr; - - /* Reuse sequence buffer if big enough */ - - if (num > seq->_maximum) - { - if (seq->_release && seq->_maximum) - { - seq->_buffer = dds_realloc_zero (seq->_buffer, num * sizeof (char*)); - } - else - { - seq->_buffer = dds_alloc (num * sizeof (char*)); - } - seq->_release = true; - seq->_maximum = num; - } - seq->_length = num; - - ptr = (char**) seq->_buffer; - while (num--) - { - *ptr = dds_stream_reuse_string (is, *ptr, 0); - ptr++; - } - break; - } - case DDS_OP_VAL_BST: - { - char * ptr; - align = *ops++; - - /* Reuse sequence buffer if big enough */ - - if (num > seq->_maximum) - { - if (seq->_release && seq->_maximum) - { - seq->_buffer = dds_realloc_zero (seq->_buffer, num * align); - } - else - { - seq->_buffer = dds_alloc (num * align); - } - seq->_release = true; - seq->_maximum = num; - } - seq->_length = num; - - ptr = (char*) seq->_buffer; - while (num--) - { - dds_stream_reuse_string (is, ptr, align); - ptr += align; - } - break; - } - default: - { - const uint32_t elem_size = *ops++; - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (*ops) - 3; - const uint32_t jmp = DDS_OP_ADR_JMP (*ops); - uint32_t i; - char * ptr; - - /* Reuse sequence buffer if big enough */ - - if (num > seq->_maximum) - { - if (seq->_release && seq->_maximum) - { - if (seq->_buffer) - { - i = seq->_length; - ptr = (char*) seq->_buffer; - while (i--) - { - dds_sample_free_contents (ptr, jsr_ops); - ptr += elem_size; - } - } - seq->_buffer = dds_realloc_zero (seq->_buffer, num * elem_size); - } - else - { - seq->_buffer = dds_alloc (num * elem_size); - } - seq->_release = true; - seq->_maximum = num; - } - seq->_length = num; - - ptr = (char*) seq->_buffer; - while (num--) - { - dds_stream_read (is, ptr, jsr_ops); - ptr += elem_size; - } - ops += jmp ? (jmp - 3) : 1; - break; - } - } - break; - } - case DDS_OP_VAL_ARR: - { - subtype = DDS_OP_SUBTYPE (op); - num = *ops++; - -#ifdef OP_DEBUG_READ - DDS_TRACE("R-ARR: %s [%d]\n", stream_op_type[subtype], num); -#endif - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - if (DDS_IS_OK (is, num * align)) - { - dds_stream_read_fixed_buffer (is, addr, num, align, is->m_endian != DDS_ENDIAN); - } - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr = (char**) addr; - while (num--) - { - *ptr = dds_stream_reuse_string (is, *ptr, 0); - ptr++; - } - break; - } - case DDS_OP_VAL_BST: - { - char * ptr = (char*) addr; - align = ops[1]; - while (num--) - { - dds_stream_reuse_string (is, ptr, align); - ptr += align; - } - ops += 2; - break; - } - default: - { - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (*ops) - 3; - const uint32_t jmp = DDS_OP_ADR_JMP (*ops); - const uint32_t elem_size = ops[1]; - - while (num--) - { - dds_stream_read (is, addr, jsr_ops); - addr += elem_size; - } - ops += jmp ? (jmp - 3) : 2; - break; - } - } - break; - } - case DDS_OP_VAL_UNI: - { - const bool has_default = op & DDS_OP_FLAG_DEF; - subtype = DDS_OP_SUBTYPE (op); - num = ops[0]; - const uint32_t * jeq_op = ops + DDS_OP_ADR_JSR (ops[1]) - 2; - uint32_t disc = 0; - - assert (subtype <= DDS_OP_VAL_4BY); - - /* Read discriminant */ - - switch (subtype) - { - case DDS_OP_VAL_1BY: - { - uint8_t d8 = dds_stream_read_uint8 (is); - *(uint8_t*) addr = d8; - disc = d8; - break; - } - case DDS_OP_VAL_2BY: - { - uint16_t d16 = dds_stream_read_uint16 (is); - *(uint16_t*) addr = d16; - disc = d16; - break; - } - case DDS_OP_VAL_4BY: - { - disc = dds_stream_read_uint32 (is); - *(uint32_t*) addr = disc; - break; - } - default: assert (0); - } - -#ifdef OP_DEBUG_READ - DDS_TRACE("R-UNI: switch %s case %d/%d\n", stream_op_type[subtype], disc, num); -#endif - - /* Read case matching discriminant */ - - while (num--) - { - assert ((DDS_OP_MASK & jeq_op[0]) == DDS_OP_JEQ); - if ((jeq_op[1] == disc) || (has_default && (num == 0))) - { - subtype = DDS_JEQ_TYPE (jeq_op[0]); - addr = data + jeq_op[2]; - -#ifdef OP_DEBUG_READ - DDS_TRACE("R-UNI: case type %s\n", stream_op_type[subtype]); -#endif - switch (subtype) - { - case DDS_OP_VAL_1BY: - { - *(uint8_t*) addr = dds_stream_read_uint8 (is); - break; - } - case DDS_OP_VAL_2BY: - { - *(uint16_t*) addr = dds_stream_read_uint16 (is); - break; - } - case DDS_OP_VAL_4BY: - { - *(uint32_t*) addr = dds_stream_read_uint32 (is); - break; - } - case DDS_OP_VAL_8BY: - { - *(uint64_t*) addr = dds_stream_read_uint64 (is); - break; - } - case DDS_OP_VAL_STR: - { - *(char**) addr = dds_stream_reuse_string (is, *((char**) addr), 0); - break; - } - default: - { - dds_stream_read (is, addr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); - break; - } - } - break; - } - jeq_op += 3; - } - - /* Jump to next instruction */ - - ops += DDS_OP_ADR_JMP (ops[1]) - 2; - break; - } - case DDS_OP_VAL_BST: - { -#ifdef OP_DEBUG_READ - DDS_TRACE("R-BST: @ %p\n", addr); -#endif - dds_stream_reuse_string (is, (char*) addr, *ops); - ops++; - break; - } - default: assert (0); - } - break; - } - case DDS_OP_JSR: /* Implies nested type */ - { -#ifdef OP_DEBUG_READ - DDS_TRACE("R-JSR: %d\n", DDS_OP_JUMP (op)); -#endif - dds_stream_read (is, data, ops + DDS_OP_JUMP (op)); - ops++; - break; - } - default: assert (0); - } - } -#ifdef OP_DEBUG_READ - DDS_TRACE("R-RTS:\n"); -#endif -} - -void dds_stream_write_sample (dds_stream_t * os, const void * data, const struct ddsi_sertopic_default * topic) -{ - const struct dds_topic_descriptor * desc = topic->type; - - if (topic->opt_size && DDS_CDR_ALIGNED (os, desc->m_align)) - { - DDS_OS_PUT_BYTES (os, data, desc->m_size); + dds_os_put_bytes (&os->x, val, size); } else { - dds_stream_write (os, data, desc->m_ops); + dds_os_put1be (os, 0); } } -void dds_stream_from_serdata_default (dds_stream_t * s, const struct ddsi_serdata_default *d) -{ - s->m_failed = false; - s->m_buffer.p8 = (uint8_t*) d; - s->m_index = (uint32_t) offsetof (struct ddsi_serdata_default, data); - s->m_size = d->size + s->m_index; - assert (d->hdr.identifier == CDR_LE || d->hdr.identifier == CDR_BE); - s->m_endian = (d->hdr.identifier == CDR_LE); -} - -void dds_stream_add_to_serdata_default (dds_stream_t * s, struct ddsi_serdata_default **d) -{ - /* DDSI requires 4 byte alignment */ - - DDS_CDR_ALIGN4 (s); - - /* Reset data pointer as stream may have reallocated */ - - (*d) = s->m_buffer.pv; - (*d)->pos = (s->m_index - (uint32_t)offsetof (struct ddsi_serdata_default, data)); - (*d)->size = (s->m_size - (uint32_t)offsetof (struct ddsi_serdata_default, data)); -} - -void dds_stream_write_key (dds_stream_t * os, const char * sample, const struct ddsi_sertopic_default * topic) -{ - const struct dds_topic_descriptor * desc = (const struct dds_topic_descriptor *) topic->type; - uint32_t i; - const char * src; - const uint32_t * op; - - for (i = 0; i < desc->m_nkeys; i++) - { - op = desc->m_ops + desc->m_keys[i].m_index; - src = sample + op[1]; - assert ((*op & DDS_OP_FLAG_KEY) && ((DDS_OP_MASK & *op) == DDS_OP_ADR)); - switch (DDS_OP_TYPE (*op)) - { - case DDS_OP_VAL_1BY: - DDS_OS_PUT1 (os, *((uint8_t*) src)); - break; - case DDS_OP_VAL_2BY: - DDS_OS_PUT2 (os, *((uint16_t*) src)); - break; - case DDS_OP_VAL_4BY: - DDS_OS_PUT4 (os, *((uint32_t*) src), uint32_t); - break; - case DDS_OP_VAL_8BY: - DDS_OS_PUT8 (os, *((uint64_t*) src), uint64_t); - break; - case DDS_OP_VAL_STR: - src = *(char**) src; - /* FALLS THROUGH */ - case DDS_OP_VAL_BST: - dds_stream_write_string (os, src); - break; - case DDS_OP_VAL_ARR: - { - uint32_t subtype = DDS_OP_SUBTYPE (*op); - assert (subtype <= DDS_OP_VAL_8BY); - uint32_t align = dds_op_size[subtype]; - DDS_CDR_ALIGNTO (os, align); - DDS_OS_PUT_BYTES (os, src, op[2] * align); - break; - } - default: assert (0); - } - } -} - -/* - dds_stream_get_keyhash: Extract key values from a stream and generate - keyhash used for instance identification. Non key fields are skipped. - Key hash data is big endian CDR encoded with no padding. Returns length - of key hash. Input stream may contain full sample of just key data. -*/ - -uint32_t dds_stream_extract_key (dds_stream_t *is, dds_stream_t *os, const uint32_t *ops, const bool just_key) -{ - uint32_t align; - uint32_t op; - uint32_t type; - uint32_t subtype; - uint32_t num; - uint32_t len; - const uint32_t origin = os->m_index; - bool is_key; - bool have_data; - - while ((op = *ops) != DDS_OP_RTS) - { - switch (DDS_OP_MASK & op) - { - case DDS_OP_ADR: - { - type = DDS_OP_TYPE (op); - is_key = (op & DDS_OP_FLAG_KEY) && (os != NULL); - have_data = is_key || !just_key; - ops += 2; - if (type <= DDS_OP_VAL_8BY) - { - if (have_data) - { - align = dds_op_size[type]; - DDS_CDR_ALIGNTO (is, align); - - /* Quick skip for basic types that are not keys */ - - if (! is_key) - { - is->m_index += align; - break; - } - } - else - { - break; - } - } -#ifdef OP_DEBUG_KEY - if (is_key) - { - DDS_TRACE("K-ADR: %s\n", stream_op_type[type]); - } -#endif - switch (type) - { - case DDS_OP_VAL_1BY: - { - uint8_t v = DDS_IS_GET1 (is); - DDS_OS_PUT1 (os, v); - break; - } - case DDS_OP_VAL_2BY: - { - uint16_t v; - DDS_IS_GET2 (is, v); - DDS_OS_PUT2 (os, v); - break; - } - case DDS_OP_VAL_4BY: - { - uint32_t v; - DDS_IS_GET4 (is, v, uint32_t); - DDS_OS_PUT4 (os, v, uint32_t); - break; - } - case DDS_OP_VAL_8BY: - { - uint64_t v; - DDS_IS_GET8 (is, v, uint64_t); - DDS_OS_PUT8 (os, v, uint64_t); - break; - } - case DDS_OP_VAL_STR: - case DDS_OP_VAL_BST: - { - if (have_data) - { - len = dds_stream_read_uint32 (is); - if (is_key) - { - DDS_OS_PUT4 (os, len, uint32_t); - DDS_OS_PUT_BYTES(os, DDS_CDR_ADDRESS (is, void), len); -#ifdef OP_DEBUG_KEY - DDS_TRACE("K-ADR: String/BString (%d)\n", len); -#endif - } - is->m_index += len; - } - if (type == DDS_OP_VAL_BST) - { - ops++; - } - break; - } - case DDS_OP_VAL_SEQ: - { - assert (! is_key); - subtype = DDS_OP_SUBTYPE (op); - num = have_data ? dds_stream_read_uint32 (is) : 0; - - if (num || (subtype > DDS_OP_VAL_STR)) - { - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - DDS_CDR_ALIGNTO (is, align); - is->m_index += align * num; - break; - } - case DDS_OP_VAL_STR: - case DDS_OP_VAL_BST: - { - while (num--) - { - len = dds_stream_read_uint32 (is); - is->m_index += len; - } - if (subtype == DDS_OP_VAL_BST) - { - ops++; - } - break; - } - default: - { - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (ops[1]) - 2; - const uint32_t jmp = DDS_OP_ADR_JMP (ops[1]); - while (num--) - { - dds_stream_extract_key (is, NULL, jsr_ops, just_key); - } - ops += jmp ? (jmp - 2) : 2; - break; - } - } - } - break; - } - case DDS_OP_VAL_ARR: - { - subtype = DDS_OP_SUBTYPE (op); - assert (! is_key || subtype <= DDS_OP_VAL_8BY); - num = have_data ? *ops : 0; - ops++; - -#ifdef OP_DEBUG_KEY - if (is_key) - { - DDS_TRACE("K-ADR: %s[%d]\n", stream_op_type[subtype], num); - } -#endif - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - if (num) - { - align = dds_op_size[subtype]; - if (is_key) - { - char *dst; - DDS_CDR_ALIGNTO (os, align); - DDS_CDR_RESIZE (os, num * align); - dst = DDS_CDR_ADDRESS(os, char); - dds_stream_read_fixed_buffer (is, dst, num, align, is->m_endian); - os->m_index += num * align; - } - is->m_index += num * align; - } - break; - } - case DDS_OP_VAL_STR: - case DDS_OP_VAL_BST: - { - while (num--) - { - len = dds_stream_read_uint32 (is); - is->m_index += len; - } - break; - } - default: - { - const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (*ops) - 3; - const uint32_t jmp = DDS_OP_ADR_JMP (*ops); - while (num--) - { - dds_stream_extract_key (is, NULL, jsr_ops, just_key); - } - ops += jmp ? (jmp - 3) : 2; - break; - } - } - break; - } - case DDS_OP_VAL_UNI: - { - const bool has_default = op & DDS_OP_FLAG_DEF; - subtype = DDS_OP_SUBTYPE (op); - num = ops[0]; - const uint32_t * jeq_op = ops + DDS_OP_ADR_JSR (ops[1]) - 2; - uint32_t disc = 0; - - assert (subtype <= DDS_OP_VAL_4BY); - assert (! is_key); - -#ifdef OP_DEBUG_KEY - DDS_TRACE("K-UNI: switch %s cases %d\n", stream_op_type[subtype], num); -#endif - /* Read discriminant */ - - if (have_data) - { - switch (subtype) - { - case DDS_OP_VAL_1BY: - { - disc = dds_stream_read_uint8 (is); - break; - } - case DDS_OP_VAL_2BY: - { - disc = dds_stream_read_uint16 (is); - break; - } - case DDS_OP_VAL_4BY: - { - disc = dds_stream_read_uint32 (is); - break; - } - default: assert (0); - } - - /* Skip union case */ - - while (num--) - { - assert ((DDS_OP_MASK & jeq_op[0]) == DDS_OP_JEQ); - if ((jeq_op[1] == disc) || (has_default && (num == 0))) - { - subtype = DDS_JEQ_TYPE (jeq_op[0]); - - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - align = dds_op_size[subtype]; - DDS_CDR_ALIGNTO (is, align); - is->m_index += align; - break; - } - case DDS_OP_VAL_STR: - case DDS_OP_VAL_BST: - { - len = dds_stream_read_uint32 (is); - is->m_index += len; - break; - } - default: - { - dds_stream_extract_key (is, NULL, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), just_key); - break; - } - } - break; - } - jeq_op += 3; - } - } - - /* Jump to next instruction */ - - ops += DDS_OP_ADR_JMP (ops[1]) - 2; - break; - } - default: assert (0); - } - break; - } - case DDS_OP_JSR: /* Implies nested type */ - { - dds_stream_extract_key (is, os, ops + DDS_OP_JUMP (op), just_key); - ops++; - break; - } - default: assert (0); - } - } - return os->m_index - origin; -} - #ifndef NDEBUG -static bool keyhash_is_reset(const dds_key_hash_t *kh) +static bool insn_key_ok_p (uint32_t insn) { - static const char nullhash[sizeof(kh->m_hash)] = { 0 }; - return !kh->m_set && memcmp(kh->m_hash, nullhash, sizeof(nullhash)) == 0; + return (DDS_OP (insn) == DDS_OP_ADR && (insn & DDS_OP_FLAG_KEY) && + (DDS_OP_TYPE (insn) <= DDS_OP_VAL_BST || + (DDS_OP_TYPE (insn) == DDS_OP_VAL_ARR && DDS_OP_SUBTYPE (insn) <= DDS_OP_VAL_8BY))); } #endif -void dds_stream_read_keyhash -( - dds_stream_t * is, - dds_key_hash_t * kh, - const dds_topic_descriptor_t * desc, - const bool just_key -) +static uint32_t read_union_discriminant (dds_istream_t * __restrict is, enum dds_stream_typecode type) { - assert (keyhash_is_reset(kh)); + assert (type == DDS_OP_VAL_1BY || type == DDS_OP_VAL_2BY || type == DDS_OP_VAL_4BY); + switch (type) + { + case DDS_OP_VAL_1BY: return dds_is_get1 (is); + case DDS_OP_VAL_2BY: return dds_is_get2 (is); + case DDS_OP_VAL_4BY: return dds_is_get4 (is); + default: return 0; + } +} + +static uint32_t write_union_discriminant (dds_ostream_t * __restrict os, enum dds_stream_typecode type, const void * __restrict addr) +{ + assert (type == DDS_OP_VAL_1BY || type == DDS_OP_VAL_2BY || type == DDS_OP_VAL_4BY); + switch (type) + { + case DDS_OP_VAL_1BY: { uint8_t d8 = *((const uint8_t *) addr); dds_os_put1 (os, d8); return d8; } + case DDS_OP_VAL_2BY: { uint16_t d16 = *((const uint16_t *) addr); dds_os_put2 (os, d16); return d16; } + case DDS_OP_VAL_4BY: { uint32_t d32 = *((const uint32_t *) addr); dds_os_put4 (os, d32); return d32; } + default: return 0; + } +} + +static const uint32_t *find_union_case (const uint32_t * __restrict union_ops, uint32_t disc) +{ + assert (DDS_OP_TYPE (*union_ops) == DDS_OP_VAL_UNI); + const bool has_default = *union_ops & DDS_OP_FLAG_DEF; + const uint32_t numcases = union_ops[2]; + const uint32_t *jeq_op = union_ops + DDS_OP_ADR_JSR (union_ops[3]); + /* Find union case; default case is always the last one */ + assert (numcases > 0); + uint32_t ci; +#ifndef NDEBUG + for (ci = 0; ci < numcases; ci++) + assert (DDS_OP (jeq_op[3 * ci]) == DDS_OP_JEQ); +#endif + for (ci = 0; ci < numcases - (has_default ? 1 : 0); ci++, jeq_op += 3) + if (jeq_op[1] == disc) + return jeq_op; + return (ci < numcases) ? jeq_op : NULL; +} + +static const uint32_t *skip_sequence_insns (const uint32_t * __restrict ops, uint32_t insn) +{ + switch (DDS_OP_SUBTYPE (insn)) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: + return ops + 2; + case DDS_OP_VAL_BST: + return ops + 3; /* bound */ + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */ + } + } + return NULL; +} + +static const uint32_t *dds_stream_write_seq (dds_ostream_t * __restrict os, const char * __restrict addr, const uint32_t * __restrict ops, uint32_t insn) +{ + const dds_sequence_t * const seq = (const dds_sequence_t *) addr; + const uint32_t num = seq->_length; + + dds_os_put4 (os, num); + if (num == 0) + return skip_sequence_insns (ops, insn); + + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + /* following length, stream is aligned to mod 4 */ + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: + dds_os_put_bytes_aligned (os, seq->_buffer, num, get_type_size (subtype)); + return ops + 2; + case DDS_OP_VAL_STR: { + const char **ptr = (const char **) seq->_buffer; + for (uint32_t i = 0; i < num; i++) + dds_stream_write_string (os, ptr[i]); + return ops + 2; + } + case DDS_OP_VAL_BST: { + const char *ptr = (const char *) seq->_buffer; + const uint32_t elem_size = ops[2]; + for (uint32_t i = 0; i < num; i++) + dds_stream_write_string (os, ptr + i * elem_size); + return ops + 3; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t elem_size = ops[2]; + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const char *ptr = (const char *) seq->_buffer; + for (uint32_t i = 0; i < num; i++) + dds_stream_write (os, ptr + i * elem_size, jsr_ops); + return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */ + } + } + return NULL; +} + +static const uint32_t *dds_stream_write_arr (dds_ostream_t * __restrict os, const char * __restrict addr, const uint32_t * __restrict ops, uint32_t insn) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + const uint32_t num = ops[2]; + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: + dds_os_put_bytes_aligned (os, addr, num, get_type_size (subtype)); + return ops + 3; + case DDS_OP_VAL_STR: { + const char **ptr = (const char **) addr; + for (uint32_t i = 0; i < num; i++) + dds_stream_write_string (os, ptr[i]); + return ops + 3; + } + case DDS_OP_VAL_BST: { + const char *ptr = (const char *) addr; + const uint32_t elem_size = ops[4]; + for (uint32_t i = 0; i < num; i++) + dds_stream_write_string (os, ptr + i * elem_size); + return ops + 5; + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + const uint32_t elem_size = ops[4]; + for (uint32_t i = 0; i < num; i++) + dds_stream_write (os, addr + i * elem_size, jsr_ops); + return ops + (jmp ? jmp : 5); + } + } + return NULL; +} + +static const uint32_t *dds_stream_write_uni (dds_ostream_t * __restrict os, const char * __restrict discaddr, const char * __restrict baseaddr, const uint32_t * __restrict ops, uint32_t insn) +{ + const uint32_t disc = write_union_discriminant (os, DDS_OP_SUBTYPE (insn), discaddr); + uint32_t const * const jeq_op = find_union_case (ops, disc); + ops += DDS_OP_ADR_JMP (ops[3]); + if (jeq_op) + { + const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]); + const void *valaddr = baseaddr + jeq_op[2]; + switch (valtype) + { + case DDS_OP_VAL_1BY: dds_os_put1 (os, *(const uint8_t *) valaddr); break; + case DDS_OP_VAL_2BY: dds_os_put2 (os, *(const uint16_t *) valaddr); break; + case DDS_OP_VAL_4BY: dds_os_put4 (os, *(const uint32_t *) valaddr); break; + case DDS_OP_VAL_8BY: dds_os_put8 (os, *(const uint64_t *) valaddr); break; + case DDS_OP_VAL_STR: dds_stream_write_string (os, *(const char **) valaddr); break; + case DDS_OP_VAL_BST: dds_stream_write_string (os, (const char *) valaddr); break; + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: + dds_stream_write (os, valaddr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); + break; + } + } + return ops; +} + +static void dds_stream_write (dds_ostream_t * __restrict os, const char * __restrict data, const uint32_t * __restrict ops) +{ + uint32_t insn; + while ((insn = *ops) != DDS_OP_RTS) + { + switch (DDS_OP (insn)) + { + case DDS_OP_ADR: { + const void *addr = data + ops[1]; + switch (DDS_OP_TYPE (insn)) + { + case DDS_OP_VAL_1BY: dds_os_put1 (os, *((const uint8_t *) addr)); ops += 2; break; + case DDS_OP_VAL_2BY: dds_os_put2 (os, *((const uint16_t *) addr)); ops += 2; break; + case DDS_OP_VAL_4BY: dds_os_put4 (os, *((const uint32_t *) addr)); ops += 2; break; + case DDS_OP_VAL_8BY: dds_os_put8 (os, *((const uint64_t *) addr)); ops += 2; break; + case DDS_OP_VAL_STR: dds_stream_write_string (os, *((const char **) addr)); ops += 2; break; + case DDS_OP_VAL_BST: dds_stream_write_string (os, (const char *) addr); ops += 3; break; + case DDS_OP_VAL_SEQ: ops = dds_stream_write_seq (os, addr, ops, insn); break; + case DDS_OP_VAL_ARR: ops = dds_stream_write_arr (os, addr, ops, insn); break; + case DDS_OP_VAL_UNI: ops = dds_stream_write_uni (os, addr, data, ops, insn); break; + case DDS_OP_VAL_STU: abort (); break; + } + break; + } + case DDS_OP_JSR: { + dds_stream_write (os, data, ops + DDS_OP_JUMP (insn)); + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } +} + +static void realloc_sequence_buffer_if_needed (dds_sequence_t * __restrict seq, uint32_t num, uint32_t elem_size, bool init) +{ + const uint32_t size = num * elem_size; + + /* maintain max sequence length (may not have been set by caller) */ + if (seq->_length > seq->_maximum) + seq->_maximum = seq->_length; + + if (num > seq->_maximum && seq->_release) + { + seq->_buffer = ddsrt_realloc (seq->_buffer, size); + if (init) + { + const uint32_t off = seq->_maximum * elem_size; + memset (seq->_buffer + off, 0, size - off); + } + seq->_maximum = num; + } + else if (num > 0 && seq->_maximum == 0) + { + seq->_buffer = ddsrt_malloc (size); + if (init) + memset (seq->_buffer, 0, size); + seq->_release = true; + seq->_maximum = num; + } +} + +static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char * __restrict addr, const uint32_t * __restrict ops, uint32_t insn) +{ + dds_sequence_t * const seq = (dds_sequence_t *) addr; + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + const uint32_t num = dds_is_get4 (is); + if (num == 0) + { + seq->_length = 0; + return skip_sequence_insns (ops, insn); + } + + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: { + const uint32_t elem_size = get_type_size (subtype); + realloc_sequence_buffer_if_needed (seq, num, elem_size, false); + seq->_length = (num <= seq->_maximum) ? num : seq->_maximum; + dds_is_get_bytes (is, seq->_buffer, seq->_length, elem_size); + if (seq->_length < num) + dds_stream_skip_forward (is, num - seq->_length, elem_size); + return ops + 2; + } + case DDS_OP_VAL_STR: { + realloc_sequence_buffer_if_needed (seq, num, sizeof (char *), true); + seq->_length = (num <= seq->_maximum) ? num : seq->_maximum; + char **ptr = (char **) seq->_buffer; + for (uint32_t i = 0; i < seq->_length; i++) + ptr[i] = dds_stream_reuse_string (is, ptr[i], 0); + for (uint32_t i = seq->_length; i < num; i++) + dds_stream_skip_string (is); + return ops + 2; + } + case DDS_OP_VAL_BST: { + const uint32_t elem_size = ops[2]; + realloc_sequence_buffer_if_needed (seq, num, elem_size, false); + seq->_length = (num <= seq->_maximum) ? num : seq->_maximum; + char *ptr = (char *) seq->_buffer; + for (uint32_t i = 0; i < seq->_length; i++) + (void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size); + for (uint32_t i = seq->_length; i < num; i++) + dds_stream_skip_string (is); + return ops + 3; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t elem_size = ops[2]; + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + realloc_sequence_buffer_if_needed (seq, num, elem_size, true); + seq->_length = (num <= seq->_maximum) ? num : seq->_maximum; + char *ptr = (char *) seq->_buffer; + for (uint32_t i = 0; i < num; i++) + dds_stream_read (is, ptr + i * elem_size, jsr_ops); + return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */ + } + } + return NULL; +} + +static const uint32_t *dds_stream_read_arr (dds_istream_t * __restrict is, char * __restrict addr, const uint32_t * __restrict ops, uint32_t insn) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + const uint32_t num = ops[2]; + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: { + const uint32_t elem_size = get_type_size (subtype); + dds_is_get_bytes (is, addr, num, elem_size); + return ops + 3; + } + case DDS_OP_VAL_STR: { + char **ptr = (char **) addr; + for (uint32_t i = 0; i < num; i++) + ptr[i] = dds_stream_reuse_string (is, ptr[i], 0); + return ops + 3; + } + case DDS_OP_VAL_BST: { + char *ptr = (char *) addr; + const uint32_t elem_size = ops[4]; + for (uint32_t i = 0; i < num; i++) + (void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size); + return ops + 5; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + const uint32_t elem_size = ops[4]; + for (uint32_t i = 0; i < num; i++) + dds_stream_read (is, addr + i * elem_size, jsr_ops); + return ops + (jmp ? jmp : 5); + } + } + return NULL; +} + +static const uint32_t *dds_stream_read_uni (dds_istream_t * __restrict is, char * __restrict discaddr, char * __restrict baseaddr, const uint32_t * __restrict ops, uint32_t insn) +{ + const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn)); + switch (DDS_OP_SUBTYPE (insn)) + { + case DDS_OP_VAL_1BY: *((uint8_t *) discaddr) = (uint8_t) disc; break; + case DDS_OP_VAL_2BY: *((uint16_t *) discaddr) = (uint16_t) disc; break; + case DDS_OP_VAL_4BY: *((uint32_t *) discaddr) = disc; break; + default: break; + } + uint32_t const * const jeq_op = find_union_case (ops, disc); + ops += DDS_OP_ADR_JMP (ops[3]); + if (jeq_op) + { + const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]); + void *valaddr = baseaddr + jeq_op[2]; + switch (valtype) + { + case DDS_OP_VAL_1BY: *((uint8_t *) valaddr) = dds_is_get1 (is); break; + case DDS_OP_VAL_2BY: *((uint16_t *) valaddr) = dds_is_get2 (is); break; + case DDS_OP_VAL_4BY: *((uint32_t *) valaddr) = dds_is_get4 (is); break; + case DDS_OP_VAL_8BY: *((uint64_t *) valaddr) = dds_is_get8 (is); break; + case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr), 0); break; + case DDS_OP_VAL_BST: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: + dds_stream_read (is, valaddr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); + break; + } + } + return ops; +} + +static void dds_stream_read (dds_istream_t * __restrict is, char * __restrict data, const uint32_t * __restrict ops) +{ + uint32_t insn; + while ((insn = *ops) != DDS_OP_RTS) + { + switch (DDS_OP (insn)) + { + case DDS_OP_ADR: { + void *addr = data + ops[1]; + switch (DDS_OP_TYPE (insn)) + { + case DDS_OP_VAL_1BY: *((uint8_t *) addr) = dds_is_get1 (is); ops += 2; break; + case DDS_OP_VAL_2BY: *((uint16_t *) addr) = dds_is_get2 (is); ops += 2; break; + case DDS_OP_VAL_4BY: *((uint32_t *) addr) = dds_is_get4 (is); ops += 2; break; + case DDS_OP_VAL_8BY: *((uint64_t *) addr) = dds_is_get8 (is); ops += 2; break; + case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr), 0); ops += 2; break; + case DDS_OP_VAL_BST: dds_stream_reuse_string (is, (char *) addr, ops[2]); ops += 3; break; + case DDS_OP_VAL_SEQ: ops = dds_stream_read_seq (is, addr, ops, insn); break; + case DDS_OP_VAL_ARR: ops = dds_stream_read_arr (is, addr, ops, insn); break; + case DDS_OP_VAL_UNI: ops = dds_stream_read_uni (is, addr, data, ops, insn); break; + case DDS_OP_VAL_STU: abort (); break; + } + break; + } + case DDS_OP_JSR: { + dds_stream_read (is, data, ops + DDS_OP_JUMP (insn)); + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } +} + +/******************************************************************************************* + ** + ** Validation and conversion to native endian. + ** + *******************************************************************************************/ + +/* Limit the size of the input buffer so we don't need to worry about adding + padding and a primitive type overflowing our offset */ +#define CDR_SIZE_MAX ((uint32_t) 0xfffffff0) + +static bool stream_normalize (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, const uint32_t * __restrict ops); + +static uint32_t check_align_prim (uint32_t off, uint32_t size, uint32_t a_lg2) +{ + assert (a_lg2 <= 3); + const uint32_t a = 1u << a_lg2; + assert (size <= CDR_SIZE_MAX); + assert (off <= size); + const uint32_t off1 = (off + a - 1) & ~(a - 1); + assert (off <= off1 && off1 <= CDR_SIZE_MAX); + if (size < off1 + a) + return UINT32_MAX; + return off1; +} + +static uint32_t check_align_prim_many (uint32_t off, uint32_t size, uint32_t a_lg2, uint32_t n) +{ + assert (a_lg2 <= 3); + const uint32_t a = 1u << a_lg2; + assert (size <= CDR_SIZE_MAX); + assert (off <= size); + const uint32_t off1 = (off + a - 1) & ~(a - 1); + assert (off <= off1 && off1 <= CDR_SIZE_MAX); + if (size < off1 || ((size - off1) >> a_lg2) < n) + return UINT32_MAX; + return off1; +} + +static bool normalize_uint8 (uint32_t *off, uint32_t size) +{ + if (*off == size) + return false; + (*off)++; + return true; +} + +static bool normalize_uint16 (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap) +{ + if ((*off = check_align_prim (*off, size, 1)) == UINT32_MAX) + return false; + if (bswap) + *((uint16_t *) (data + *off)) = bswap2u (*((uint16_t *) (data + *off))); + (*off) += 2; + return true; +} + +static bool normalize_uint32 (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap) +{ + if ((*off = check_align_prim (*off, size, 2)) == UINT32_MAX) + return false; + if (bswap) + *((uint32_t *) (data + *off)) = bswap4u (*((uint32_t *) (data + *off))); + (*off) += 4; + return true; +} + +static bool read_and_normalize_uint32 (uint32_t * __restrict val, char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap) +{ + if ((*off = check_align_prim (*off, size, 2)) == UINT32_MAX) + return false; + if (bswap) + *((uint32_t *) (data + *off)) = bswap4u (*((uint32_t *) (data + *off))); + *val = *((uint32_t *) (data + *off)); + (*off) += 4; + return true; +} + +static bool normalize_uint64 (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap) +{ + if ((*off = check_align_prim (*off, size, 3)) == UINT32_MAX) + return false; + if (bswap) + *((uint64_t *) (data + *off)) = bswap8u (*((uint64_t *) (data + *off))); + (*off) += 8; + return true; +} + +static bool normalize_string (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, size_t maxsz) +{ + uint32_t sz; + if (!read_and_normalize_uint32 (&sz, data, off, size, bswap)) + return false; + if (sz == 0 || size - *off < sz || maxsz < sz) + return false; + if (data[*off + sz - 1] != 0) + return false; + *off += sz; + return true; +} + +static bool normalize_primarray (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, uint32_t num, enum dds_stream_typecode type) +{ + switch (type) + { + case DDS_OP_VAL_1BY: + if ((*off = check_align_prim_many (*off, size, 0, num)) == UINT32_MAX) + return false; + *off += num; + return true; + case DDS_OP_VAL_2BY: + if ((*off = check_align_prim_many (*off, size, 1, num)) == UINT32_MAX) + return false; + if (bswap) + { + uint16_t *xs = (uint16_t *) (data + *off); + for (uint32_t i = 0; i < num; i++) + xs[i] = bswap2u (xs[i]); + } + *off += 2 * num; + return true; + case DDS_OP_VAL_4BY: + if ((*off = check_align_prim_many (*off, size, 2, num)) == UINT32_MAX) + return false; + if (bswap) + { + uint32_t *xs = (uint32_t *) (data + *off); + for (uint32_t i = 0; i < num; i++) + xs[i] = bswap4u (xs[i]); + } + *off += 4 * num; + return true; + case DDS_OP_VAL_8BY: + if ((*off = check_align_prim_many (*off, size, 3, num)) == UINT32_MAX) + return false; + if (bswap) + { + uint64_t *xs = (uint64_t *) (data + *off); + for (uint32_t i = 0; i < num; i++) + xs[i] = bswap8u (xs[i]); + } + *off += 8 * num; + return true; + default: + abort (); + break; + } + return false; +} + +static const uint32_t *normalize_seq (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, const uint32_t * __restrict ops, uint32_t insn) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + uint32_t num; + if (!read_and_normalize_uint32 (&num, data, off, size, bswap)) + return NULL; + if (num == 0) + return skip_sequence_insns (ops, insn); + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: + if (!normalize_primarray (data, off, size, bswap, num, subtype)) + return NULL; + return ops + 2; + case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: { + const size_t maxsz = (subtype == DDS_OP_VAL_STR) ? SIZE_MAX : ops[2]; + for (uint32_t i = 0; i < num; i++) + if (!normalize_string (data, off, size, bswap, maxsz)) + return NULL; + return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3); + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + for (uint32_t i = 0; i < num; i++) + if (!stream_normalize (data, off, size, bswap, jsr_ops)) + return NULL; + return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */ + } + } + return NULL; +} + +static const uint32_t *normalize_arr (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, const uint32_t * __restrict ops, uint32_t insn) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + const uint32_t num = ops[2]; + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: + if (!normalize_primarray (data, off, size, bswap, num, subtype)) + return NULL; + return ops + 3; + case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: { + const size_t maxsz = (subtype == DDS_OP_VAL_STR) ? SIZE_MAX : ops[4]; + for (uint32_t i = 0; i < num; i++) + if (!normalize_string (data, off, size, bswap, maxsz)) + return NULL; + return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5); + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + for (uint32_t i = 0; i < num; i++) + if (!stream_normalize (data, off, size, bswap, jsr_ops)) + return NULL; + return ops + (jmp ? jmp : 5); + } + } + return NULL; +} + +static bool normalize_uni_disc (uint32_t * __restrict val, char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, enum dds_stream_typecode disctype) +{ + switch (disctype) + { + case DDS_OP_VAL_1BY: + if ((*off = check_align_prim (*off, size, 0)) == UINT32_MAX) + return false; + *val = *((uint8_t *) (data + *off)); + (*off) += 1; + return true; + case DDS_OP_VAL_2BY: + if ((*off = check_align_prim (*off, size, 1)) == UINT32_MAX) + return false; + if (bswap) + *((uint16_t *) (data + *off)) = bswap2u (*((uint16_t *) (data + *off))); + *val = *((uint16_t *) (data + *off)); + (*off) += 2; + return true; + case DDS_OP_VAL_4BY: + if ((*off = check_align_prim (*off, size, 2)) == UINT32_MAX) + return false; + if (bswap) + *((uint32_t *) (data + *off)) = bswap4u (*((uint32_t *) (data + *off))); + *val = *((uint32_t *) (data + *off)); + (*off) += 4; + return true; + default: + abort (); + } + return false; +} + +static const uint32_t *normalize_uni (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, const uint32_t * __restrict ops, uint32_t insn) +{ + uint32_t disc; + if (!normalize_uni_disc (&disc, data, off, size, bswap, DDS_OP_SUBTYPE (insn))) + return NULL; + uint32_t const * const jeq_op = find_union_case (ops, disc); + ops += DDS_OP_ADR_JMP (ops[3]); + if (jeq_op) + { + const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]); + switch (valtype) + { + case DDS_OP_VAL_1BY: if (!normalize_uint8 (off, size)) return NULL; break; + case DDS_OP_VAL_2BY: if (!normalize_uint16 (data, off, size, bswap)) return NULL; break; + case DDS_OP_VAL_4BY: if (!normalize_uint32 (data, off, size, bswap)) return NULL; break; + case DDS_OP_VAL_8BY: if (!normalize_uint64 (data, off, size, bswap)) return NULL; break; + case DDS_OP_VAL_STR: if (!normalize_string (data, off, size, bswap, SIZE_MAX)) return NULL; break; + case DDS_OP_VAL_BST: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: + if (!stream_normalize (data, off, size, bswap, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]))) + return NULL; + break; + } + } + return ops; +} + +static bool stream_normalize (char * __restrict data, uint32_t * __restrict off, uint32_t size, bool bswap, const uint32_t * __restrict ops) +{ + uint32_t insn; + while ((insn = *ops) != DDS_OP_RTS) + { + switch (DDS_OP (insn)) + { + case DDS_OP_ADR: { + switch (DDS_OP_TYPE (insn)) + { + case DDS_OP_VAL_1BY: if (!normalize_uint8 (off, size)) return false; ops += 2; break; + case DDS_OP_VAL_2BY: if (!normalize_uint16 (data, off, size, bswap)) return false; ops += 2; break; + case DDS_OP_VAL_4BY: if (!normalize_uint32 (data, off, size, bswap)) return false; ops += 2; break; + case DDS_OP_VAL_8BY: if (!normalize_uint64 (data, off, size, bswap)) return false; ops += 2; break; + case DDS_OP_VAL_STR: if (!normalize_string (data, off, size, bswap, SIZE_MAX)) return false; ops += 2; break; + case DDS_OP_VAL_BST: if (!normalize_string (data, off, size, bswap, ops[2])) return false; ops += 3; break; + case DDS_OP_VAL_SEQ: ops = normalize_seq (data, off, size, bswap, ops, insn); if (!ops) return false; break; + case DDS_OP_VAL_ARR: ops = normalize_arr (data, off, size, bswap, ops, insn); if (!ops) return false; break; + case DDS_OP_VAL_UNI: ops = normalize_uni (data, off, size, bswap, ops, insn); if (!ops) return false; break; + case DDS_OP_VAL_STU: abort (); break; + } + break; + } + case DDS_OP_JSR: { + if (!stream_normalize (data, off, size, bswap, ops + DDS_OP_JUMP (insn))) + return false; + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } + return true; +} + +static bool stream_normalize_key (void * __restrict data, uint32_t size, bool bswap, const struct dds_topic_descriptor * __restrict desc) +{ + uint32_t off = 0; + for (uint32_t i = 0; i < desc->m_nkeys; i++) + { + const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index; + assert (insn_key_ok_p (*op)); + switch (DDS_OP_TYPE (*op)) + { + case DDS_OP_VAL_1BY: if (!normalize_uint8 (&off, size)) return false; break; + case DDS_OP_VAL_2BY: if (!normalize_uint16 (data, &off, size, bswap)) return false; break; + case DDS_OP_VAL_4BY: if (!normalize_uint32 (data, &off, size, bswap)) return false; break; + case DDS_OP_VAL_8BY: if (!normalize_uint64 (data, &off, size, bswap)) return false; break; + case DDS_OP_VAL_STR: if (!normalize_string (data, &off, size, bswap, SIZE_MAX)) return false; break; + case DDS_OP_VAL_BST: if (!normalize_string (data, &off, size, bswap, op[2])) return false; break; + case DDS_OP_VAL_ARR: if (!normalize_arr (data, &off, size, bswap, op, *op)) return false; break; + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: + abort (); + break; + } + } + return true; +} + +bool dds_stream_normalize (void * __restrict data, uint32_t size, bool bswap, const struct ddsi_sertopic_default * __restrict topic, bool just_key) +{ + if (size > CDR_SIZE_MAX) + return false; + if (just_key) + return stream_normalize_key (data, size, bswap, topic->type); + else + { + uint32_t off = 0; + return stream_normalize (data, &off, size, bswap, topic->type->m_ops); + } +} + +/******************************************************************************************* + ** + ** Read/write of samples and keys -- i.e., DDSI payloads. + ** + *******************************************************************************************/ + +void dds_stream_read_sample (dds_istream_t * __restrict is, void * __restrict data, const struct ddsi_sertopic_default * __restrict topic) +{ + const struct dds_topic_descriptor *desc = topic->type; + if (topic->opt_size) + dds_is_get_bytes (is, data, desc->m_size, 1); + else + { + if (desc->m_flagset & DDS_TOPIC_CONTAINS_UNION) + { + /* Switching union cases causes big trouble if some cases have sequences or strings, + and other cases have other things mapped to those addresses. So, pretend to be + nice by freeing whatever was allocated, then clearing all memory. This will + make any preallocated buffers go to waste, but it does allow reusing the message + from read-to-read, at the somewhat reasonable price of a slower deserialization + and not being able to use preallocated sequences in topics containing unions. */ + dds_sample_free_contents (data, desc->m_ops); + memset (data, 0, desc->m_size); + } + dds_stream_read (is, data, desc->m_ops); + } +} + +void dds_stream_write_sample (dds_ostream_t * __restrict os, const void * __restrict data, const struct ddsi_sertopic_default * __restrict topic) +{ + const struct dds_topic_descriptor *desc = topic->type; + if (topic->opt_size && desc->m_align && (os->m_index % desc->m_align) == 0) + dds_os_put_bytes (os, data, desc->m_size); + else + dds_stream_write (os, data, desc->m_ops); +} + +void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic) +{ + const dds_topic_descriptor_t *desc = topic->type; + for (uint32_t i = 0; i < desc->m_nkeys; i++) + { + const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index; + char *dst = sample + op[1]; + assert (insn_key_ok_p (*op)); + switch (DDS_OP_TYPE (*op)) + { + case DDS_OP_VAL_1BY: *((uint8_t *) dst) = dds_is_get1 (is); break; + case DDS_OP_VAL_2BY: *((uint16_t *) dst) = dds_is_get2 (is); break; + case DDS_OP_VAL_4BY: *((uint32_t *) dst) = dds_is_get4 (is); break; + case DDS_OP_VAL_8BY: *((uint64_t *) dst) = dds_is_get8 (is); break; + case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst), 0); break; + case DDS_OP_VAL_BST: dds_stream_reuse_string (is, dst, op[2]); break; + case DDS_OP_VAL_ARR: + dds_is_get_bytes (is, dst, op[2], get_type_size (DDS_OP_SUBTYPE (*op))); + break; + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: + abort (); + break; + } + } +} + +void dds_stream_write_key (dds_ostream_t * __restrict os, const char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic) +{ + const struct dds_topic_descriptor *desc = (const struct dds_topic_descriptor *) topic->type; + for (uint32_t i = 0; i < desc->m_nkeys; i++) + { + const uint32_t *insnp = desc->m_ops + desc->m_keys[i].m_index; + const void *src = sample + insnp[1]; + assert (insn_key_ok_p (*insnp)); + switch (DDS_OP_TYPE (*insnp)) + { + case DDS_OP_VAL_1BY: dds_os_put1 (os, *((uint8_t *) src)); break; + case DDS_OP_VAL_2BY: dds_os_put2 (os, *((uint16_t *) src)); break; + case DDS_OP_VAL_4BY: dds_os_put4 (os, *((uint32_t *) src)); break; + case DDS_OP_VAL_8BY: dds_os_put8 (os, *((uint64_t *) src)); break; + case DDS_OP_VAL_STR: dds_stream_write_string (os, *(char **) src); break; + case DDS_OP_VAL_BST: dds_stream_write_string (os, src); break; + case DDS_OP_VAL_ARR: { + const uint32_t elem_size = get_type_size (DDS_OP_SUBTYPE (*insnp)); + const uint32_t num = insnp[2]; + dds_cdr_alignto_clear_and_resize(os, elem_size, num * elem_size); + dds_os_put_bytes (os, src, num * elem_size); + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + abort (); + break; + } + } + } +} + +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN +static void dds_stream_swap_insitu (void * __restrict vbuf, uint32_t size, uint32_t num) +{ + assert (size == 1 || size == 2 || size == 4 || size == 8); + switch (size) + { + case 1: + break; + case 2: { + uint16_t *buf = vbuf; + for (uint32_t i = 0; i < num; i++) + buf[i] = bswap2u (buf[i]); + break; + } + case 4: { + uint32_t *buf = vbuf; + for (uint32_t i = 0; i < num; i++) + buf[i] = bswap4u (buf[i]); + break; + } + case 8: { + uint64_t *buf = vbuf; + for (uint32_t i = 0; i < num; i++) + buf[i] = bswap8u (buf[i]); + break; + } + } +} + +void dds_stream_write_keyBE (dds_ostreamBE_t * __restrict os, const char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic) +{ + const struct dds_topic_descriptor *desc = (const struct dds_topic_descriptor *) topic->type; + for (uint32_t i = 0; i < desc->m_nkeys; i++) + { + const uint32_t *insnp = desc->m_ops + desc->m_keys[i].m_index; + const void *src = sample + insnp[1]; + assert (insn_key_ok_p (*insnp)); + switch (DDS_OP_TYPE (*insnp)) + { + case DDS_OP_VAL_1BY: dds_os_put1be (os, *((uint8_t *) src)); break; + case DDS_OP_VAL_2BY: dds_os_put2be (os, *((uint16_t *) src)); break; + case DDS_OP_VAL_4BY: dds_os_put4be (os, *((uint32_t *) src)); break; + case DDS_OP_VAL_8BY: dds_os_put8be (os, *((uint64_t *) src)); break; + case DDS_OP_VAL_STR: dds_streamBE_write_string (os, *(char **) src); break; + case DDS_OP_VAL_BST: dds_streamBE_write_string (os, src); break; + case DDS_OP_VAL_ARR: { + const uint32_t elem_size = get_type_size (DDS_OP_SUBTYPE (*insnp)); + const uint32_t num = insnp[2]; + dds_cdr_alignto_clear_and_resize_be (os, elem_size, num * elem_size); + void * const dst = os->x.m_buffer + os->x.m_index; + dds_os_put_bytes (&os->x, src, num * elem_size); + dds_stream_swap_insitu (dst, elem_size, num); + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + abort (); + break; + } + } + } +} +#elif DDSRT_ENDIAN == DDSRT_BIG_ENDIAN +void dds_stream_write_keyBE (dds_ostreamBE_t * __restrict os, const char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic) +{ + dds_stream_write_key (&os->x, sample, topic); +} +#else +#error "DDSRT_ENDIAN neither LITTLE nor BIG" +#endif + +/******************************************************************************************* + ** + ** Extracting key/keyhash (the only difference that a keyhash MUST be big-endian, + ** padding MUST be cleared, and that it may be necessary to run the value through + ** MD5. + ** + *******************************************************************************************/ + +static void dds_stream_extract_key_from_data1 (dds_istream_t * __restrict is, dds_ostream_t * __restrict os, const uint32_t * __restrict ops, uint32_t * __restrict keys_remaining); + +static void dds_stream_extract_key_from_key_prim_op (dds_istream_t * __restrict is, dds_ostream_t * __restrict os, const uint32_t * __restrict op) +{ + assert ((*op & DDS_OP_FLAG_KEY) && ((DDS_OP (*op)) == DDS_OP_ADR)); + switch (DDS_OP_TYPE (*op)) + { + case DDS_OP_VAL_1BY: dds_os_put1 (os, dds_is_get1 (is)); break; + case DDS_OP_VAL_2BY: dds_os_put2 (os, dds_is_get2 (is)); break; + case DDS_OP_VAL_4BY: dds_os_put4 (os, dds_is_get4 (is)); break; + case DDS_OP_VAL_8BY: dds_os_put8 (os, dds_is_get8 (is)); break; + case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: { + uint32_t sz = dds_is_get4 (is); + dds_os_put4 (os, sz); + dds_os_put_bytes (os, is->m_buffer + is->m_index, sz); + is->m_index += sz; + break; + } + case DDS_OP_VAL_ARR: { + const uint32_t subtype = DDS_OP_SUBTYPE (*op); + assert (subtype <= DDS_OP_VAL_8BY); + const uint32_t align = get_type_size (subtype); + const uint32_t num = op[2]; + dds_cdr_alignto_clear_and_resize (os, align, num * align); + void * const dst = os->m_buffer + os->m_index; + dds_is_get_bytes (is, dst, num, align); + os->m_index += num * align; + is->m_index += num * align; + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + abort (); + break; + } + } +} + +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN +static void dds_stream_swap_copy (void * __restrict vdst, const void * __restrict vsrc, uint32_t size, uint32_t num) +{ + assert (size == 2 || size == 4 || size == 8); + switch (size) + { + case 2: { + const uint16_t *src = vsrc; + uint16_t *dst = vdst; + for (uint32_t i = 0; i < num; i++) + dst[i] = bswap2u (src[i]); + break; + } + case 4: { + const uint32_t *src = vsrc; + uint32_t *dst = vdst; + for (uint32_t i = 0; i < num; i++) + dst[i] = bswap4u (src[i]); + break; + } + case 8: { + const uint64_t *src = vsrc; + uint64_t *dst = vdst; + for (uint32_t i = 0; i < num; i++) + dst[i] = bswap8u (src[i]); + break; + } + } +} +#endif + +static void dds_stream_extract_keyBE_from_key_prim_op (dds_istream_t * __restrict is, dds_ostreamBE_t * __restrict os, const uint32_t * __restrict op) +{ + assert ((*op & DDS_OP_FLAG_KEY) && ((DDS_OP (*op)) == DDS_OP_ADR)); + switch (DDS_OP_TYPE (*op)) + { + case DDS_OP_VAL_1BY: dds_os_put1be (os, dds_is_get1 (is)); break; + case DDS_OP_VAL_2BY: dds_os_put2be (os, dds_is_get2 (is)); break; + case DDS_OP_VAL_4BY: dds_os_put4be (os, dds_is_get4 (is)); break; + case DDS_OP_VAL_8BY: dds_os_put8be (os, dds_is_get8 (is)); break; + case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: { + uint32_t sz = dds_is_get4 (is); + dds_os_put4be (os, sz); + dds_os_put_bytes (&os->x, is->m_buffer + is->m_index, sz); + is->m_index += sz; + break; + } + case DDS_OP_VAL_ARR: { + const uint32_t subtype = DDS_OP_SUBTYPE (*op); + assert (subtype <= DDS_OP_VAL_8BY); + const uint32_t align = get_type_size (subtype); + const uint32_t num = op[2]; + dds_cdr_alignto (is, align); + dds_cdr_alignto_clear_and_resize_be (os, align, num * align); + void const * const src = is->m_buffer + is->m_index; + void * const dst = os->x.m_buffer + os->x.m_index; +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN + dds_stream_swap_copy (dst, src, num, align); +#else + memcpy (dst, src, num * align); +#endif + os->x.m_index += num * align; + is->m_index += num * align; + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + abort (); + break; + } + } +} + +static void dds_stream_extract_keyBE_from_key (dds_istream_t * __restrict is, dds_ostreamBE_t * __restrict os, const struct ddsi_sertopic_default * __restrict topic) +{ + const dds_topic_descriptor_t *desc = topic->type; + for (uint32_t i = 0; i < desc->m_nkeys; i++) + { + uint32_t const * const op = desc->m_ops + desc->m_keys[i].m_index; + dds_stream_extract_keyBE_from_key_prim_op (is, os, op); + } +} + +static void dds_stream_extract_key_from_data_skip_subtype (dds_istream_t * __restrict is, uint32_t num, uint32_t subtype, const uint32_t * __restrict subops) +{ + switch (subtype) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: { + const uint32_t elem_size = get_type_size (subtype); + dds_cdr_alignto (is, elem_size); + is->m_index += num * elem_size; + break; + } + case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: { + for (uint32_t i = 0; i < num; i++) + { + const uint32_t len = dds_is_get4 (is); + is->m_index += len; + } + break; + } + case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { + uint32_t remain = UINT32_MAX; + for (uint32_t i = 0; i < num; i++) + dds_stream_extract_key_from_data1 (is, NULL, subops, &remain); + break; + } + } +} + +static const uint32_t *dds_stream_extract_key_from_data_skip_array (dds_istream_t * __restrict is, const uint32_t * __restrict ops) +{ + const uint32_t op = *ops; + assert (DDS_OP_TYPE (op) == DDS_OP_VAL_ARR); + const uint32_t subtype = DDS_OP_SUBTYPE (op); + const uint32_t num = ops[2]; + if (subtype > DDS_OP_VAL_BST) + { + const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + dds_stream_extract_key_from_data_skip_subtype (is, num, subtype, jsr_ops); + return ops + (jmp ? jmp : 5); + } + else + { + dds_stream_extract_key_from_data_skip_subtype (is, num, subtype, NULL); + return ops + 3; + } +} + +static const uint32_t *dds_stream_extract_key_from_data_skip_sequence (dds_istream_t * __restrict is, const uint32_t * __restrict ops) +{ + const uint32_t op = *ops; + const enum dds_stream_typecode type = DDS_OP_TYPE (op); + assert (type == DDS_OP_VAL_SEQ); + const uint32_t subtype = DDS_OP_SUBTYPE (op); + const uint32_t num = dds_is_get4 (is); + if (num == 0) + return ops + 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + else if (subtype > DDS_OP_VAL_BST) + { + const uint32_t * jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); + dds_stream_extract_key_from_data_skip_subtype (is, num, subtype, jsr_ops); + return ops + (jmp ? jmp : 4); + } + else + { + dds_stream_extract_key_from_data_skip_subtype (is, num, subtype, NULL); + return ops + 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + } +} + +static const uint32_t *dds_stream_extract_key_from_data_skip_union (dds_istream_t * __restrict is, const uint32_t * __restrict ops) +{ + const uint32_t op = *ops; + assert (DDS_OP_TYPE (op) == DDS_OP_VAL_UNI); + const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (op)); + uint32_t const * const jeq_op = find_union_case (ops, disc); + if (jeq_op) + dds_stream_extract_key_from_data_skip_subtype (is, 1, DDS_JEQ_TYPE (jeq_op[0]), jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); + return ops + DDS_OP_ADR_JMP (ops[3]); +} + +static void dds_stream_extract_key_from_data1 (dds_istream_t * __restrict is, dds_ostream_t * __restrict os, const uint32_t * __restrict ops, uint32_t * __restrict keys_remaining) +{ + uint32_t op; + while ((op = *ops) != DDS_OP_RTS) + { + switch (DDS_OP (op)) + { + case DDS_OP_ADR: { + const uint32_t type = DDS_OP_TYPE (op); + const bool is_key = (op & DDS_OP_FLAG_KEY) && (os != NULL); + if (is_key) + { + dds_stream_extract_key_from_key_prim_op (is, os, ops); + if (--(*keys_remaining) == 0) + return; + ops += 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + } + else + { + switch (type) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: + dds_stream_extract_key_from_data_skip_subtype (is, 1, type, NULL); + ops += 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + break; + case DDS_OP_VAL_SEQ: + ops = dds_stream_extract_key_from_data_skip_sequence (is, ops); + break; + case DDS_OP_VAL_ARR: + ops = dds_stream_extract_key_from_data_skip_array (is, ops); + break; + case DDS_OP_VAL_UNI: + ops = dds_stream_extract_key_from_data_skip_union (is, ops); + break; + case DDS_OP_VAL_STU: + abort (); + } + } + break; + } + case DDS_OP_JSR: { /* Implies nested type */ + ops += 2; + dds_stream_extract_key_from_data1 (is, os, ops + DDS_OP_JUMP (op), keys_remaining); + if (--(*keys_remaining) == 0) + return; + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } +} + +static void dds_stream_extract_keyBE_from_data1 (dds_istream_t * __restrict is, dds_ostreamBE_t * __restrict os, const uint32_t * __restrict ops, uint32_t * __restrict keys_remaining) +{ + uint32_t op; + while ((op = *ops) != DDS_OP_RTS) + { + switch (DDS_OP (op)) + { + case DDS_OP_ADR: { + const uint32_t type = DDS_OP_TYPE (op); + const bool is_key = (op & DDS_OP_FLAG_KEY) && (os != NULL); + if (is_key) + { + dds_stream_extract_keyBE_from_key_prim_op (is, os, ops); + if (--(*keys_remaining) == 0) + return; + ops += 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + } + else + { + switch (type) + { + case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: + dds_stream_extract_key_from_data_skip_subtype (is, 1, type, NULL); + ops += 2 + (type == DDS_OP_VAL_BST || type == DDS_OP_VAL_ARR); + break; + case DDS_OP_VAL_SEQ: + ops = dds_stream_extract_key_from_data_skip_sequence (is, ops); + break; + case DDS_OP_VAL_ARR: + ops = dds_stream_extract_key_from_data_skip_array (is, ops); + break; + case DDS_OP_VAL_UNI: + ops = dds_stream_extract_key_from_data_skip_union (is, ops); + break; + case DDS_OP_VAL_STU: + abort (); + } + } + break; + } + case DDS_OP_JSR: { /* Implies nested type */ + ops += 2; + dds_stream_extract_keyBE_from_data1 (is, os, ops + DDS_OP_JUMP (op), keys_remaining); + if (--(*keys_remaining) == 0) + return; + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } +} + +void dds_stream_extract_key_from_data (dds_istream_t * __restrict is, dds_ostream_t * __restrict os, const struct ddsi_sertopic_default * __restrict topic) +{ + const dds_topic_descriptor_t *desc = topic->type; + uint32_t keys_remaining = desc->m_nkeys; + dds_stream_extract_key_from_data1 (is, os, desc->m_ops, &keys_remaining); +} + +void dds_stream_extract_keyBE_from_data (dds_istream_t * __restrict is, dds_ostreamBE_t * __restrict os, const struct ddsi_sertopic_default * __restrict topic) +{ + const dds_topic_descriptor_t *desc = topic->type; + uint32_t keys_remaining = desc->m_nkeys; + dds_stream_extract_keyBE_from_data1 (is, os, desc->m_ops, &keys_remaining); +} + +void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t * __restrict kh, const struct ddsi_sertopic_default * __restrict topic, const bool just_key) +{ + const dds_topic_descriptor_t *desc = topic->type; kh->m_set = 1; if (desc->m_nkeys == 0) kh->m_iskey = 1; else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) { - dds_stream_t os; - uint32_t ncheck; + dds_ostreamBE_t os; kh->m_iskey = 1; - dds_stream_init(&os, 0); - os.m_buffer.pv = kh->m_hash; - os.m_size = 16; - os.m_endian = 0; - ncheck = dds_stream_extract_key (is, &os, desc->m_ops, just_key); - assert(ncheck <= 16); - (void)ncheck; + dds_ostreamBE_init (&os, 0); + os.x.m_buffer = kh->m_hash; + os.x.m_size = 16; + if (just_key) + dds_stream_extract_keyBE_from_key (is, &os, topic); + else + dds_stream_extract_keyBE_from_data (is, &os, topic); + assert (os.x.m_index <= 16); } else { - dds_stream_t os; + dds_ostreamBE_t os; ddsrt_md5_state_t md5st; kh->m_iskey = 0; - dds_stream_init (&os, 0); - os.m_endian = 0; - dds_stream_extract_key (is, &os, desc->m_ops, just_key); + dds_ostreamBE_init (&os, 0); + if (just_key) + dds_stream_extract_keyBE_from_key (is, &os, topic); + else + dds_stream_extract_keyBE_from_data (is, &os, topic); ddsrt_md5_init (&md5st); - ddsrt_md5_append (&md5st, os.m_buffer.p8, os.m_index); - ddsrt_md5_finish (&md5st, (unsigned char *) kh->m_hash); - dds_stream_fini (&os); + ddsrt_md5_append (&md5st, os.x.m_buffer, os.x.m_index); + ddsrt_md5_finish (&md5st, kh->m_hash); + dds_ostreamBE_fini (&os); } } -void dds_stream_read_key -( - dds_stream_t * is, - char * sample, - const dds_topic_descriptor_t * desc -) +/******************************************************************************************* + ** + ** Stuff to make it possible to treat a ddsi_serdata_default as a stream + ** + *******************************************************************************************/ + +DDSRT_STATIC_ASSERT ((offsetof (struct ddsi_serdata_default, data) % 8) == 0); + +void dds_istream_from_serdata_default (dds_istream_t * __restrict s, const struct ddsi_serdata_default * __restrict d) { - uint32_t i; - char * dst; - const uint32_t * op; - - for (i = 0; i < desc->m_nkeys; i++) - { - op = desc->m_ops + desc->m_keys[i].m_index; - dst = sample + op[1]; - assert ((*op & DDS_OP_FLAG_KEY) && ((DDS_OP_MASK & *op) == DDS_OP_ADR)); - switch (DDS_OP_TYPE (*op)) - { - case DDS_OP_VAL_1BY: - *((uint8_t*) dst) = dds_stream_read_uint8 (is); - break; - case DDS_OP_VAL_2BY: - *((uint16_t*) dst) = dds_stream_read_uint16 (is); - break; - case DDS_OP_VAL_4BY: - *((uint32_t*) dst) = dds_stream_read_uint32 (is); - break; - case DDS_OP_VAL_8BY: - *((uint64_t*) dst) = dds_stream_read_uint64 (is); - break; - case DDS_OP_VAL_STR: - *((char**) dst) = dds_stream_reuse_string (is, *((char**) dst), 0); - break; - case DDS_OP_VAL_BST: - dds_stream_reuse_string (is, dst, op[2]); - break; - case DDS_OP_VAL_ARR: - { - uint32_t subtype = DDS_OP_SUBTYPE (*op); - assert (subtype <= DDS_OP_VAL_8BY); - dds_stream_read_fixed_buffer (is, dst, op[2], dds_op_size[subtype], is->m_endian != DDS_ENDIAN); - break; - } - default: assert (0); - } - } + s->m_buffer = (const unsigned char *) d; + s->m_index = (uint32_t) offsetof (struct ddsi_serdata_default, data); + s->m_size = d->size + s->m_index; +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN + assert (d->hdr.identifier == CDR_LE); +#elif DDSRT_ENDIAN == DDSRT_BIG_ENDIAN + assert (d->hdr.identifier == CDR_BE); +#else +#error "DDSRT_ENDIAN neither LITTLE nor BIG" +#endif +} + +void dds_ostream_from_serdata_default (dds_ostream_t * __restrict s, struct ddsi_serdata_default * __restrict d) +{ + s->m_buffer = (unsigned char *) d; + s->m_index = (uint32_t) offsetof (struct ddsi_serdata_default, data); + s->m_size = d->size + s->m_index; +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN + assert (d->hdr.identifier == CDR_LE); +#elif DDSRT_ENDIAN == DDSRT_BIG_ENDIAN + assert (d->hdr.identifier == CDR_BE); +#else +#error "DDSRT_ENDIAN neither LITTLE nor BIG" +#endif +} + +void dds_ostream_add_to_serdata_default (dds_ostream_t * __restrict s, struct ddsi_serdata_default ** __restrict d) +{ + /* DDSI requires 4 byte alignment */ + + const uint32_t pad = dds_cdr_alignto_clear_and_resize (s, 4, 0); + assert (pad <= 3); + + /* Reset data pointer as stream may have reallocated */ + + (*d) = (void *) s->m_buffer; + (*d)->pos = (s->m_index - (uint32_t) offsetof (struct ddsi_serdata_default, data)); + (*d)->size = (s->m_size - (uint32_t) offsetof (struct ddsi_serdata_default, data)); + (*d)->hdr.options = toBE2u ((uint16_t) pad); +} + +void dds_ostreamBE_from_serdata_default (dds_ostreamBE_t * __restrict s, struct ddsi_serdata_default * __restrict d) +{ + s->x.m_buffer = (unsigned char *) d; + s->x.m_index = (uint32_t) offsetof (struct ddsi_serdata_default, data); + s->x.m_size = d->size + s->x.m_index; + assert (d->hdr.identifier == CDR_BE); +} + +void dds_ostreamBE_add_to_serdata_default (dds_ostreamBE_t * __restrict s, struct ddsi_serdata_default ** __restrict d) +{ + /* DDSI requires 4 byte alignment */ + + const uint32_t pad = dds_cdr_alignto_clear_and_resize_be (s, 4, 0); + assert (pad <= 3); + + /* Reset data pointer as stream may have reallocated */ + + (*d) = (void *) s->x.m_buffer; + (*d)->pos = (s->x.m_index - (uint32_t) offsetof (struct ddsi_serdata_default, data)); + (*d)->size = (s->x.m_size - (uint32_t) offsetof (struct ddsi_serdata_default, data)); + (*d)->hdr.options = toBE2u ((uint16_t) pad); } diff --git a/src/core/ddsc/src/dds_subscriber.c b/src/core/ddsc/src/dds_subscriber.c index 1a51775..2c3f6ae 100644 --- a/src/core/ddsc/src/dds_subscriber.c +++ b/src/core/ddsc/src/dds_subscriber.c @@ -11,203 +11,93 @@ */ #include #include "dds__listener.h" -#include "dds__qos.h" -#include "dds__err.h" +#include "dds__participant.h" #include "dds__subscriber.h" +#include "dds__qos.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_globals.h" +#include "dds/ddsrt/heap.h" #include "dds/version.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_subscriber) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_subscriber) #define DDS_SUBSCRIBER_STATUS_MASK \ - DDS_DATA_ON_READERS_STATUS + (DDS_DATA_ON_READERS_STATUS) -static dds_return_t -dds_subscriber_instance_hdl( - dds_entity *e, - dds_instance_handle_t *i) +static dds_return_t dds_subscriber_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) { - (void)e; - (void)i; - /* TODO: Get/generate proper handle. */ - DDS_ERROR("Generating subscriber instance handle is not supported"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); + /* note: e->m_qos is still the old one to allow for failure here */ + (void) e; (void) qos; (void) enabled; + return DDS_RETCODE_OK; } -static dds_return_t -dds__subscriber_qos_validate( - const dds_qos_t *qos, - bool enabled) +static dds_return_t dds_subscriber_status_validate (uint32_t mask) { - dds_return_t ret = DDS_RETCODE_OK; + return (mask & ~DDS_SUBSCRIBER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; +} - assert(qos); +const struct dds_entity_deriver dds_entity_deriver_subscriber = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_entity_deriver_dummy_delete, + .set_qos = dds_subscriber_qos_set, + .validate_status = dds_subscriber_status_validate +}; - if((qos->present & QP_GROUP_DATA) && !validate_octetseq(&qos->group_data)) { - DDS_ERROR("Group data policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PARTITION) && !validate_stringseq(&qos->partition)) { - DDS_ERROR("Partition policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PRESENTATION) && validate_presentation_qospolicy(&qos->presentation)) { - DDS_ERROR("Presentation policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy(&qos->entity_factory)) { - DDS_ERROR("Prismtech entity factory policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if(ret == DDS_RETCODE_OK && enabled && (qos->present & QP_PRESENTATION)) { - /* TODO: Improve/check immutable check. */ - DDS_ERROR("Presentation QoS policy is immutable\n"); - ret = DDS_ERRNO(DDS_RETCODE_IMMUTABLE_POLICY); - } +dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_qos_t *qos, const dds_listener_t *listener) +{ + /* participant entity lock must be held */ + dds_subscriber *sub; + dds_entity_t subscriber; + dds_return_t ret; + dds_qos_t *new_qos; + new_qos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (new_qos, qos, DDS_SUBSCRIBER_QOS_MASK); + nn_xqos_mergein_missing (new_qos, &participant->m_entity.m_domain->gv.default_xqos_sub, ~(uint64_t)0); + if ((ret = nn_xqos_valid (&participant->m_entity.m_domain->gv.logconfig, new_qos)) != DDS_RETCODE_OK) + { + dds_delete_qos (new_qos); return ret; + } + + sub = dds_alloc (sizeof (*sub)); + subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK); + sub->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&participant->m_entity, &sub->m_entity); + return subscriber; } -static dds_return_t -dds_subscriber_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) +dds_entity_t dds_create_subscriber (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener) { - dds_return_t ret = dds__subscriber_qos_validate(qos, enabled); - (void)e; - if (ret == DDS_RETCODE_OK) { - if (enabled) { - /* TODO: CHAM-95: DDSI does not support changing QoS policies. */ - DDS_ERROR(DDS_PROJECT_NAME" does not support changing QoS policies yet\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); - } - } + dds_participant *par; + dds_entity_t hdl; + dds_return_t ret; + if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) return ret; + hdl = dds__create_subscriber_l (par, qos, listener); + dds_participant_unlock (par); + return hdl; } -static dds_return_t -dds_subscriber_status_validate( - uint32_t mask) +dds_return_t dds_notify_readers (dds_entity_t subscriber) { - dds_return_t ret = DDS_RETCODE_OK; - - if (mask & ~(DDS_SUBSCRIBER_STATUS_MASK)) { - DDS_ERROR("Invalid status mask\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - + dds_subscriber *sub; + dds_return_t ret; + if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK) return ret; + dds_subscriber_unlock (sub); + return DDS_RETCODE_UNSUPPORTED; } -dds_entity_t -dds__create_subscriber_l( - dds_entity *participant, /* entity-lock must be held */ - const dds_qos_t *qos, - const dds_listener_t *listener) +dds_return_t dds_subscriber_begin_coherent (dds_entity_t e) { - dds_subscriber * sub; - dds_entity_t subscriber; - dds_return_t ret; - dds_qos_t * new_qos; - - /* Validate qos */ - if (qos) { - if ((ret = dds__subscriber_qos_validate(qos, false)) != DDS_RETCODE_OK) { - goto err_param; - } - new_qos = dds_create_qos(); - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(new_qos, qos); - } else { - new_qos = NULL; - } - - /* Create subscriber */ - sub = dds_alloc(sizeof(*sub)); - subscriber = dds_entity_init(&sub->m_entity, participant, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK); - sub->m_entity.m_deriver.set_qos = dds_subscriber_qos_set; - sub->m_entity.m_deriver.validate_status = dds_subscriber_status_validate; - sub->m_entity.m_deriver.get_instance_hdl = dds_subscriber_instance_hdl; - - return subscriber; - - /* Error handling */ -err_param: - return ret; + return dds_generic_unimplemented_operation (e, DDS_KIND_SUBSCRIBER); } -dds_entity_t -dds_create_subscriber( - dds_entity_t participant, - const dds_qos_t *qos, - const dds_listener_t *listener) +dds_return_t dds_subscriber_end_coherent (dds_entity_t e) { - dds_entity * par; - dds_entity_t hdl; - dds_retcode_t errnr; - - errnr = dds_entity_lock(participant, DDS_KIND_PARTICIPANT, &par); - if (errnr != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking participant\n"); - hdl = DDS_ERRNO(errnr); - return hdl; - } - - hdl = dds__create_subscriber_l(par, qos, listener); - dds_entity_unlock(par); - - return hdl; -} - -dds_return_t -dds_notify_readers( - dds_entity_t subscriber) -{ - dds_entity *iter; - dds_entity *sub; - dds_retcode_t errnr; - dds_return_t ret; - - errnr = dds_entity_lock(subscriber, DDS_KIND_SUBSCRIBER, &sub); - if (errnr == DDS_RETCODE_OK) { - errnr = DDS_RETCODE_UNSUPPORTED; - DDS_ERROR("Unsupported operation\n"); - ret = DDS_ERRNO(errnr); - iter = sub->m_children; - while (iter) { - ddsrt_mutex_lock(&iter->m_mutex); - // TODO: check if reader has data available, call listener - ddsrt_mutex_unlock(&iter->m_mutex); - iter = iter->m_next; - } - dds_entity_unlock(sub); - } else { - DDS_ERROR("Error occurred on locking subscriber\n"); - ret = DDS_ERRNO(errnr); - } - - return ret; -} - -dds_return_t -dds_subscriber_begin_coherent( - dds_entity_t e) -{ - /* TODO: CHAM-124 Currently unsupported. */ - (void)e; - DDS_ERROR("Using coherency to get a coherent data set is not currently being supported\n"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); -} - -dds_return_t -dds_subscriber_end_coherent( - dds_entity_t e) -{ - /* TODO: CHAM-124 Currently unsupported. */ - (void)e; - DDS_ERROR("Using coherency to get a coherent data set is not currently being supported\n"); - return DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); + return dds_generic_unimplemented_operation (e, DDS_KIND_SUBSCRIBER); } diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index c0cb41d..e9f0fc5 100644 --- a/src/core/ddsc/src/dds_topic.c +++ b/src/core/ddsc/src/dds_topic.c @@ -14,79 +14,76 @@ #include #include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" #include "dds__topic.h" #include "dds__listener.h" -#include "dds__qos.h" +#include "dds__participant.h" #include "dds__stream.h" #include "dds__init.h" #include "dds__domain.h" -#include "dds__err.h" +#include "dds__get_status.h" +#include "dds__qos.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/q_ddsi_discovery.h" #include "dds/ddsi/ddsi_iid.h" +#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/q_globals.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_topic) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic) #define DDS_TOPIC_STATUS_MASK \ - DDS_INCONSISTENT_TOPIC_STATUS + (DDS_INCONSISTENT_TOPIC_STATUS) -const ddsrt_avl_treedef_t dds_topictree_def = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY -( - offsetof (struct ddsi_sertopic, avlnode), - offsetof (struct ddsi_sertopic, name_type_name), - (int (*) (const void *, const void *)) strcmp, - 0 -); +struct topic_sertopic_node { + ddsrt_avl_node_t avlnode; + uint32_t refc; + const struct ddsi_sertopic *st; +}; -static bool -is_valid_name( - const char *name) +static int topic_sertopic_node_cmp (const void *va, const void *vb) { - bool valid = false; - /* DDS Spec: - * | TOPICNAME - A topic name is an identifier for a topic, and is defined as any series of characters - * | 'a', ..., 'z', - * | 'A', ..., 'Z', - * | '0', ..., '9', - * | '-' but may not start with a digit. - * It is considered that '-' is an error in the spec and should say '_'. So, that's what we'll check for. - * | '/' got added for ROS2 - */ - assert(name); - if ((name[0] != '\0') && (!isdigit((unsigned char)name[0]))) { - while (isalnum((unsigned char)*name) || (*name == '_') || (*name == '/')) { - name++; - } - if (*name == '\0') { - valid = true; - } - } - - return valid; + const struct ddsi_sertopic *a = va; + const struct ddsi_sertopic *b = vb; + return strcmp (a->name, b->name); } +const ddsrt_avl_treedef_t dds_topictree_def = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY (offsetof (struct topic_sertopic_node, avlnode), offsetof (struct topic_sertopic_node, st), topic_sertopic_node_cmp, 0); -static dds_return_t -dds_topic_status_validate( - uint32_t mask) +static bool is_valid_name (const char *name) ddsrt_nonnull_all; + +static bool is_valid_name (const char *name) { - dds_return_t ret = DDS_RETCODE_OK; + /* DDS Spec: + * | TOPICNAME - A topic name is an identifier for a topic, and is defined as any series of characters + * | 'a', ..., 'z', + * | 'A', ..., 'Z', + * | '0', ..., '9', + * | '-' but may not start with a digit. + * It is considered that '-' is an error in the spec and should say '_'. So, that's what we'll check for. + * | '/' got added for ROS2 + */ + if (name[0] == '\0' || isdigit ((unsigned char) name[0])) + return false; + for (size_t i = 0; name[i]; i++) + if (!(isalnum ((unsigned char) name[i]) || name[i] == '_' || name[i] == '/')) + return false; + return true; +} - if (mask & ~(DDS_TOPIC_STATUS_MASK)) { - DDS_ERROR("Argument mask is invalid\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - - return ret; +static dds_return_t dds_topic_status_validate (uint32_t mask) +{ + return (mask & ~DDS_TOPIC_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } /* Topic status change callback handler. Supports INCONSISTENT_TOPIC - status (only defined status on a topic). + status (only defined status on a topic). Irrelevant until inconsistent topic + definitions can be detected, so until topic discovery is added. */ - +#if 0 static void dds_topic_status_cb (struct dds_topic *tp) { struct dds_listener const * const lst = &tp->m_entity.m_listener; @@ -101,191 +98,136 @@ static void dds_topic_status_cb (struct dds_topic *tp) if (lst->on_inconsistent_topic) { ddsrt_mutex_unlock (&tp->m_entity.m_observers_lock); - dds_entity_invoke_listener(&tp->m_entity, DDS_INCONSISTENT_TOPIC_STATUS_ID, &tp->m_inconsistent_topic_status); + dds_entity_invoke_listener (&tp->m_entity, DDS_INCONSISTENT_TOPIC_STATUS_ID, &tp->m_inconsistent_topic_status); ddsrt_mutex_lock (&tp->m_entity.m_observers_lock); tp->m_inconsistent_topic_status.total_count_change = 0; } - dds_entity_status_set(&tp->m_entity, DDS_INCONSISTENT_TOPIC_STATUS); + dds_entity_status_set (&tp->m_entity, DDS_INCONSISTENT_TOPIC_STATUS); tp->m_entity.m_cb_count--; ddsrt_cond_broadcast (&tp->m_entity.m_observers_cond); ddsrt_mutex_unlock (&tp->m_entity.m_observers_lock); } +#endif -struct ddsi_sertopic * -dds_topic_lookup_locked( - dds_domain *domain, - const char *name) +struct ddsi_sertopic *dds_topic_lookup (dds_domain *domain, const char *name) { - struct ddsi_sertopic *st = NULL; - ddsrt_avl_iter_t iter; - - assert (domain); - assert (name); - - st = ddsrt_avl_iter_first (&dds_topictree_def, &domain->m_topics, &iter); - while (st) { - if (strcmp (st->name, name) == 0) { - break; - } - st = ddsrt_avl_iter_next (&iter); - } - return st; + const struct ddsi_sertopic key = { .name = (char *) name }; + struct ddsi_sertopic *st; + struct topic_sertopic_node *nst; + ddsrt_mutex_lock (&dds_global.m_mutex); + if ((nst = ddsrt_avl_lookup (&dds_topictree_def, &domain->m_topics, &key)) == NULL) + st = NULL; + else + st = ddsi_sertopic_ref (nst->st); + ddsrt_mutex_unlock (&dds_global.m_mutex); + return st; } -struct ddsi_sertopic * -dds_topic_lookup( - dds_domain *domain, - const char *name) +static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_entity_t topic, const char *name) { - struct ddsi_sertopic *st; - ddsrt_mutex_lock (&dds_global.m_mutex); - st = dds_topic_lookup_locked(domain, name); - ddsrt_mutex_unlock (&dds_global.m_mutex); - return st; + dds_topic *tp; + if (dds_topic_lock (topic, &tp) != DDS_RETCODE_OK) + return false; + + bool ret; + if (tp->m_entity.m_participant->m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0) + ret = false; + else + { + /* FIXME: calling addref is wrong because the Cyclone library has no + knowledge of the reference and hence simply deleting the participant + won't make the ref count drop to 0. On the other hand, the DDS spec + says find_topic (and a second call to create_topic) return a new + proxy that must separately be deleted. */ + dds_entity_add_ref_locked (&tp->m_entity); + ret = true; + } + dds_topic_unlock (tp); + return ret; } -void -dds_topic_free( - dds_domainid_t domainid, - struct ddsi_sertopic *st) +dds_entity_t dds_find_topic (dds_entity_t participant, const char *name) { - dds_domain *domain; + dds_entity *pe; + dds_return_t ret; + dds_entity_t topic; - assert (st); + if (name == NULL) + return DDS_RETCODE_BAD_PARAMETER; - ddsrt_mutex_lock (&dds_global.m_mutex); - domain = ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &domainid); - if (domain != NULL) { - ddsrt_avl_delete (&dds_topictree_def, &domain->m_topics, st); - } - ddsrt_mutex_unlock (&dds_global.m_mutex); - st->status_cb_entity = NULL; - ddsi_sertopic_unref (st); -} - -static void -dds_topic_add_locked( - dds_domainid_t id, - struct ddsi_sertopic *st) -{ - dds_domain * dom; - dom = dds_domain_find_locked (id); - assert (dom); - ddsrt_avl_insert (&dds_topictree_def, &dom->m_topics, st); -} - -DDS_EXPORT dds_entity_t -dds_find_topic( - dds_entity_t participant, - const char *name) -{ - dds_entity_t tp; - dds_entity *p = NULL; - struct ddsi_sertopic *st; - dds_retcode_t rc; - - if (name) { - rc = dds_entity_lock(participant, DDS_KIND_PARTICIPANT, &p); - if (rc == DDS_RETCODE_OK) { - ddsrt_mutex_lock (&dds_global.m_mutex); - st = dds_topic_lookup_locked (p->m_domain, name); - if (st) { - /* FIXME: calling addref is wrong because the Cyclone library has no - knowledge of the reference and hence simply deleting the participant - won't make the ref count drop to 0. On the other hand, the DDS spec - says find_topic (and a second call to create_topic) return a new - proxy that must separately be deleted. */ - dds_entity_add_ref (&st->status_cb_entity->m_entity); - tp = st->status_cb_entity->m_entity.m_hdllink.hdl; - } else { - DDS_ERROR("Topic is not being created yet\n"); - tp = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - } - ddsrt_mutex_unlock (&dds_global.m_mutex); - dds_entity_unlock(p); - } else { - tp = DDS_ERRNO(rc); - } - } else { - DDS_ERROR("Argument name is not valid\n"); - tp = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - - return tp; -} - -static dds_return_t -dds_topic_delete( - dds_entity *e) -{ - dds_topic_free(e->m_domainid, ((dds_topic*) e)->m_stopic); - return DDS_RETCODE_OK; -} - -static dds_return_t -dds_topic_qos_validate( - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = DDS_RETCODE_OK; - assert(qos); - - /* Check consistency. */ - if (!dds_qos_validate_common(qos)) { - DDS_ERROR("Argument QoS is not valid\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - if ((qos->present & QP_GROUP_DATA) && !validate_octetseq (&qos->group_data)) { - DDS_ERROR("Group data QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_DURABILITY_SERVICE) && (validate_durability_service_qospolicy(&qos->durability_service) != 0)) { - DDS_ERROR("Durability service QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_LIFESPAN) && (validate_duration(&qos->lifespan.duration) != 0)) { - DDS_ERROR("Lifespan QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if (qos->present & QP_HISTORY && (qos->present & QP_RESOURCE_LIMITS) && (validate_history_and_resource_limits(&qos->history, &qos->resource_limits) != 0)) { - DDS_ERROR("Lifespan QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if(ret == DDS_RETCODE_OK && enabled){ - ret = dds_qos_validate_mutable_common(qos); - } + /* claim participant handle to guarantee the handle remains valid after + unlocking the participant prior to verifying the found topic still + exists */ + if ((ret = dds_entity_pin (participant, &pe)) < 0) return ret; -} + if (dds_entity_kind (pe) != DDS_KIND_PARTICIPANT) + { + dds_entity_unpin (pe); + return DDS_RETCODE_ILLEGAL_OPERATION; + } - -static dds_return_t -dds_topic_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = dds_topic_qos_validate(qos, enabled); - (void)e; - if (ret == DDS_RETCODE_OK) { - if (enabled) { - /* TODO: CHAM-95: DDSI does not support changing QoS policies. */ - DDS_ERROR("Changing the topic QoS is not supported\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); + do { + dds_participant *p; + topic = DDS_RETCODE_PRECONDITION_NOT_MET; + if ((ret = dds_participant_lock (participant, &p)) == DDS_RETCODE_OK) + { + ddsrt_avl_iter_t it; + for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &p->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it)) + { + if (dds_entity_kind (e) == DDS_KIND_TOPIC && strcmp (((dds_topic *) e)->m_stopic->name, name) == 0) + { + topic = e->m_hdllink.hdl; + break; } + } + dds_participant_unlock (p); } - return ret; + } while (topic > 0 && !dds_find_topic_check_and_add_ref (participant, topic, name)); + + dds_entity_unpin (pe); + return topic; } -static bool dupdef_qos_ok(const dds_qos_t *qos, const struct ddsi_sertopic *st) +static dds_return_t dds_topic_delete (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_topic_delete (dds_entity *e) { - if ((qos == NULL) != (st->status_cb_entity->m_entity.m_qos == NULL)) { - return false; - } else if (qos == NULL) { - return true; - } else { - return dds_qos_equal(st->status_cb_entity->m_entity.m_qos, qos); - } + dds_topic *tp = (dds_topic *) e; + dds_domain *domain = tp->m_entity.m_domain; + ddsrt_avl_dpath_t dp; + struct topic_sertopic_node *stn; + + ddsrt_mutex_lock (&dds_global.m_mutex); + + stn = ddsrt_avl_lookup_dpath (&dds_topictree_def, &domain->m_topics, tp->m_stopic, &dp); + assert (stn != NULL); + if (--stn->refc == 0) + { + ddsrt_avl_delete_dpath (&dds_topictree_def, &domain->m_topics, stn, &dp); + ddsrt_free (stn); + } + + ddsi_sertopic_unref (tp->m_stopic); + ddsrt_mutex_unlock (&dds_global.m_mutex); + return DDS_RETCODE_OK; +} + +static dds_return_t dds_topic_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) +{ + /* note: e->m_qos is still the old one to allow for failure here */ + (void) e; (void) qos; (void) enabled; + return DDS_RETCODE_OK; +} + +static bool dupdef_qos_ok (const dds_qos_t *qos, const dds_topic *tp) +{ + if ((qos == NULL) != (tp->m_entity.m_qos == NULL)) + return false; + else if (qos == NULL) + return true; + else + return dds_qos_equal (tp->m_entity.m_qos, qos); } static bool sertopic_equivalent (const struct ddsi_sertopic *a, const struct ddsi_sertopic *b) @@ -301,276 +243,329 @@ static bool sertopic_equivalent (const struct ddsi_sertopic *a, const struct dds return true; } -DDS_EXPORT dds_entity_t -dds_create_topic_arbitrary ( - dds_entity_t participant, - struct ddsi_sertopic *sertopic, - const dds_qos_t *qos, - const dds_listener_t *listener, - const nn_plist_t *sedp_plist) +static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos) { - struct ddsi_sertopic *stgeneric; - dds_retcode_t rc; - dds_entity *par; - dds_topic *top; - dds_qos_t *new_qos = NULL; - dds_entity_t hdl; - struct participant *ddsi_pp; + dds_topic *tp; + dds_return_t ret; - if (sertopic == NULL){ - DDS_ERROR("Topic description is NULL\n"); - hdl = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto bad_param_err; + if (dds_topic_lock (topic, &tp) < 0) + return DDS_RETCODE_NOT_FOUND; + + if (tp->m_entity.m_participant->m_hdllink.hdl != participant) + ret = DDS_RETCODE_NOT_FOUND; + else if (!sertopic_equivalent (tp->m_stopic, sertopic)) + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + else if (!dupdef_qos_ok (qos, tp)) + ret = DDS_RETCODE_INCONSISTENT_POLICY; + else + { + /* FIXME: calling addref is wrong because the Cyclone library has no + knowledge of the reference and hence simply deleting the participant + won't make the ref count drop to 0. On the other hand, the DDS spec + says find_topic (and a second call to create_topic) return a new + proxy that must separately be deleted. */ + dds_entity_add_ref_locked (&tp->m_entity); + ret = DDS_RETCODE_OK; + } + dds_topic_unlock (tp); + return ret; +} + +const struct dds_entity_deriver dds_entity_deriver_topic = { + .close = dds_entity_deriver_dummy_close, + .delete = dds_topic_delete, + .set_qos = dds_topic_qos_set, + .validate_status = dds_topic_status_validate +}; + +dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const nn_plist_t *sedp_plist) +{ + dds_return_t rc; + dds_participant *par; + dds_entity *par_ent; + dds_topic *top; + dds_qos_t *new_qos = NULL; + dds_entity_t hdl; + struct participant *ddsi_pp; + + if (sertopic == NULL) + return DDS_RETCODE_BAD_PARAMETER; + + /* Claim participant handle so we can be sure the handle will not be + reused if we temporarily unlock the participant to check the an + existing topic's compatibility */ + if ((rc = dds_entity_pin (participant, &par_ent)) < 0) + return rc; + + new_qos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (new_qos, qos, DDS_TOPIC_QOS_MASK); + /* One would expect this: + * + * nn_xqos_mergein_missing (new_qos, &gv.default_xqos_tp, ~(uint64_t)0); + * + * but the crazy defaults of the DDS specification has a default settings + * for reliability that are dependent on the entity type: readers and + * topics default to best-effort, but writers to reliable. + * + * Leaving the topic QoS sparse means a default-default topic QoS of + * best-effort will do "the right thing" and let a writer still default to + * reliable ... (and keep behaviour unchanged) */ + if ((rc = nn_xqos_valid (&par_ent->m_domain->gv.logconfig, new_qos)) != DDS_RETCODE_OK) + goto err_invalid_qos; + + /* FIXME: just mutex_lock ought to be good enough, but there is the + pesky "closed" check still ... */ + if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) + goto err_lock_participant; + + bool retry_lookup; + do { + dds_entity_t topic; + + /* claim participant handle to guarantee the handle remains valid after + unlocking the participant prior to verifying the found topic still + exists */ + topic = DDS_RETCODE_PRECONDITION_NOT_MET; + ddsrt_avl_iter_t it; + for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &par->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it)) + { + if (dds_entity_kind (e) == DDS_KIND_TOPIC && strcmp (((dds_topic *) e)->m_stopic->name, sertopic->name) == 0) + { + topic = e->m_hdllink.hdl; + break; + } } - - rc = dds_entity_lock(participant, DDS_KIND_PARTICIPANT, &par); - if (rc != DDS_RETCODE_OK) { - hdl = DDS_ERRNO(rc); - goto lock_err; + if (topic < 0) + { + /* no topic with the name exists; we have locked the participant, and + so we can proceed with creating the topic */ + retry_lookup = false; } + else + { + /* some topic with the same name exists; need to lock the topic to + perform the checks, but locking the topic while holding the + participant lock violates the lock order (child -> parent). So + unlock that participant and check the topic while accounting + for the various scary cases. */ + dds_participant_unlock (par); - /* Validate qos */ - if (qos) { - hdl = dds_topic_qos_validate (qos, false); - if (hdl != DDS_RETCODE_OK) { - goto qos_err; - } + rc = create_topic_topic_arbirary_check_sertopic (participant, topic, sertopic, new_qos); + switch (rc) + { + case DDS_RETCODE_OK: /* duplicate definition */ + dds_entity_unpin (par_ent); + dds_delete_qos (new_qos); + return topic; + + case DDS_RETCODE_NOT_FOUND: + /* either participant is now being deleted, topic was deleted, or + topic was deleted & the handle reused for something else -- so */ + retry_lookup = true; + break; + + case DDS_RETCODE_PRECONDITION_NOT_MET: /* incompatible sertopic */ + case DDS_RETCODE_INCONSISTENT_POLICY: /* different QoS */ + /* inconsistent definition */ + dds_entity_unpin (par_ent); + dds_delete_qos (new_qos); + return rc; + + default: + abort (); + } + + if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) + goto err_lock_participant; } + } while (retry_lookup); - /* FIXME: I find it weird that qos may be NULL in the entity */ + /* FIXME: make this a function + Add sertopic to domain -- but note that it may have been created by another thread + on another participant that is attached to the same domain */ + { + struct dds_domain *domain = par->m_entity.m_domain; + + ddsrt_avl_ipath_t ip; + struct topic_sertopic_node *stn; - /* Check if topic already exists with same name */ ddsrt_mutex_lock (&dds_global.m_mutex); - if ((stgeneric = dds_topic_lookup_locked (par->m_domain, sertopic->name)) != NULL) { - if (!sertopic_equivalent (stgeneric, sertopic)) { - /* FIXME: should copy the type, perhaps? but then the pointers will no longer be the same */ - DDS_ERROR("Create topic with mismatching type\n"); - hdl = DDS_ERRNO(DDS_RETCODE_PRECONDITION_NOT_MET); - } else if (!dupdef_qos_ok(qos, stgeneric)) { - /* FIXME: should copy the type, perhaps? but then the pointers will no longer be the same */ - DDS_ERROR("Create topic with mismatching qos\n"); - hdl = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } else { - /* FIXME: calling addref is wrong because the Cyclone library has no - knowledge of the reference and hence simply deleting the participant - won't make the ref count drop to 0. On the other hand, the DDS spec - says find_topic (and a second call to create_topic) return a new - proxy that must separately be deleted. */ - dds_entity_add_ref (&stgeneric->status_cb_entity->m_entity); - hdl = stgeneric->status_cb_entity->m_entity.m_hdllink.hdl; - } - ddsrt_mutex_unlock (&dds_global.m_mutex); - } else { - if (qos) { - new_qos = dds_create_qos(); - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(new_qos, qos); - } - /* Create topic */ - top = dds_alloc (sizeof (*top)); - hdl = dds_entity_init (&top->m_entity, par, DDS_KIND_TOPIC, new_qos, listener, DDS_TOPIC_STATUS_MASK); - top->m_entity.m_deriver.delete = dds_topic_delete; - top->m_entity.m_deriver.set_qos = dds_topic_qos_set; - top->m_entity.m_deriver.validate_status = dds_topic_status_validate; - top->m_stopic = ddsi_sertopic_ref (sertopic); - sertopic->status_cb_entity = top; - - /* Add topic to extent */ - dds_topic_add_locked (par->m_domainid, sertopic); - ddsrt_mutex_unlock (&dds_global.m_mutex); - - /* Publish Topic */ - thread_state_awake (lookup_thread_state ()); - ddsi_pp = ephash_lookup_participant_guid (&par->m_guid); - assert (ddsi_pp); - if (sedp_plist) { - sedp_write_topic (ddsi_pp, sedp_plist); - } - thread_state_asleep (lookup_thread_state ()); + stn = ddsrt_avl_lookup_ipath (&dds_topictree_def, &domain->m_topics, sertopic, &ip); + if (stn == NULL) + { + /* no existing definition: use new */ + stn = ddsrt_malloc (sizeof (*stn)); + stn->refc = 1; + stn->st = ddsi_sertopic_ref (sertopic); + ddsrt_avl_insert (&dds_topictree_def, &domain->m_topics, stn); + ddsrt_mutex_unlock (&dds_global.m_mutex); } + else if (sertopic_equivalent (stn->st, sertopic)) + { + /* ok -- same definition, so use existing one instead */ + sertopic = ddsi_sertopic_ref (stn->st); + stn->refc++; + ddsrt_mutex_unlock (&dds_global.m_mutex); + } + else + { + /* bummer, delete */ + ddsrt_mutex_unlock (&dds_global.m_mutex); + rc = DDS_RETCODE_PRECONDITION_NOT_MET; + goto err_sertopic_reuse; + } + } -qos_err: - dds_entity_unlock(par); -lock_err: -bad_param_err: - return hdl; -} + /* Create topic */ + top = dds_alloc (sizeof (*top)); + hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, new_qos, listener, DDS_TOPIC_STATUS_MASK); + top->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&par->m_entity, &top->m_entity); + top->m_stopic = sertopic; -DDS_EXPORT dds_entity_t -dds_create_topic( - dds_entity_t participant, - const dds_topic_descriptor_t *desc, - const char *name, - const dds_qos_t *qos, - const dds_listener_t *listener) -{ - char *key = NULL; - struct ddsi_sertopic_default *st; - const char *typename; - dds_qos_t *new_qos = NULL; + /* Publish Topic */ + thread_state_awake (lookup_thread_state (), &par->m_entity.m_domain->gv); + ddsi_pp = ephash_lookup_participant_guid (par->m_entity.m_domain->gv.guid_hash, &par->m_entity.m_guid); + assert (ddsi_pp); + if (sedp_plist) + { nn_plist_t plist; - dds_entity_t hdl; - uint32_t index; - size_t keysz; - - if (desc == NULL){ - DDS_ERROR("Topic description is NULL"); - hdl = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto bad_param_err; - } - - if (name == NULL) { - DDS_ERROR("Topic name is NULL"); - hdl = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto bad_param_err; - } - - if (!is_valid_name(name)) { - DDS_ERROR("Topic name contains characters that are not allowed."); - hdl = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto bad_param_err; - } - - typename = desc->m_typename; - keysz = strlen (name) + strlen (typename) + 2; - key = (char*) dds_alloc (keysz); - (void) snprintf(key, keysz, "%s/%s", name, typename); - - st = dds_alloc (sizeof (*st)); - - ddsrt_atomic_st32 (&st->c.refc, 1); - st->c.iid = ddsi_iid_gen (); - st->c.status_cb = dds_topic_status_cb; - st->c.status_cb_entity = NULL; /* set by dds_create_topic_arbitrary */ - st->c.name_type_name = key; - st->c.name = dds_string_dup (name); - st->c.type_name = dds_string_dup (typename); - st->c.ops = &ddsi_sertopic_ops_default; - st->c.serdata_ops = desc->m_nkeys ? &ddsi_serdata_ops_cdr : &ddsi_serdata_ops_cdr_nokey; - st->c.serdata_basehash = ddsi_sertopic_compute_serdata_basehash (st->c.serdata_ops); - st->native_encoding_identifier = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE); - - st->type = (void*) desc; - st->nkeys = desc->m_nkeys; - st->keys = desc->m_keys; - - /* Check if topic cannot be optimised (memcpy marshal) */ - if ((desc->m_flagset & DDS_TOPIC_NO_OPTIMIZE) == 0) { - st->opt_size = dds_stream_check_optimize (desc); - } - nn_plist_init_empty (&plist); - if (new_qos) { - dds_merge_qos (&plist.qos, new_qos); - } - - /* Set Topic meta data (for SEDP publication) */ - plist.qos.topic_name = dds_string_dup (st->c.name); - plist.qos.type_name = dds_string_dup (st->c.type_name); - plist.qos.present |= (QP_TOPIC_NAME | QP_TYPE_NAME); - if (desc->m_meta) { - plist.type_description = dds_string_dup (desc->m_meta); - plist.present |= PP_PRISMTECH_TYPE_DESCRIPTION; - } - if (desc->m_nkeys) { - plist.qos.present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; - plist.qos.subscription_keys.use_key_list = 1; - plist.qos.subscription_keys.key_list.n = desc->m_nkeys; - plist.qos.subscription_keys.key_list.strs = dds_alloc (desc->m_nkeys * sizeof (char*)); - for (index = 0; index < desc->m_nkeys; index++) { - plist.qos.subscription_keys.key_list.strs[index] = dds_string_dup (desc->m_keys[index].m_name); - } - } - - hdl = dds_create_topic_arbitrary(participant, &st->c, qos, listener, &plist); - ddsi_sertopic_unref (&st->c); + nn_plist_mergein_missing (&plist, sedp_plist, ~(uint64_t)0, ~(uint64_t)0); + nn_xqos_mergein_missing (&plist.qos, new_qos, ~(uint64_t)0); + sedp_write_topic (ddsi_pp, &plist); nn_plist_fini (&plist); + } + thread_state_asleep (lookup_thread_state ()); + dds_participant_unlock (par); + dds_entity_unpin (par_ent); + return hdl; -bad_param_err: - return hdl; +err_sertopic_reuse: + dds_participant_unlock (par); +err_lock_participant: +err_invalid_qos: + dds_delete_qos (new_qos); + dds_entity_unpin (par_ent); + return rc; } -static bool -dds_topic_chaining_filter( - const void *sample, - void *ctx) +dds_entity_t dds_create_topic (dds_entity_t participant, const dds_topic_descriptor_t *desc, const char *name, const dds_qos_t *qos, const dds_listener_t *listener) { - dds_topic_filter_fn realf = (dds_topic_filter_fn)ctx; - return realf (sample); + struct ddsi_sertopic_default *st; + nn_plist_t plist; + dds_entity_t hdl; + struct dds_entity *ppent; + dds_return_t ret; + + if (desc == NULL || name == NULL || !is_valid_name (name)) + return DDS_RETCODE_BAD_PARAMETER; + + if ((ret = dds_entity_pin (participant, &ppent)) < 0) + return ret; + + st = dds_alloc (sizeof (*st)); + + ddsi_sertopic_init (&st->c, name, desc->m_typename, &ddsi_sertopic_ops_default, desc->m_nkeys ? &ddsi_serdata_ops_cdr : &ddsi_serdata_ops_cdr_nokey, (desc->m_nkeys == 0)); + st->native_encoding_identifier = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE); + st->serpool = ppent->m_domain->gv.serpool; + st->type = (void*) desc; + st->nkeys = desc->m_nkeys; + st->keys = desc->m_keys; + + /* Check if topic cannot be optimised (memcpy marshal) */ + if (!(desc->m_flagset & DDS_TOPIC_NO_OPTIMIZE)) { + st->opt_size = dds_stream_check_optimize (desc); + DDS_CTRACE (&ppent->m_domain->gv.logconfig, "Marshalling for type: %s is %soptimised\n", desc->m_typename, st->opt_size ? "" : "not "); + } + + nn_plist_init_empty (&plist); + /* Set Topic meta data (for SEDP publication) */ + plist.qos.topic_name = ddsrt_strdup (st->c.name); + plist.qos.type_name = ddsrt_strdup (st->c.type_name); + plist.qos.present |= (QP_TOPIC_NAME | QP_TYPE_NAME); + if (desc->m_meta) + { + plist.type_description = dds_string_dup (desc->m_meta); + plist.present |= PP_PRISMTECH_TYPE_DESCRIPTION; + } + if (desc->m_nkeys) + { + plist.qos.present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; + plist.qos.subscription_keys.use_key_list = 1; + plist.qos.subscription_keys.key_list.n = desc->m_nkeys; + plist.qos.subscription_keys.key_list.strs = dds_alloc (desc->m_nkeys * sizeof (char*)); + for (uint32_t index = 0; index < desc->m_nkeys; index++) + plist.qos.subscription_keys.key_list.strs[index] = dds_string_dup (desc->m_keys[index].m_name); + } + + hdl = dds_create_topic_arbitrary (participant, &st->c, qos, listener, &plist); + ddsi_sertopic_unref (&st->c); + dds_entity_unpin (ppent); + nn_plist_fini (&plist); + return hdl; } -static void -dds_topic_mod_filter( - dds_entity_t topic, - dds_topic_intern_filter_fn *filter, - void **ctx, - bool set) +static bool dds_topic_chaining_filter (const void *sample, void *ctx) { - dds_topic *t; - if (dds_topic_lock(topic, &t) == DDS_RETCODE_OK) { - if (set) { - t->filter_fn = *filter; - t->filter_ctx = *ctx; - } else { - *filter = t->filter_fn; - *ctx = t->filter_ctx; - } - dds_topic_unlock(t); + dds_topic_filter_fn realf = (dds_topic_filter_fn) ctx; + return realf (sample); +} + +static void dds_topic_mod_filter (dds_entity_t topic, dds_topic_intern_filter_fn *filter, void **ctx, bool set) +{ + dds_topic *t; + if (dds_topic_lock (topic, &t) == DDS_RETCODE_OK) + { + if (set) { + t->filter_fn = *filter; + t->filter_ctx = *ctx; } else { - *filter = 0; - *ctx = NULL; + *filter = t->filter_fn; + *ctx = t->filter_ctx; } + dds_topic_unlock (t); + } + else + { + *filter = 0; + *ctx = NULL; + } } -void -dds_set_topic_filter( - dds_entity_t topic, - dds_topic_filter_fn filter) +void dds_set_topic_filter (dds_entity_t topic, dds_topic_filter_fn filter) { - dds_topic_intern_filter_fn chaining = dds_topic_chaining_filter; - void *realf = (void *)filter; - dds_topic_mod_filter (topic, &chaining, &realf, true); + dds_topic_intern_filter_fn chaining = dds_topic_chaining_filter; + void *realf = (void *) filter; + dds_topic_mod_filter (topic, &chaining, &realf, true); } -void -dds_topic_set_filter( - dds_entity_t topic, - dds_topic_filter_fn filter) +void dds_topic_set_filter (dds_entity_t topic, dds_topic_filter_fn filter) { - dds_set_topic_filter(topic, filter); + dds_set_topic_filter (topic, filter); } -dds_topic_filter_fn -dds_get_topic_filter( - dds_entity_t topic) +dds_topic_filter_fn dds_get_topic_filter (dds_entity_t topic) { - dds_topic_intern_filter_fn filter; - void *ctx; - dds_topic_mod_filter (topic, &filter, &ctx, false); - return (filter == dds_topic_chaining_filter) ? (dds_topic_filter_fn)ctx : 0; + dds_topic_intern_filter_fn filter; + void *ctx; + dds_topic_mod_filter (topic, &filter, &ctx, false); + return (filter == dds_topic_chaining_filter) ? (dds_topic_filter_fn) ctx : 0; } -dds_topic_filter_fn -dds_topic_get_filter( - dds_entity_t topic) +dds_topic_filter_fn dds_topic_get_filter (dds_entity_t topic) { - return dds_get_topic_filter(topic); + return dds_get_topic_filter (topic); } -void -dds_topic_set_filter_with_ctx( - dds_entity_t topic, - dds_topic_intern_filter_fn filter, - void *ctx) +void dds_topic_set_filter_with_ctx (dds_entity_t topic, dds_topic_intern_filter_fn filter, void *ctx) { dds_topic_mod_filter (topic, &filter, &ctx, true); } -dds_topic_intern_filter_fn -dds_topic_get_filter_with_ctx( - dds_entity_t topic) +dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx (dds_entity_t topic) { dds_topic_intern_filter_fn filter; void *ctx; @@ -578,101 +573,32 @@ dds_topic_get_filter_with_ctx( return (filter == dds_topic_chaining_filter) ? 0 : filter; } -DDS_EXPORT dds_return_t -dds_get_name( - dds_entity_t topic, - char *name, - size_t size) +dds_return_t dds_get_name (dds_entity_t topic, char *name, size_t size) { - dds_topic *t; - dds_return_t ret; - dds_retcode_t rc; - - if(size <= 0){ - DDS_ERROR("Argument size is smaller than 0\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if(name == NULL){ - DDS_ERROR("Argument name is NULL\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - name[0] = '\0'; - rc = dds_topic_lock(topic, &t); - if (rc == DDS_RETCODE_OK) { - (void)snprintf(name, size, "%s", t->m_stopic->name); - dds_topic_unlock(t); - ret = DDS_RETCODE_OK; - } else { - DDS_ERROR("Error occurred on locking topic\n"); - ret = DDS_ERRNO(rc); - goto fail; - } -fail: + dds_topic *t; + dds_return_t ret; + if (size <= 0 || name == NULL) + return DDS_RETCODE_BAD_PARAMETER; + name[0] = '\0'; + if ((ret = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) return ret; + (void) snprintf (name, size, "%s", t->m_stopic->name); + dds_topic_unlock (t); + return DDS_RETCODE_OK; } -DDS_EXPORT dds_return_t -dds_get_type_name( - dds_entity_t topic, - char *name, - size_t size) +dds_return_t dds_get_type_name (dds_entity_t topic, char *name, size_t size) { - dds_topic *t; - dds_retcode_t rc; - dds_return_t ret; - - if(size <= 0){ - DDS_ERROR("Argument size is smaller than 0\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - if(name == NULL){ - DDS_ERROR("Argument name is NULL\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - goto fail; - } - name[0] = '\0'; - rc = dds_topic_lock(topic, &t); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking topic\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - (void)snprintf(name, size, "%s", t->m_stopic->type_name); - dds_topic_unlock(t); - ret = DDS_RETCODE_OK; -fail: + dds_topic *t; + dds_return_t ret; + if (size <= 0 || name == NULL) + return DDS_RETCODE_BAD_PARAMETER; + name[0] = '\0'; + if ((ret = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) return ret; + (void) snprintf (name, size, "%s", t->m_stopic->type_name); + dds_topic_unlock (t); + return DDS_RETCODE_OK; } -dds_return_t -dds_get_inconsistent_topic_status( - dds_entity_t topic, - dds_inconsistent_topic_status_t *status) -{ - dds_retcode_t rc; - dds_topic *t; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_topic_lock(topic, &t); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking topic\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = t->m_inconsistent_topic_status; - } - ddsrt_mutex_lock (&t->m_entity.m_observers_lock); - if (t->m_entity.m_status_enable & DDS_INCONSISTENT_TOPIC_STATUS) { - t->m_inconsistent_topic_status.total_count_change = 0; - dds_entity_status_reset(&t->m_entity, DDS_INCONSISTENT_TOPIC_STATUS); - } - ddsrt_mutex_unlock (&t->m_entity.m_observers_lock); - dds_topic_unlock(t); -fail: - return ret; -} +DDS_GET_STATUS(topic, inconsistent_topic, INCONSISTENT_TOPIC, total_count_change) diff --git a/src/core/ddsc/src/dds_waitset.c b/src/core/ddsc/src/dds_waitset.c index 4d5bd4b..1305979 100644 --- a/src/core/ddsc/src/dds_waitset.c +++ b/src/core/ddsc/src/dds_waitset.c @@ -14,458 +14,304 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds__entity.h" +#include "dds__participant.h" #include "dds__querycond.h" #include "dds__readcond.h" #include "dds__rhc.h" -#include "dds__err.h" +#include "dds/ddsi/ddsi_iid.h" -DEFINE_ENTITY_LOCK_UNLOCK(static, dds_waitset, DDS_KIND_WAITSET) +DEFINE_ENTITY_LOCK_UNLOCK (static, dds_waitset, DDS_KIND_WAITSET) -static void -dds_waitset_swap( - dds_attachment **dst, - dds_attachment **src, - dds_attachment *prev, - dds_attachment *idx) +static bool is_triggered (struct dds_entity *e) { - /* Remove from source. */ - if (prev == NULL) { - *src = idx->next; - } else { - prev->next = idx->next; - } - - /* Add to destination. */ - idx->next = *dst; - *dst = idx; + bool t; + switch (e->m_kind) + { + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + case DDS_KIND_COND_GUARD: + case DDS_KIND_WAITSET: + t = ddsrt_atomic_ld32 (&e->m_status.m_trigger) != 0; + break; + default: + t = (ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & SAM_STATUS_MASK) != 0; + break; + } + return t; } -static dds_return_t -dds_waitset_wait_impl( - dds_entity_t waitset, - dds_attach_t *xs, - size_t nxs, - dds_time_t abstimeout, - dds_time_t tnow) +static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_time_t abstimeout) { - dds_waitset *ws; - dds_return_t ret; - dds_retcode_t rc; - dds_attachment *idx; - dds_attachment *next; - dds_attachment *prev; + dds_waitset *ws; + dds_return_t ret; - if ((xs == NULL) && (nxs != 0)){ - DDS_ERROR("A size was given, but no array\n"); - return DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); + if ((xs == NULL) != (nxs == 0)) + return DDS_RETCODE_BAD_PARAMETER; + + /* Locking the waitset here will delay a possible deletion until it is + * unlocked. Even when the related mutex is unlocked by a conditioned wait. */ + { + dds_entity *ent; + if ((ret = dds_entity_pin (waitset, &ent)) != DDS_RETCODE_OK) + return ret; + if (dds_entity_kind (ent) != DDS_KIND_WAITSET) + { + dds_entity_unpin (ent); + return DDS_RETCODE_ILLEGAL_OPERATION; } - if ((xs != NULL) && (nxs == 0)){ - DDS_ERROR("Array is given with an invalid size\n"); - return DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); + ws = (dds_waitset *) ent; + } + + /* Move any previously but no longer triggering entities back to the observed list */ + ddsrt_mutex_lock (&ws->m_entity.m_mutex); + ws->ntriggered = 0; + for (size_t i = 0; i < ws->nentities; i++) + { + if (is_triggered (ws->entities[i].entity)) + { + dds_attachment tmp = ws->entities[i]; + ws->entities[i] = ws->entities[ws->ntriggered]; + ws->entities[ws->ntriggered++] = tmp; } + } - /* Locking the waitset here will delay a possible deletion until it is - * unlocked. Even when the related mutex is unlocked by a conditioned wait. */ - rc = dds_waitset_lock(waitset, &ws); - if (rc == DDS_RETCODE_OK) { - /* Check if any of any previous triggered entities has changed there status - * and thus it trigger value could be false now. */ - idx = ws->triggered; - prev = NULL; - while (idx != NULL) { - next = idx->next; - if (idx->entity->m_trigger == 0) { - /* Move observed entity to triggered list. */ - dds_waitset_swap(&(ws->observed), &(ws->triggered), prev, idx); - } else { - prev = idx; - } - idx = next; - } - /* Check if any of the entities have been triggered. */ - idx = ws->observed; - prev = NULL; - while (idx != NULL) { - next = idx->next; - if (idx->entity->m_trigger > 0) { - /* Move observed entity to triggered list. */ - dds_waitset_swap(&(ws->triggered), &(ws->observed), prev, idx); - } else { - prev = idx; - } - idx = next; - } + /* Only wait/keep waiting when we have something to observe and there aren't any triggers yet. */ + while (ws->nentities > 0 && ws->ntriggered == 0) + if (!ddsrt_cond_waituntil (&ws->m_entity.m_cond, &ws->m_entity.m_mutex, abstimeout)) + break; - /* Only wait/keep waiting when whe have something to observer and there aren't any triggers yet. */ - rc = DDS_RETCODE_OK; - while ((ws->observed != NULL) && (ws->triggered == NULL) && (rc == DDS_RETCODE_OK)) { - if (abstimeout == DDS_NEVER) { - ddsrt_cond_wait(&ws->m_entity.m_cond, &ws->m_entity.m_mutex); - } else if (abstimeout <= tnow) { - rc = DDS_RETCODE_TIMEOUT; - } else { - dds_duration_t dt = abstimeout - tnow; - (void)ddsrt_cond_waitfor(&ws->m_entity.m_cond, &ws->m_entity.m_mutex, dt); - tnow = dds_time(); - } - } + ret = (int32_t) ws->ntriggered; + for (size_t i = 0; i < ws->ntriggered && i < nxs; i++) + xs[i] = ws->entities[i].arg; + ddsrt_mutex_unlock (&ws->m_entity.m_mutex); + dds_entity_unpin (&ws->m_entity); + return ret; +} - /* Get number of triggered entities - * - set attach array when needed - * - swap them back to observed */ - if (rc == DDS_RETCODE_OK) { - ret = 0; - idx = ws->triggered; - while (idx != NULL) { - if ((uint32_t)ret < (uint32_t)nxs) { - xs[ret] = idx->arg; - } - ret++; +static dds_return_t dds_waitset_close (struct dds_entity *e) +{ + /* deep in the process of deleting the entity, so this is the only thread */ + dds_waitset *ws = (dds_waitset *) e; + for (size_t i = 0; i < ws->nentities; i++) + (void) dds_entity_observer_unregister (ws->entities[i].entity, &ws->m_entity); + return DDS_RETCODE_OK; +} - next = idx->next; - /* The idx is always the first in triggered, so no prev. */ - dds_waitset_swap(&(ws->observed), &(ws->triggered), NULL, idx); - idx = next; - } - } else if (rc == DDS_RETCODE_TIMEOUT) { - ret = 0; - } else { - DDS_ERROR("Internal error"); - ret = DDS_ERRNO(rc); - } +static dds_return_t dds_waitset_delete (struct dds_entity *e) +{ + /* deep in the process of deleting the entity, so this is the only thread */ + dds_waitset *ws = (dds_waitset *) e; + ddsrt_free (ws->entities); + return DDS_RETCODE_OK; +} - dds_waitset_unlock(ws); - } else { - DDS_ERROR("Error occurred on locking waitset\n"); - ret = DDS_ERRNO(rc); - } +const struct dds_entity_deriver dds_entity_deriver_waitset = { + .close = dds_waitset_close, + .delete = dds_waitset_delete, + .set_qos = dds_entity_deriver_dummy_set_qos, + .validate_status = dds_entity_deriver_dummy_validate_status +}; +dds_entity_t dds_create_waitset (dds_entity_t participant) +{ + dds_entity_t hdl; + dds_participant *par; + dds_return_t rc; + + if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) + return rc; + + dds_waitset *waitset = dds_alloc (sizeof (*waitset)); + hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0); + waitset->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&par->m_entity, &waitset->m_entity); + waitset->nentities = 0; + waitset->ntriggered = 0; + waitset->entities = NULL; + dds_participant_unlock (par); + return hdl; +} + +dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size) +{ + dds_return_t ret; + dds_waitset *ws; + + if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK) return ret; + + if (entities != NULL) + { + for (size_t i = 0; i < ws->nentities && i < size; i++) + entities[i] = ws->entities[i].handle; + } + ret = (int32_t) ws->nentities; + dds_waitset_unlock (ws); + return ret; } -static void -dds_waitset_close_list( - dds_attachment **list, - dds_entity_t waitset) +static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed) { - dds_attachment *idx = *list; - dds_attachment *next; - while (idx != NULL) { - next = idx->next; - (void)dds_entity_observer_unregister(idx->entity->m_hdllink.hdl, waitset); - ddsrt_free(idx); - idx = next; + size_t i; + for (i = 0; i < ws->nentities; i++) + if (ws->entities[i].handle == observed) + break; + if (i < ws->nentities) + { + if (i < ws->ntriggered) + { + ws->entities[i] = ws->entities[--ws->ntriggered]; + ws->entities[ws->ntriggered] = ws->entities[--ws->nentities]; } - *list = NULL; -} - -static bool -dds_waitset_remove_from_list( - dds_attachment **list, - dds_entity_t observed) -{ - dds_attachment *idx = *list; - dds_attachment *prev = NULL; - - while (idx != NULL) { - if (idx->entity->m_hdllink.hdl == observed) { - if (prev == NULL) { - *list = idx->next; - } else { - prev->next = idx->next; - } - ddsrt_free(idx); - - /* We're done. */ - return true; - } - prev = idx; - idx = idx->next; - } - return false; -} - -dds_return_t -dds_waitset_close( - struct dds_entity *e) -{ - dds_waitset *ws = (dds_waitset*)e; - - dds_waitset_close_list(&ws->observed, e->m_hdllink.hdl); - dds_waitset_close_list(&ws->triggered, e->m_hdllink.hdl); - - /* Trigger waitset to wake up. */ - ddsrt_cond_broadcast(&e->m_cond); - - return DDS_RETCODE_OK; -} - -DDS_EXPORT dds_entity_t -dds_create_waitset( - dds_entity_t participant) -{ - dds_entity_t hdl; - dds_entity *par; - dds_retcode_t rc; - - rc = dds_entity_lock(participant, DDS_KIND_PARTICIPANT, &par); - if (rc == DDS_RETCODE_OK) { - dds_waitset *waitset = dds_alloc(sizeof(*waitset)); - hdl = dds_entity_init(&waitset->m_entity, par, DDS_KIND_WAITSET, NULL, NULL, 0); - waitset->m_entity.m_deriver.close = dds_waitset_close; - waitset->observed = NULL; - waitset->triggered = NULL; - dds_entity_unlock(par); - } else { - hdl = DDS_ERRNO(rc); - } - - return hdl; -} - - -DDS_EXPORT dds_return_t -dds_waitset_get_entities( - dds_entity_t waitset, - dds_entity_t *entities, - size_t size) -{ - dds_return_t ret = 0; - dds_retcode_t rc; - dds_waitset *ws; - - rc = dds_waitset_lock(waitset, &ws); - if (rc == DDS_RETCODE_OK) { - dds_attachment* iter; - - iter = ws->observed; - while (iter) { - if (((size_t)ret < size) && (entities != NULL)) { - entities[ret] = iter->entity->m_hdllink.hdl; - } - ret++; - iter = iter->next; - } - - iter = ws->triggered; - while (iter) { - if (((size_t)ret < size) && (entities != NULL)) { - entities[ret] = iter->entity->m_hdllink.hdl; - } - ret++; - iter = iter->next; - } - dds_waitset_unlock(ws); - } else { - DDS_ERROR("Error occurred on locking waitset\n"); - ret = DDS_ERRNO(rc); - } - - return ret; -} - - -static void -dds_waitset_move( - dds_attachment **src, - dds_attachment **dst, - dds_entity_t entity) -{ - dds_attachment *idx = *src; - dds_attachment *prev = NULL; - while (idx != NULL) { - if (idx->entity->m_hdllink.hdl == entity) { - /* Swap idx from src to dst. */ - dds_waitset_swap(dst, src, prev, idx); - - /* We're done. */ - return; - } - prev = idx; - idx = idx->next; - } -} - -static void -dds_waitset_remove( - dds_waitset *ws, - dds_entity_t observed) -{ - if (!dds_waitset_remove_from_list(&(ws->observed), observed)) { - (void)dds_waitset_remove_from_list(&(ws->triggered), observed); + else + { + ws->entities[i] = ws->entities[--ws->nentities]; } + return; + } } /* This is called when the observed entity signals a status change. */ -void -dds_waitset_observer( - dds_entity_t observer, - dds_entity_t observed, - uint32_t status) +static void dds_waitset_observer (dds_entity *ent, dds_entity_t observed, uint32_t status) { - dds_waitset *ws; - if (dds_waitset_lock(observer, &ws) == DDS_RETCODE_OK) { - if (status & DDS_DELETING_STATUS) { - /* Remove this observed entity, which is being deleted, from the waitset. */ - dds_waitset_remove(ws, observed); - /* Our registration to this observed entity will be removed automatically. */ - } else if (status != 0) { - /* Move observed entity to triggered list. */ - dds_waitset_move(&(ws->observed), &(ws->triggered), observed); - } else { - /* Remove observed entity from triggered list (which it possibly resides in). */ - dds_waitset_move(&(ws->triggered), &(ws->observed), observed); - } - /* Trigger waitset to wake up. */ - ddsrt_cond_broadcast(&ws->m_entity.m_cond); - dds_waitset_unlock(ws); - } + assert (dds_entity_kind (ent) == DDS_KIND_WAITSET); + dds_waitset *ws = (dds_waitset *) ent; + (void) status; + + ddsrt_mutex_lock (&ws->m_entity.m_mutex); + /* Move observed entity to triggered list. */ + size_t i; + for (i = 0; i < ws->nentities; i++) + if (ws->entities[i].handle == observed) + break; + if (i < ws->nentities && i >= ws->ntriggered) + { + dds_attachment tmp = ws->entities[i]; + ws->entities[i] = ws->entities[ws->ntriggered]; + ws->entities[ws->ntriggered++] = tmp; + } + /* Trigger waitset to wake up. */ + ddsrt_cond_broadcast (&ws->m_entity.m_cond); + ddsrt_mutex_unlock (&ws->m_entity.m_mutex); } -DDS_EXPORT dds_return_t -dds_waitset_attach( - dds_entity_t waitset, - dds_entity_t entity, - dds_attach_t x) +static void dds_waitset_delete_observer (dds_entity *ent, dds_entity_t observed) { - dds_entity *e = NULL; - dds_waitset *ws; - dds_retcode_t rc; - dds_return_t ret; + assert (dds_entity_kind (ent) == DDS_KIND_WAITSET); + dds_waitset *ws = (dds_waitset *) ent; + ddsrt_mutex_lock (&ws->m_entity.m_mutex); + /* Remove this observed entity, which is being deleted, from the waitset. */ + dds_waitset_remove (ws, observed); + /* Our registration to this observed entity will be removed automatically. */ + /* Trigger waitset to wake up. */ + ddsrt_cond_broadcast (&ws->m_entity.m_cond); + ddsrt_mutex_unlock (&ws->m_entity.m_mutex); +} - rc = dds_waitset_lock(waitset, &ws); - if (rc == DDS_RETCODE_OK) { - if (waitset != entity) { - rc = dds_entity_lock(entity, DDS_KIND_DONTCARE, &e); - if (rc != DDS_RETCODE_OK) { - e = NULL; - } - } else { - e = &ws->m_entity; - } - - /* This will fail if given entity is already attached (or deleted). */ - if (rc == DDS_RETCODE_OK) { - rc = dds_entity_observer_register_nl(e, waitset, dds_waitset_observer); - } - - if (rc == DDS_RETCODE_OK) { - dds_attachment *a = ddsrt_malloc(sizeof(dds_attachment)); - a->arg = x; - a->entity = e; - if (e->m_trigger > 0) { - a->next = ws->triggered; - ws->triggered = a; - } else { - a->next = ws->observed; - ws->observed = a; - } - ret = DDS_RETCODE_OK; - } else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET) { - DDS_ERROR("Entity is not valid\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } else { - DDS_ERROR("Entity is already attached\n"); - ret = DDS_ERRNO(rc); - } - if ((e != NULL) && (waitset != entity)) { - dds_entity_unlock(e); - } - dds_waitset_unlock(ws); - } else { - DDS_ERROR("Error occurred on locking waitset\n"); - ret = DDS_ERRNO(rc); - } +dds_return_t dds_waitset_attach (dds_entity_t waitset, dds_entity_t entity, dds_attach_t x) +{ + dds_entity *e; + dds_waitset *ws; + dds_return_t ret; + if ((ret = dds_waitset_lock (waitset, &ws)) < 0) return ret; + + if (waitset == entity) + e = &ws->m_entity; + else if ((ret = dds_entity_pin (entity, &e)) < 0) + goto err_waitset; + + /* This will fail if given entity is already attached (or deleted). */ + if ((ret = dds_entity_observer_register (e, &ws->m_entity, dds_waitset_observer, dds_waitset_delete_observer)) != DDS_RETCODE_OK) + goto err_entity; + + ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities)); + ws->entities[ws->nentities].arg = x; + ws->entities[ws->nentities].entity = e; + ws->entities[ws->nentities].handle = e->m_hdllink.hdl; + ws->nentities++; + if (is_triggered (e)) + { + const size_t i = ws->nentities - 1; + dds_attachment tmp = ws->entities[i]; + ws->entities[i] = ws->entities[ws->ntriggered]; + ws->entities[ws->ntriggered++] = tmp; + } + ddsrt_cond_broadcast (&ws->m_entity.m_cond); + +err_entity: + if (e != &ws->m_entity) + dds_entity_unpin (e); +err_waitset: + dds_waitset_unlock (ws); + return ret; } -DDS_EXPORT dds_return_t -dds_waitset_detach( - dds_entity_t waitset, - dds_entity_t entity) +dds_return_t dds_waitset_detach (dds_entity_t waitset, dds_entity_t entity) { - dds_waitset *ws; - dds_retcode_t rc; - dds_return_t ret; - - rc = dds_waitset_lock(waitset, &ws); - if (rc == DDS_RETCODE_OK) { - /* Possibly fails when entity was not attached. */ - if (waitset == entity) { - rc = dds_entity_observer_unregister_nl(&ws->m_entity, waitset); - } else { - rc = dds_entity_observer_unregister(entity, waitset); - } - if (rc == DDS_RETCODE_OK) { - dds_waitset_remove(ws, entity); - ret = DDS_RETCODE_OK; - } else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET) { - DDS_ERROR("The given entity to detach is invalid\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } else { - DDS_ERROR("The given entity to detach was not attached previously\n"); - ret = DDS_ERRNO(rc); - } - dds_waitset_unlock(ws); - } else { - DDS_ERROR("Error occurred on locking waitset\n"); - ret = DDS_ERRNO(rc); - } + dds_waitset *ws; + dds_entity *e; + dds_return_t ret; + if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK) return ret; + + /* Possibly fails when entity was not attached. */ + if (waitset == entity) + ret = dds_entity_observer_unregister (&ws->m_entity, &ws->m_entity); + else if ((ret = dds_entity_pin (entity, &e)) < 0) + ; /* entity invalid */ + else + { + ret = dds_entity_observer_unregister (e, &ws->m_entity); + dds_entity_unpin (e); + } + + if (ret == DDS_RETCODE_OK) + { + dds_waitset_remove (ws, entity); + } + else + { + if (ret != DDS_RETCODE_PRECONDITION_NOT_MET) + ret = DDS_RETCODE_BAD_PARAMETER; + } + dds_waitset_unlock (ws); + return ret; } -dds_return_t -dds_waitset_wait_until( - dds_entity_t waitset, - dds_attach_t *xs, - size_t nxs, - dds_time_t abstimeout) +dds_return_t dds_waitset_wait_until (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_time_t abstimeout) { - return dds_waitset_wait_impl(waitset, xs, nxs, abstimeout, dds_time()); + return dds_waitset_wait_impl (waitset, xs, nxs, abstimeout); } -dds_return_t -dds_waitset_wait( - dds_entity_t waitset, - dds_attach_t *xs, - size_t nxs, - dds_duration_t reltimeout) +dds_return_t dds_waitset_wait (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_duration_t reltimeout) { - dds_entity_t ret; - - if (reltimeout >= 0) { - dds_time_t tnow = dds_time(); - dds_time_t abstimeout = (DDS_INFINITY - reltimeout <= tnow) ? DDS_NEVER : (tnow + reltimeout); - ret = dds_waitset_wait_impl(waitset, xs, nxs, abstimeout, tnow); - } else{ - DDS_ERROR("Negative timeout\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - - return ret; + if (reltimeout < 0) + return DDS_RETCODE_BAD_PARAMETER; + const dds_time_t tnow = dds_time (); + const dds_time_t abstimeout = (DDS_INFINITY - reltimeout <= tnow) ? DDS_NEVER : (tnow + reltimeout); + return dds_waitset_wait_impl (waitset, xs, nxs, abstimeout); } dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger) { - dds_waitset *ws; - dds_retcode_t rc; + dds_entity *ent; + dds_return_t rc; - if ((rc = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((rc = dds_entity_pin (waitset, &ent)) != DDS_RETCODE_OK) + return rc; + else if (dds_entity_kind (ent) != DDS_KIND_WAITSET) + { + dds_entity_unpin (ent); + return DDS_RETCODE_ILLEGAL_OPERATION; + } - ddsrt_mutex_unlock (&ws->m_entity.m_mutex); + ddsrt_mutex_lock (&ent->m_observers_lock); + dds_entity_trigger_set (ent, trigger); + ddsrt_mutex_unlock (&ent->m_observers_lock); - ddsrt_mutex_lock (&ws->m_entity.m_observers_lock); - if (trigger) - dds_entity_status_set (&ws->m_entity, DDS_WAITSET_TRIGGER_STATUS); - else - dds_entity_status_reset (&ws->m_entity, DDS_WAITSET_TRIGGER_STATUS); - ddsrt_mutex_unlock (&ws->m_entity.m_observers_lock); - - ddsrt_mutex_lock (&ws->m_entity.m_mutex); - dds_waitset_unlock (ws); + dds_entity_unpin (ent); return DDS_RETCODE_OK; } - diff --git a/src/core/ddsc/src/dds_whc.c b/src/core/ddsc/src/dds_whc.c index 2992990..0fc5e8b 100644 --- a/src/core/ddsc/src/dds_whc.c +++ b/src/core/ddsc/src/dds_whc.c @@ -35,7 +35,7 @@ struct whc_node { struct whc_node *next_seq; /* next in this interval */ struct whc_node *prev_seq; /* prev in this interval */ struct whc_idxnode *idxnode; /* NULL if not in index */ - unsigned idxnode_pos; /* index in idxnode.hist */ + uint32_t idxnode_pos; /* index in idxnode.hist */ seqno_t seq; uint64_t total_bytes; /* cumulative number of bytes up to and including this node */ size_t size; @@ -43,7 +43,7 @@ struct whc_node { unsigned unacked: 1; /* counted in whc::unacked_bytes iff 1 */ unsigned borrowed: 1; /* at most one can borrow it at any time */ nn_mtime_t last_rexmit_ts; - unsigned rexmit_count; + uint32_t rexmit_count; struct ddsi_serdata *serdata; }; @@ -59,12 +59,8 @@ struct whc_idxnode { uint64_t iid; seqno_t prune_seq; struct ddsi_tkmap_instance *tk; - unsigned headidx; -#if __STDC_VERSION__ >= 199901L + uint32_t headidx; struct whc_node *hist[]; -#else - struct whc_node *hist[1]; -#endif }; #if USE_EHH @@ -77,14 +73,18 @@ struct whc_seq_entry { struct whc_impl { struct whc common; ddsrt_mutex_t lock; - unsigned seq_size; + uint32_t seq_size; size_t unacked_bytes; size_t sample_overhead; + uint32_t fragment_size; uint64_t total_bytes; /* total number of bytes pushed in */ unsigned is_transient_local: 1; - unsigned hdepth; /* 0 = unlimited */ - unsigned tldepth; /* 0 = disabled/unlimited (no need to maintain an index if KEEP_ALL <=> is_transient_local + tldepth=0) */ - unsigned idxdepth; /* = max(hdepth, tldepth) */ + unsigned xchecks: 1; + struct q_globals *gv; + struct ddsi_tkmap *tkmap; + uint32_t hdepth; /* 0 = unlimited */ + uint32_t tldepth; /* 0 = disabled/unlimited (no need to maintain an index if KEEP_ALL <=> is_transient_local + tldepth=0) */ + uint32_t idxdepth; /* = max (hdepth, tldepth) */ seqno_t max_drop_seq; /* samples in whc with seq <= max_drop_seq => transient-local */ struct whc_intvnode *open_intv; /* interval where next sample will go (usually) */ struct whc_node *maxseq_node; /* NULL if empty; if not in open_intv, open_intv is empty */ @@ -103,14 +103,12 @@ struct whc_sample_iter_impl { }; /* check that our definition of whc_sample_iter fits in the type that callers allocate */ -struct whc_sample_iter_sizecheck { - char fits_in_generic_type[sizeof(struct whc_sample_iter_impl) <= sizeof(struct whc_sample_iter) ? 1 : -1]; -}; +DDSRT_STATIC_ASSERT (sizeof (struct whc_sample_iter_impl) <= sizeof (struct whc_sample_iter)); /* Hash + interval tree adminitration of samples-by-sequence number * - by definition contains all samples in WHC (unchanged from older versions) * Circular array of samples per instance, inited to all 0 - * - length is max(durability_service.history_depth, history.depth), KEEP_ALL => as-if 0 + * - length is max (durability_service.history_depth, history.depth), KEEP_ALL => as-if 0 * - no instance index if above length 0 * - each sample (i.e., whc_node): backpointer into index * - maintain index of latest sample, end of history then trivially follows from index arithmetic @@ -124,18 +122,18 @@ static void insert_whcn_in_hash (struct whc_impl *whc, struct whc_node *whcn); static void whc_delete_one (struct whc_impl *whc, struct whc_node *whcn); static int compare_seq (const void *va, const void *vb); static void free_deferred_free_list (struct whc_node *deferred_free_list); -static void get_state_locked(const struct whc_impl *whc, struct whc_state *st); +static void get_state_locked (const struct whc_impl *whc, struct whc_state *st); -static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list); -static unsigned whc_default_remove_acked_messages (struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list); +static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list); +static uint32_t whc_default_remove_acked_messages (struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list); static void whc_default_free_deferred_free_list (struct whc *whc, struct whc_node *deferred_free_list); -static void whc_default_get_state(const struct whc *whc, struct whc_state *st); +static void whc_default_get_state (const struct whc *whc, struct whc_state *st); static int whc_default_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); static seqno_t whc_default_next_seq (const struct whc *whc, seqno_t seq); static bool whc_default_borrow_sample (const struct whc *whc, seqno_t seq, struct whc_borrowed_sample *sample); static bool whc_default_borrow_sample_key (const struct whc *whc, const struct ddsi_serdata *serdata_key, struct whc_borrowed_sample *sample); static void whc_default_return_sample (struct whc *whc, struct whc_borrowed_sample *sample, bool update_retransmit_info); -static unsigned whc_default_downgrade_to_volatile (struct whc *whc, struct whc_state *st); +static uint32_t whc_default_downgrade_to_volatile (struct whc *whc, struct whc_state *st); static void whc_default_sample_iter_init (const struct whc *whc, struct whc_sample_iter *opaque_it); static bool whc_default_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, struct whc_borrowed_sample *sample); static void whc_default_free (struct whc *whc); @@ -158,13 +156,15 @@ static const struct whc_ops whc_ops = { .free = whc_default_free }; -/* Number of instantiated WHCs and a global freelist for WHC nodes that gets - initialized lazily and cleaned up automatically when the last WHC is freed. - Protected by dds_global.m_mutex. +#define TRACE(...) DDS_CLOG (DDS_LC_WHC, &whc->gv->logconfig, __VA_ARGS__) - sizeof (whc_node) on 64-bit machines ~ 100 bytes, so this is ~1MB - 8k entries seems to be roughly the amount needed for minimum samples, - maximum message size and a short round-trip time */ +/* Number of instantiated WHCs and a global freelist for WHC nodes that gets + initialized lazily and cleaned up automatically when the last WHC is freed. + Protected by dds_global.m_mutex. + + sizeof (whc_node) on 64-bit machines ~ 100 bytes, so this is ~1MB + 8k entries seems to be roughly the amount needed for minimum samples, + maximum message size and a short round-trip time */ #define MAX_FREELIST_SIZE 8192 static uint32_t whc_count; static struct nn_freelist whc_node_freelist; @@ -175,9 +175,9 @@ static uint32_t whc_seq_entry_hash (const void *vn) const struct whc_seq_entry *n = vn; /* we hash the lower 32 bits, on the assumption that with 4 billion samples in between there won't be significant correlation */ - const uint64_t c = UINT64_C(16292676669999574021); + const uint64_t c = UINT64_C (16292676669999574021); const uint32_t x = (uint32_t) n->seq; - return (unsigned) ((x * c) >> 32); + return (uint32_t) ((x * c) >> 32); } static int whc_seq_entry_eq (const void *va, const void *vb) @@ -192,9 +192,9 @@ static uint32_t whc_node_hash (const void *vn) const struct whc_node *n = vn; /* we hash the lower 32 bits, on the assumption that with 4 billion samples in between there won't be significant correlation */ - const uint64_t c = UINT64_C(16292676669999574021); + const uint64_t c = UINT64_C (16292676669999574021); const uint32_t x = (uint32_t) n->seq; - return (unsigned) ((x * c) >> 32); + return (uint32_t) ((x * c) >> 32); } static int whc_node_eq (const void *va, const void *vb) @@ -245,10 +245,10 @@ static struct whc_node *whc_findmax_procedurally (const struct whc_impl *whc) static void check_whc (const struct whc_impl *whc) { /* there's much more we can check, but it gets expensive quite - quickly: all nodes but open_intv non-empty, non-overlapping and - non-contiguous; min & maxp1 of intervals correct; each interval - contiguous; all samples in seq & in seqhash; tlidx \subseteq seq; - seq-number ordered list correct; &c. */ + quickly: all nodes but open_intv non-empty, non-overlapping and + non-contiguous; min & maxp1 of intervals correct; each interval + contiguous; all samples in seq & in seqhash; tlidx \subseteq seq; + seq-number ordered list correct; &c. */ assert (whc->open_intv != NULL); assert (whc->open_intv == ddsrt_avl_find_max (&whc_seq_treedef, &whc->seq)); assert (ddsrt_avl_find_succ (&whc_seq_treedef, &whc->seq, whc->open_intv) == NULL); @@ -269,8 +269,8 @@ static void check_whc (const struct whc_impl *whc) } assert (whc->maxseq_node == whc_findmax_procedurally (whc)); -#if !defined(NDEBUG) - if (config.enabled_xchecks & DDS_XCHECK_WHC) +#if !defined (NDEBUG) + if (whc->xchecks) { struct whc_intvnode *firstintv; struct whc_node *cur; @@ -295,10 +295,10 @@ static void insert_whcn_in_hash (struct whc_impl *whc, struct whc_node *whcn) #if USE_EHH struct whc_seq_entry e = { .seq = whcn->seq, .whcn = whcn }; if (!ddsrt_ehh_add (whc->seq_hash, &e)) - assert(0); + assert (0); #else if (!ddsrt_hh_add (whc->seq_hash, whcn)) - assert(0); + assert (0); #endif } @@ -307,11 +307,11 @@ static void remove_whcn_from_hash (struct whc_impl *whc, struct whc_node *whcn) /* precondition: whcn is in hash */ #if USE_EHH struct whc_seq_entry e = { .seq = whcn->seq }; - if (!ddsrt_ehh_remove(whc->seq_hash, &e)) - assert(0); + if (!ddsrt_ehh_remove (whc->seq_hash, &e)) + assert (0); #else - if (!ddsrt_hh_remove(whc->seq_hash, whcn)) - assert(0); + if (!ddsrt_hh_remove (whc->seq_hash, whcn)) + assert (0); #endif } @@ -319,14 +319,14 @@ static struct whc_node *whc_findseq (const struct whc_impl *whc, seqno_t seq) { #if USE_EHH struct whc_seq_entry e = { .seq = seq }, *r; - if ((r = ddsrt_ehh_lookup(whc->seq_hash, &e)) != NULL) + if ((r = ddsrt_ehh_lookup (whc->seq_hash, &e)) != NULL) return r->whcn; else return NULL; #else struct whc_node template; template.seq = seq; - return ddsrt_hh_lookup(whc->seq_hash, &template); + return ddsrt_hh_lookup (whc->seq_hash, &template); #endif } @@ -334,11 +334,11 @@ static struct whc_node *whc_findkey (const struct whc_impl *whc, const struct dd { union { struct whc_idxnode idxn; - char pad[sizeof(struct whc_idxnode) + sizeof(struct whc_node *)]; + char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)]; } template; struct whc_idxnode *n; check_whc (whc); - template.idxn.iid = ddsi_tkmap_lookup(gv.m_tkmap, serdata_key); + template.idxn.iid = ddsi_tkmap_lookup (whc->tkmap, serdata_key); n = ddsrt_hh_lookup (whc->idx_hash, &template.idxn); if (n == NULL) return NULL; @@ -349,18 +349,21 @@ static struct whc_node *whc_findkey (const struct whc_impl *whc, const struct dd } } -struct whc *whc_new (int is_transient_local, unsigned hdepth, unsigned tldepth) +struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdepth, uint32_t tldepth) { size_t sample_overhead = 80; /* INFO_TS, DATA (estimate), inline QoS */ struct whc_impl *whc; struct whc_intvnode *intv; - assert((hdepth == 0 || tldepth <= hdepth) || is_transient_local); + assert ((hdepth == 0 || tldepth <= hdepth) || is_transient_local); whc = ddsrt_malloc (sizeof (*whc)); whc->common.ops = &whc_ops; ddsrt_mutex_init (&whc->lock); whc->is_transient_local = is_transient_local ? 1 : 0; + whc->xchecks = (gv->config.enabled_xchecks & DDS_XCHECK_WHC) != 0; + whc->gv = gv; + whc->tkmap = gv->m_tkmap; whc->hdepth = hdepth; whc->tldepth = tldepth; whc->idxdepth = hdepth > tldepth ? hdepth : tldepth; @@ -369,14 +372,15 @@ struct whc *whc_new (int is_transient_local, unsigned hdepth, unsigned tldepth) whc->unacked_bytes = 0; whc->total_bytes = 0; whc->sample_overhead = sample_overhead; + whc->fragment_size = gv->config.fragment_size; #if USE_EHH whc->seq_hash = ddsrt_ehh_new (sizeof (struct whc_seq_entry), 32, whc_seq_entry_hash, whc_seq_entry_eq); #else - whc->seq_hash = ddsrt_hh_new(32, whc_node_hash, whc_node_eq); + whc->seq_hash = ddsrt_hh_new (1, whc_node_hash, whc_node_eq); #endif if (whc->idxdepth > 0) - whc->idx_hash = ddsrt_hh_new(32, whc_idxnode_hash_key, whc_idxnode_eq_key); + whc->idx_hash = ddsrt_hh_new (1, whc_idxnode_hash_key, whc_idxnode_eq_key); else whc->idx_hash = NULL; @@ -417,9 +421,9 @@ void whc_default_free (struct whc *whc_generic) { struct ddsrt_hh_iter it; struct whc_idxnode *n; - for (n = ddsrt_hh_iter_first(whc->idx_hash, &it); n != NULL; n = ddsrt_hh_iter_next(&it)) - ddsrt_free(n); - ddsrt_hh_free(whc->idx_hash); + for (n = ddsrt_hh_iter_first (whc->idx_hash, &it); n != NULL; n = ddsrt_hh_iter_next (&it)) + ddsrt_free (n); + ddsrt_hh_free (whc->idx_hash); } { @@ -427,10 +431,10 @@ void whc_default_free (struct whc *whc_generic) while (whcn) { struct whc_node *tmp = whcn; -/* The compiler doesn't realize that whcn->prev_seq is always initialized. */ -DDSRT_WARNING_MSVC_OFF(6001); + /* The compiler doesn't realize that whcn->prev_seq is always initialized. */ + DDSRT_WARNING_MSVC_OFF (6001); whcn = whcn->prev_seq; -DDSRT_WARNING_MSVC_ON(6001); + DDSRT_WARNING_MSVC_ON (6001); free_whc_node_contents (tmp); ddsrt_free (tmp); } @@ -452,7 +456,7 @@ DDSRT_WARNING_MSVC_ON(6001); ddsrt_free (whc); } -static void get_state_locked(const struct whc_impl *whc, struct whc_state *st) +static void get_state_locked (const struct whc_impl *whc, struct whc_state *st) { if (whc->seq_size == 0) { @@ -473,12 +477,12 @@ static void get_state_locked(const struct whc_impl *whc, struct whc_state *st) } } -static void whc_default_get_state(const struct whc *whc_generic, struct whc_state *st) +static void whc_default_get_state (const struct whc *whc_generic, struct whc_state *st) { const struct whc_impl * const whc = (const struct whc_impl *)whc_generic; ddsrt_mutex_lock ((ddsrt_mutex_t *)&whc->lock); check_whc (whc); - get_state_locked(whc, st); + get_state_locked (whc, st); ddsrt_mutex_unlock ((ddsrt_mutex_t *)&whc->lock); } @@ -489,8 +493,8 @@ static struct whc_node *find_nextseq_intv (struct whc_intvnode **p_intv, const s if ((n = whc_findseq (whc, seq)) == NULL) { /* don't know seq => lookup interval with min > seq (intervals are - contiguous, so if we don't know seq, an interval [X,Y) with X < - SEQ < Y can't exist */ + contiguous, so if we don't know seq, an interval [X,Y) with X < + SEQ < Y can't exist */ #ifndef NDEBUG { struct whc_intvnode *predintv = ddsrt_avl_lookup_pred_eq (&whc_seq_treedef, &whc->seq, &seq); @@ -551,13 +555,12 @@ static void delete_one_sample_from_idx (struct whc_impl *whc, struct whc_node *w else { #ifndef NDEBUG - unsigned i; - for (i = 0; i < whc->idxdepth; i++) + for (uint32_t i = 0; i < whc->idxdepth; i++) assert (i == idxn->headidx || idxn->hist[i] == NULL); #endif if (!ddsrt_hh_remove (whc->idx_hash, idxn)) assert (0); - ddsi_tkmap_instance_unref(idxn->tk); + ddsi_tkmap_instance_unref (whc->tkmap, idxn->tk); ddsrt_free (idxn); } whcn->idxnode = NULL; @@ -565,8 +568,7 @@ static void delete_one_sample_from_idx (struct whc_impl *whc, struct whc_node *w static void free_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_idxnode *idxn) { - unsigned i; - for (i = 0; i < whc->idxdepth; i++) + for (uint32_t i = 0; i < whc->idxdepth; i++) { if (idxn->hist[i]) { @@ -574,13 +576,13 @@ static void free_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop_s oldn->idxnode = NULL; if (oldn->seq <= max_drop_seq) { - DDS_LOG(DDS_LC_WHC, " prune tl whcn %p\n", (void *)oldn); - assert(oldn != whc->maxseq_node); + TRACE (" prune tl whcn %p\n", (void *)oldn); + assert (oldn != whc->maxseq_node); whc_delete_one (whc, oldn); } } } - ddsrt_free(idxn); + ddsrt_free (idxn); } static void delete_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_idxnode *idxn) @@ -590,34 +592,34 @@ static void delete_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop free_one_instance_from_idx (whc, max_drop_seq, idxn); } -static int whcn_in_tlidx (const struct whc_impl *whc, const struct whc_idxnode *idxn, unsigned pos) +static int whcn_in_tlidx (const struct whc_impl *whc, const struct whc_idxnode *idxn, uint32_t pos) { if (idxn == NULL) return 0; else { - unsigned d = (idxn->headidx + (pos > idxn->headidx ? whc->idxdepth : 0)) - pos; + uint32_t d = (idxn->headidx + (pos > idxn->headidx ? whc->idxdepth : 0)) - pos; assert (d < whc->idxdepth); return d < whc->tldepth; } } -static unsigned whc_default_downgrade_to_volatile (struct whc *whc_generic, struct whc_state *st) +static uint32_t whc_default_downgrade_to_volatile (struct whc *whc_generic, struct whc_state *st) { struct whc_impl * const whc = (struct whc_impl *)whc_generic; seqno_t old_max_drop_seq; struct whc_node *deferred_free_list; - unsigned cnt; + uint32_t cnt; /* We only remove them from whc->tlidx: we don't remove them from - whc->seq yet. That'll happen eventually. */ + whc->seq yet. That'll happen eventually. */ ddsrt_mutex_lock (&whc->lock); check_whc (whc); if (whc->idxdepth == 0) { /* if not maintaining an index at all, this is nonsense */ - get_state_locked(whc, st); + get_state_locked (whc, st); ddsrt_mutex_unlock (&whc->lock); return 0; } @@ -625,29 +627,29 @@ static unsigned whc_default_downgrade_to_volatile (struct whc *whc_generic, stru assert (!whc->is_transient_local); if (whc->tldepth > 0) { - assert(whc->hdepth == 0 || whc->tldepth <= whc->hdepth); + assert (whc->hdepth == 0 || whc->tldepth <= whc->hdepth); whc->tldepth = 0; if (whc->hdepth == 0) { struct ddsrt_hh_iter it; struct whc_idxnode *n; - for (n = ddsrt_hh_iter_first(whc->idx_hash, &it); n != NULL; n = ddsrt_hh_iter_next(&it)) + for (n = ddsrt_hh_iter_first (whc->idx_hash, &it); n != NULL; n = ddsrt_hh_iter_next (&it)) free_one_instance_from_idx (whc, 0, n); - ddsrt_hh_free(whc->idx_hash); + ddsrt_hh_free (whc->idx_hash); whc->idxdepth = 0; whc->idx_hash = NULL; } } /* Immediately drop them from the WHC (used to delay it until the - next ack); but need to make sure remove_acked_messages processes - them all. */ + next ack); but need to make sure remove_acked_messages processes + them all. */ old_max_drop_seq = whc->max_drop_seq; whc->max_drop_seq = 0; cnt = whc_default_remove_acked_messages_full (whc, old_max_drop_seq, &deferred_free_list); whc_default_free_deferred_free_list (whc_generic, deferred_free_list); assert (whc->max_drop_seq == old_max_drop_seq); - get_state_locked(whc, st); + get_state_locked (whc, st); ddsrt_mutex_unlock (&whc->lock); return cnt; } @@ -655,20 +657,20 @@ static unsigned whc_default_downgrade_to_volatile (struct whc *whc_generic, stru static size_t whcn_size (const struct whc_impl *whc, const struct whc_node *whcn) { size_t sz = ddsi_serdata_size (whcn->serdata); - return sz + ((sz + config.fragment_size - 1) / config.fragment_size) * whc->sample_overhead; + return sz + ((sz + whc->fragment_size - 1) / whc->fragment_size) * whc->sample_overhead; } static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_intv, struct whc_node **p_whcn) { /* Removes *p_whcn, possibly deleting or splitting *p_intv, as the - case may be. Does *NOT* update whc->seq_size. *p_intv must be - the interval containing *p_whcn (&& both must actually exist). + case may be. Does *NOT* update whc->seq_size. *p_intv must be + the interval containing *p_whcn (&& both must actually exist). - Returns: - - 0 if delete failed (only possible cause is memory exhaustion), - in which case *p_intv & *p_whcn are undefined; - - 1 if successful, in which case *p_intv & *p_whcn are set - correctly for the next sample in sequence number order */ + Returns: + - 0 if delete failed (only possible cause is memory exhaustion), + in which case *p_intv & *p_whcn are undefined; + - 1 if successful, in which case *p_intv & *p_whcn are set + correctly for the next sample in sequence number order */ struct whc_intvnode *intv = *p_intv; struct whc_node *whcn = *p_whcn; assert (whcn->seq >= intv->min && whcn->seq < intv->maxp1); @@ -685,13 +687,13 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i } /* Take it out of seqhash; deleting it from the list ordered on - sequence numbers is left to the caller (it has to be done unconditionally, - but remove_acked_messages defers it until the end or a skipped node). */ + sequence numbers is left to the caller (it has to be done unconditionally, + but remove_acked_messages defers it until the end or a skipped node). */ remove_whcn_from_hash (whc, whcn); /* We may have introduced a hole & have to split the interval - node, or we may have nibbled of the first one, or even the - last one. */ + node, or we may have nibbled of the first one, or even the + last one. */ if (whcn == intv->first) { if (whcn == intv->last && intv != whc->open_intv) @@ -714,7 +716,7 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i else if (whcn == intv->last) { /* well, at least it isn't the first one & so the interval is - still non-empty and we don't have to drop the interval */ + still non-empty and we don't have to drop the interval */ assert (intv->min < whcn->seq); assert (whcn->prev_seq); assert (whcn->prev_seq->seq + 1 == whcn->seq); @@ -725,9 +727,9 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i else { /* somewhere in the middle => split the interval (ideally, - would split it lazily, but it really is a transient-local - issue only, and so we can (for now) get away with splitting - it greedily */ + would split it lazily, but it really is a transient-local + issue only, and so we can (for now) get away with splitting + it greedily */ struct whc_intvnode *new_intv; ddsrt_avl_ipath_t path; @@ -746,7 +748,7 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i assert (new_intv->min < new_intv->maxp1); /* insert new node & continue the loop with intv set to the - new interval */ + new interval */ if (ddsrt_avl_lookup_ipath (&whc_seq_treedef, &whc->seq, &new_intv->min, &path) != NULL) assert (0); ddsrt_avl_insert_ipath (&whc_seq_treedef, &whc->seq, new_intv, &path); @@ -801,11 +803,11 @@ static void whc_default_free_deferred_free_list (struct whc *whc_generic, struct free_deferred_free_list (deferred_free_list); } -static unsigned whc_default_remove_acked_messages_noidx (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list) +static uint32_t whc_default_remove_acked_messages_noidx (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list) { struct whc_intvnode *intv; struct whc_node *whcn; - unsigned ndropped = 0; + uint32_t ndropped = 0; /* In the trivial case of an empty WHC, get out quickly */ if (max_drop_seq <= whc->max_drop_seq || whc->maxseq_node == NULL) @@ -817,7 +819,7 @@ static unsigned whc_default_remove_acked_messages_noidx (struct whc_impl *whc, s } /* If simple, we have always dropped everything up to whc->max_drop_seq, - and there can only be a single interval */ + and there can only be a single interval */ #ifndef NDEBUG whcn = find_nextseq_intv (&intv, whc, whc->max_drop_seq); assert (whcn == NULL || whcn->prev_seq == NULL); @@ -826,14 +828,14 @@ static unsigned whc_default_remove_acked_messages_noidx (struct whc_impl *whc, s intv = whc->open_intv; /* Drop everything up to and including max_drop_seq, or absent that one, - the highest available sequence number (which then must be less) */ + the highest available sequence number (which then must be less) */ if ((whcn = whc_findseq (whc, max_drop_seq)) == NULL) { if (max_drop_seq < intv->min) { /* at startup, whc->max_drop_seq = 0 and reader states have max ack'd seq taken from wr->seq; - so if multiple readers are matched and the writer runs ahead of the readers, for the first - ack, whc->max_drop_seq < max_drop_seq = MIN(readers max ack) < intv->min */ + so if multiple readers are matched and the writer runs ahead of the readers, for the first + ack, whc->max_drop_seq < max_drop_seq = MIN (readers max ack) < intv->min */ if (max_drop_seq > whc->max_drop_seq) whc->max_drop_seq = max_drop_seq; *deferred_free_list = NULL; @@ -847,7 +849,7 @@ static unsigned whc_default_remove_acked_messages_noidx (struct whc_impl *whc, s } *deferred_free_list = intv->first; - ndropped = (unsigned) (whcn->seq - intv->min + 1); + ndropped = (uint32_t) (whcn->seq - intv->min + 1); intv->first = whcn->next_seq; intv->min = max_drop_seq + 1; @@ -877,18 +879,18 @@ static unsigned whc_default_remove_acked_messages_noidx (struct whc_impl *whc, s return ndropped; } -static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list) +static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_node **deferred_free_list) { struct whc_intvnode *intv; struct whc_node *whcn; struct whc_node *prev_seq; struct whc_node deferred_list_head, *last_to_free = &deferred_list_head; - unsigned ndropped = 0; + uint32_t ndropped = 0; if (whc->is_transient_local && whc->tldepth == 0) { /* KEEP_ALL on transient local, so we can never ever delete anything */ - DDS_LOG(DDS_LC_WHC, " KEEP_ALL transient-local: do nothing\n"); + TRACE (" KEEP_ALL transient-local: do nothing\n"); *deferred_free_list = NULL; return 0; } @@ -898,11 +900,11 @@ static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, se prev_seq = whcn ? whcn->prev_seq : NULL; while (whcn && whcn->seq <= max_drop_seq) { - DDS_LOG(DDS_LC_WHC, " whcn %p %"PRId64, (void *) whcn, whcn->seq); - if (whcn_in_tlidx(whc, whcn->idxnode, whcn->idxnode_pos)) + TRACE (" whcn %p %"PRId64, (void *) whcn, whcn->seq); + if (whcn_in_tlidx (whc, whcn->idxnode, whcn->idxnode_pos)) { /* quickly skip over samples in tlidx */ - DDS_LOG(DDS_LC_WHC, " tl:keep"); + TRACE (" tl:keep"); if (whcn->unacked) { assert (whc->unacked_bytes >= whcn->size); @@ -920,13 +922,13 @@ static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, se } else { - DDS_LOG(DDS_LC_WHC, " delete"); + TRACE (" delete"); last_to_free->next_seq = whcn; last_to_free = last_to_free->next_seq; whc_delete_one_intv (whc, &intv, &whcn); ndropped++; } - DDS_LOG(DDS_LC_WHC, "\n"); + TRACE ("\n"); } if (prev_seq) prev_seq->next_seq = whcn; @@ -936,32 +938,32 @@ static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, se *deferred_free_list = deferred_list_head.next_seq; /* If the history is deeper than durability_service.history (but not KEEP_ALL), then there - may be old samples in this instance, samples that were retained because they were within - the T-L history but that are not anymore. Writing new samples will eventually push these - out, but if the difference is large and the update rate low, it may take a long time. - Thus, we had better prune them. */ + may be old samples in this instance, samples that were retained because they were within + the T-L history but that are not anymore. Writing new samples will eventually push these + out, but if the difference is large and the update rate low, it may take a long time. + Thus, we had better prune them. */ if (whc->tldepth > 0 && whc->idxdepth > whc->tldepth) { - assert(whc->hdepth == whc->idxdepth); - DDS_LOG(DDS_LC_WHC, " idxdepth %u > tldepth %u > 0 -- must prune\n", whc->idxdepth, whc->tldepth); + assert (whc->hdepth == whc->idxdepth); + TRACE (" idxdepth %"PRIu32" > tldepth %"PRIu32" > 0 -- must prune\n", whc->idxdepth, whc->tldepth); /* Do a second pass over the sequence number range we just processed: this time we only - encounter samples that were retained because of the transient-local durability setting - (the rest has been dropped already) and we prune old samples in the instance */ + encounter samples that were retained because of the transient-local durability setting + (the rest has been dropped already) and we prune old samples in the instance */ whcn = find_nextseq_intv (&intv, whc, whc->max_drop_seq); while (whcn && whcn->seq <= max_drop_seq) { struct whc_idxnode * const idxn = whcn->idxnode; - unsigned cnt, idx; + uint32_t cnt, idx; - DDS_LOG(DDS_LC_WHC, " whcn %p %"PRId64" idxn %p prune_seq %"PRId64":", (void *)whcn, whcn->seq, (void *)idxn, idxn->prune_seq); + TRACE (" whcn %p %"PRId64" idxn %p prune_seq %"PRId64":", (void *) whcn, whcn->seq, (void *) idxn, idxn->prune_seq); - assert(whcn_in_tlidx(whc, idxn, whcn->idxnode_pos)); + assert (whcn_in_tlidx (whc, idxn, whcn->idxnode_pos)); assert (idxn->prune_seq <= max_drop_seq); if (idxn->prune_seq == max_drop_seq) { - DDS_LOG(DDS_LC_WHC, " already pruned\n"); + TRACE (" already pruned\n"); whcn = whcn->next_seq; continue; } @@ -977,27 +979,27 @@ static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, se if ((oldn = idxn->hist[idx]) != NULL) { /* Delete it - but this may not result in deleting the index node as - there must still be a more recent one available */ + there must still be a more recent one available */ #ifndef NDEBUG struct whc_node whcn_template; union { struct whc_idxnode idxn; - char pad[sizeof(struct whc_idxnode) + sizeof(struct whc_node *)]; + char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)]; } template; template.idxn.headidx = 0; template.idxn.hist[0] = &whcn_template; - whcn_template.serdata = ddsi_serdata_ref(oldn->serdata); - assert(oldn->seq < whcn->seq); + whcn_template.serdata = ddsi_serdata_ref (oldn->serdata); + assert (oldn->seq < whcn->seq); #endif - DDS_LOG(DDS_LC_WHC, " del %p %"PRId64, (void *) oldn, oldn->seq); + TRACE (" del %p %"PRId64, (void *) oldn, oldn->seq); whc_delete_one (whc, oldn); #ifndef NDEBUG - assert(ddsrt_hh_lookup(whc->idx_hash, &template) == idxn); - ddsi_serdata_unref(whcn_template.serdata); + assert (ddsrt_hh_lookup (whc->idx_hash, &template) == idxn); + ddsi_serdata_unref (whcn_template.serdata); #endif } } - DDS_LOG(DDS_LC_WHC, "\n"); + TRACE ("\n"); whcn = whcn->next_seq; } } @@ -1011,22 +1013,22 @@ static unsigned whc_default_remove_acked_messages_full (struct whc_impl *whc, se return ndropped; } -static unsigned whc_default_remove_acked_messages (struct whc *whc_generic, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list) +static uint32_t whc_default_remove_acked_messages (struct whc *whc_generic, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list) { struct whc_impl * const whc = (struct whc_impl *)whc_generic; - unsigned cnt; + uint32_t cnt; ddsrt_mutex_lock (&whc->lock); assert (max_drop_seq < MAX_SEQ_NUMBER); assert (max_drop_seq >= whc->max_drop_seq); - if (dds_get_log_mask() & DDS_LC_WHC) + if (whc->gv->logconfig.c.mask & DDS_LC_WHC) { struct whc_state tmp; - get_state_locked(whc, &tmp); - DDS_LOG(DDS_LC_WHC, "whc_default_remove_acked_messages(%p max_drop_seq %"PRId64")\n", (void *)whc, max_drop_seq); - DDS_LOG(DDS_LC_WHC, " whc: [%"PRId64",%"PRId64"] max_drop_seq %"PRId64" h %u tl %u\n", - tmp.min_seq, tmp.max_seq, whc->max_drop_seq, whc->hdepth, whc->tldepth); + get_state_locked (whc, &tmp); + TRACE ("whc_default_remove_acked_messages(%p max_drop_seq %"PRId64")\n", (void *)whc, max_drop_seq); + TRACE (" whc: [%"PRId64",%"PRId64"] max_drop_seq %"PRId64" h %"PRIu32" tl %"PRIu32"\n", + tmp.min_seq, tmp.max_seq, whc->max_drop_seq, whc->hdepth, whc->tldepth); } check_whc (whc); @@ -1035,7 +1037,7 @@ static unsigned whc_default_remove_acked_messages (struct whc *whc_generic, seqn cnt = whc_default_remove_acked_messages_noidx (whc, max_drop_seq, deferred_free_list); else cnt = whc_default_remove_acked_messages_full (whc, max_drop_seq, deferred_free_list); - get_state_locked(whc, whcst); + get_state_locked (whc, whcst); ddsrt_mutex_unlock (&whc->lock); return cnt; } @@ -1108,38 +1110,39 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se struct whc_idxnode *idxn; union { struct whc_idxnode idxn; - char pad[sizeof(struct whc_idxnode) + sizeof(struct whc_node *)]; + char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)]; } template; ddsrt_mutex_lock (&whc->lock); check_whc (whc); - if (dds_get_log_mask() & DDS_LC_WHC) + if (whc->gv->logconfig.c.mask & DDS_LC_WHC) { struct whc_state whcst; - get_state_locked(whc, &whcst); - DDS_LOG(DDS_LC_WHC, "whc_default_insert(%p max_drop_seq %"PRId64" seq %"PRId64" plist %p serdata %p:%"PRIx32")\n", (void *)whc, max_drop_seq, seq, (void*)plist, (void*)serdata, serdata->hash); - DDS_LOG(DDS_LC_WHC, " whc: [%"PRId64",%"PRId64"] max_drop_seq %"PRId64" h %u tl %u\n", - whcst.min_seq, whcst.max_seq, whc->max_drop_seq, whc->hdepth, whc->tldepth); + get_state_locked (whc, &whcst); + TRACE ("whc_default_insert(%p max_drop_seq %"PRId64" seq %"PRId64" plist %p serdata %p:%"PRIx32")\n", + (void *) whc, max_drop_seq, seq, (void *) plist, (void *) serdata, serdata->hash); + TRACE (" whc: [%"PRId64",%"PRId64"] max_drop_seq %"PRId64" h %"PRIu32" tl %"PRIu32"\n", + whcst.min_seq, whcst.max_seq, whc->max_drop_seq, whc->hdepth, whc->tldepth); } assert (max_drop_seq < MAX_SEQ_NUMBER); assert (max_drop_seq >= whc->max_drop_seq); /* Seq must be greater than what is currently stored. Usually it'll - be the next sequence number, but if there are no readers - temporarily, a gap may be among the possibilities */ + be the next sequence number, but if there are no readers + temporarily, a gap may be among the possibilities */ assert (whc->seq_size == 0 || seq > whc->maxseq_node->seq); /* Always insert in seq admin */ newn = whc_default_insert_seq (whc, max_drop_seq, seq, plist, serdata); - DDS_LOG(DDS_LC_WHC, " whcn %p:", (void*)newn); + TRACE (" whcn %p:", (void*)newn); /* Special case of empty data (such as commit messages) can't go into index, and if we're not maintaining an index, we're done, too */ if (serdata->kind == SDK_EMPTY || whc->idxdepth == 0) { - DDS_LOG(DDS_LC_WHC, " empty or no hist\n"); + TRACE (" empty or no hist\n"); ddsrt_mutex_unlock (&whc->lock); return 0; } @@ -1148,15 +1151,15 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se if ((idxn = ddsrt_hh_lookup (whc->idx_hash, &template)) != NULL) { /* Unregisters cause deleting of index entry, non-unregister of adding/overwriting in history */ - DDS_LOG(DDS_LC_WHC, " idxn %p", (void *)idxn); + TRACE (" idxn %p", (void *)idxn); if (serdata->statusinfo & NN_STATUSINFO_UNREGISTER) { - DDS_LOG(DDS_LC_WHC, " unreg:delete\n"); + TRACE (" unreg:delete\n"); delete_one_instance_from_idx (whc, max_drop_seq, idxn); if (newn->seq <= max_drop_seq) { struct whc_node *prev_seq = newn->prev_seq; - DDS_LOG(DDS_LC_WHC, " unreg:seq <= max_drop_seq: delete newn\n"); + TRACE (" unreg:seq <= max_drop_seq: delete newn\n"); whc_delete_one (whc, newn); whc->maxseq_node = prev_seq; } @@ -1168,7 +1171,7 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se idxn->headidx = 0; if ((oldn = idxn->hist[idxn->headidx]) != NULL) { - DDS_LOG(DDS_LC_WHC, " overwrite whcn %p", (void *)oldn); + TRACE (" overwrite whcn %p", (void *)oldn); oldn->idxnode = NULL; } idxn->hist[idxn->headidx] = newn; @@ -1177,46 +1180,45 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se if (oldn && (whc->hdepth > 0 || oldn->seq <= max_drop_seq)) { - DDS_LOG(DDS_LC_WHC, " prune whcn %p", (void *)oldn); - assert(oldn != whc->maxseq_node); + TRACE (" prune whcn %p", (void *)oldn); + assert (oldn != whc->maxseq_node); whc_delete_one (whc, oldn); } /* Special case for dropping everything beyond T-L history when the new sample is being - auto-acknowledged (for lack of reliable readers), and the keep-last T-L history is - shallower than the keep-last regular history (normal path handles this via pruning in - whc_default_remove_acked_messages, but that never happens when there are no readers). */ + auto-acknowledged (for lack of reliable readers), and the keep-last T-L history is + shallower than the keep-last regular history (normal path handles this via pruning in + whc_default_remove_acked_messages, but that never happens when there are no readers). */ if (seq <= max_drop_seq && whc->tldepth > 0 && whc->idxdepth > whc->tldepth) { - unsigned pos = idxn->headidx + whc->idxdepth - whc->tldepth; + uint32_t pos = idxn->headidx + whc->idxdepth - whc->tldepth; if (pos >= whc->idxdepth) pos -= whc->idxdepth; if ((oldn = idxn->hist[pos]) != NULL) { - DDS_LOG(DDS_LC_WHC, " prune tl whcn %p", (void *)oldn); - assert(oldn != whc->maxseq_node); + TRACE (" prune tl whcn %p", (void *)oldn); + assert (oldn != whc->maxseq_node); whc_delete_one (whc, oldn); } } - DDS_LOG(DDS_LC_WHC, "\n"); + TRACE ("\n"); } } else { - DDS_LOG(DDS_LC_WHC, " newkey"); + TRACE (" newkey"); /* Ignore unregisters, but insert everything else */ if (!(serdata->statusinfo & NN_STATUSINFO_UNREGISTER)) { - unsigned i; idxn = ddsrt_malloc (sizeof (*idxn) + whc->idxdepth * sizeof (idxn->hist[0])); - DDS_LOG(DDS_LC_WHC, " idxn %p", (void *)idxn); - ddsi_tkmap_instance_ref(tk); + TRACE (" idxn %p", (void *)idxn); + ddsi_tkmap_instance_ref (tk); idxn->iid = tk->m_iid; idxn->tk = tk; idxn->prune_seq = 0; idxn->headidx = 0; idxn->hist[0] = newn; - for (i = 1; i < whc->idxdepth; i++) + for (uint32_t i = 1; i < whc->idxdepth; i++) idxn->hist[i] = NULL; newn->idxnode = idxn; newn->idxnode_pos = 0; @@ -1225,24 +1227,24 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se } else { - DDS_LOG(DDS_LC_WHC, " unreg:skip"); + TRACE (" unreg:skip"); if (newn->seq <= max_drop_seq) { struct whc_node *prev_seq = newn->prev_seq; - DDS_LOG(DDS_LC_WHC, " unreg:seq <= max_drop_seq: delete newn\n"); + TRACE (" unreg:seq <= max_drop_seq: delete newn\n"); whc_delete_one (whc, newn); whc->maxseq_node = prev_seq; } } - DDS_LOG(DDS_LC_WHC, "\n"); + TRACE ("\n"); } ddsrt_mutex_unlock (&whc->lock); return 0; } -static void make_borrowed_sample(struct whc_borrowed_sample *sample, struct whc_node *whcn) +static void make_borrowed_sample (struct whc_borrowed_sample *sample, struct whc_node *whcn) { - assert(!whcn->borrowed); + assert (!whcn->borrowed); whcn->borrowed = 1; sample->seq = whcn->seq; sample->plist = whcn->plist; @@ -1258,11 +1260,11 @@ static bool whc_default_borrow_sample (const struct whc *whc_generic, seqno_t se struct whc_node *whcn; bool found; ddsrt_mutex_lock ((ddsrt_mutex_t *)&whc->lock); - if ((whcn = whc_findseq(whc, seq)) == NULL) + if ((whcn = whc_findseq (whc, seq)) == NULL) found = false; else { - make_borrowed_sample(sample, whcn); + make_borrowed_sample (sample, whcn); found = true; } ddsrt_mutex_unlock ((ddsrt_mutex_t *)&whc->lock); @@ -1275,11 +1277,11 @@ static bool whc_default_borrow_sample_key (const struct whc *whc_generic, const struct whc_node *whcn; bool found; ddsrt_mutex_lock ((ddsrt_mutex_t *)&whc->lock); - if ((whcn = whc_findkey(whc, serdata_key)) == NULL) + if ((whcn = whc_findkey (whc, serdata_key)) == NULL) found = false; else { - make_borrowed_sample(sample, whcn); + make_borrowed_sample (sample, whcn); found = true; } ddsrt_mutex_unlock ((ddsrt_mutex_t *)&whc->lock); @@ -1293,14 +1295,15 @@ static void return_sample_locked (struct whc_impl *whc, struct whc_borrowed_samp { /* data no longer present in WHC - that means ownership for serdata, plist shifted to the borrowed copy and "returning" it really becomes "destroying" it */ ddsi_serdata_unref (sample->serdata); - if (sample->plist) { + if (sample->plist) + { nn_plist_fini (sample->plist); ddsrt_free (sample->plist); } } else { - assert(whcn->borrowed); + assert (whcn->borrowed); whcn->borrowed = 0; if (update_retransmit_info) { @@ -1338,7 +1341,7 @@ static bool whc_default_sample_iter_borrow_next (struct whc_sample_iter *opaque_ if (!it->first) { seq = sample->seq; - return_sample_locked(whc, sample, false); + return_sample_locked (whc, sample, false); } else { @@ -1349,7 +1352,7 @@ static bool whc_default_sample_iter_borrow_next (struct whc_sample_iter *opaque_ valid = false; else { - make_borrowed_sample(sample, whcn); + make_borrowed_sample (sample, whcn); valid = true; } ddsrt_mutex_unlock (&whc->lock); diff --git a/src/core/ddsc/src/dds_whc_builtintopic.c b/src/core/ddsc/src/dds_whc_builtintopic.c index ded5cf3..b399705 100644 --- a/src/core/ddsc/src/dds_whc_builtintopic.c +++ b/src/core/ddsc/src/dds_whc_builtintopic.c @@ -19,6 +19,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_globals.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__serdata_builtintopic.h" #include "dds__whc_builtintopic.h" @@ -27,6 +28,7 @@ struct bwhc { struct whc common; enum ddsi_sertopic_builtintopic_type type; + const struct ephash *guid_hash; }; enum bwhc_iter_state { @@ -44,9 +46,7 @@ struct bwhc_iter { }; /* check that our definition of whc_sample_iter fits in the type that callers allocate */ -struct bwhc_sample_iter_sizecheck { - char fits_in_generic_type[sizeof(struct bwhc_iter) <= sizeof(struct whc_sample_iter) ? 1 : -1]; -}; +DDSRT_STATIC_ASSERT (sizeof (struct bwhc_iter) <= sizeof (struct whc_sample_iter)); static void bwhc_free (struct whc *whc_generic) { @@ -64,7 +64,7 @@ static void bwhc_sample_iter_init (const struct whc *whc_generic, struct whc_sam static bool is_visible (const struct entity_common *e) { const nn_vendorid_t vendorid = get_entity_vendorid (e); - return ddsi_plugin.builtintopic_is_visible (e->guid.entityid, e->onlylocal, vendorid); + return builtintopic_is_visible (e->gv->builtin_topic_interface, &e->guid, vendorid); } static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, struct whc_borrowed_sample *sample) @@ -92,7 +92,7 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str case DSBT_READER: kind = EK_READER; break; } assert (whc->type == DSBT_PARTICIPANT || kind != EK_PARTICIPANT); - ephash_enum_init (&it->it, kind); + ephash_enum_init (&it->it, whc->guid_hash, kind); it->st = BIS_LOCAL; /* FALLS THROUGH */ case BIS_LOCAL: @@ -115,7 +115,7 @@ static bool bwhc_sample_iter_borrow_next (struct whc_sample_iter *opaque_it, str case DSBT_READER: kind = EK_PROXY_READER; break; } assert (kind != EK_PARTICIPANT); - ephash_enum_init (&it->it, kind); + ephash_enum_init (&it->it, whc->guid_hash, kind); it->st = BIS_PROXY; /* FALLS THROUGH */ case BIS_PROXY: @@ -192,10 +192,11 @@ static const struct whc_ops bwhc_ops = { .free = bwhc_free }; -struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type) +struct whc *builtintopic_whc_new (enum ddsi_sertopic_builtintopic_type type, const struct ephash *guid_hash) { struct bwhc *whc = ddsrt_malloc (sizeof (*whc)); whc->common.ops = &bwhc_ops; whc->type = type; + whc->guid_hash = guid_hash; return (struct whc *) whc; } diff --git a/src/core/ddsc/src/dds_write.c b/src/core/ddsc/src/dds_write.c index 032141a..4115b0d 100644 --- a/src/core/ddsc/src/dds_write.c +++ b/src/core/ddsc/src/dds_write.c @@ -14,29 +14,28 @@ #include "dds__writer.h" #include "dds__write.h" #include "dds/ddsi/ddsi_tkmap.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_xmsg.h" +#include "dds/ddsi/q_rhc.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds__stream.h" -#include "dds__err.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/q_globals.h" dds_return_t dds_write (dds_entity_t writer, const void *data) { dds_return_t ret; - dds_retcode_t rc; dds_writer *wr; if (data == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + return ret; ret = dds_write_impl (wr, data, dds_time (), 0); dds_writer_unlock (wr); return ret; @@ -45,14 +44,13 @@ dds_return_t dds_write (dds_entity_t writer, const void *data) dds_return_t dds_writecdr (dds_entity_t writer, struct ddsi_serdata *serdata) { dds_return_t ret; - dds_retcode_t rc; dds_writer *wr; if (serdata == NULL) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + return ret; ret = dds_writecdr_impl (wr, serdata, dds_time (), 0); dds_writer_unlock (wr); return ret; @@ -61,14 +59,13 @@ dds_return_t dds_writecdr (dds_entity_t writer, struct ddsi_serdata *serdata) dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t timestamp) { dds_return_t ret; - dds_retcode_t rc; dds_writer *wr; if (data == NULL || timestamp < 0) - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); + return DDS_RETCODE_BAD_PARAMETER; - if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + if ((ret = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + return ret; ret = dds_write_impl (wr, data, timestamp, 0); dds_writer_unlock (wr); return ret; @@ -76,7 +73,7 @@ dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t tim static dds_return_t try_store (struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms) { - while (!(ddsi_plugin.rhc_plugin.rhc_store_fn) (rhc, pwr_info, payload, tk)) + while (! rhc_store (rhc, pwr_info, payload, tk)) { if (*max_block_ms > 0) { @@ -85,8 +82,7 @@ static dds_return_t try_store (struct rhc *rhc, const struct proxy_writer_info * } else { - DDS_ERROR ("The writer could not deliver data on time, probably due to a local reader resources being full\n"); - return DDS_ERRNO (DDS_RETCODE_TIMEOUT); + return DDS_RETCODE_TIMEOUT; } } return DDS_RETCODE_OK; @@ -101,12 +97,11 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay struct reader ** const rdary = wr->rdary.rdary; if (rdary[0]) { - dds_duration_t max_block_ms = nn_from_ddsi_duration (wr->xqos->reliability.max_blocking_time); + dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time; struct proxy_writer_info pwr_info; - unsigned i; make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos); - for (i = 0; rdary[i]; i++) { - DDS_TRACE ("reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid)); + for (uint32_t i = 0; rdary[i]; i++) { + DDS_CTRACE (&wr->e.gv->logconfig, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid)); if ((ret = try_store (rdary[i]->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK) break; } @@ -116,33 +111,39 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay else { /* When deleting, pwr is no longer accessible via the hash - tables, and consequently, a reader may be deleted without - it being possible to remove it from rdary. The primary - reason rdary exists is to avoid locking the proxy writer - but this is less of an issue when we are deleting it, so - we fall back to using the GUIDs so that we can deliver all - samples we received from it. As writer being deleted any - reliable samples that are rejected are simply discarded. */ + tables, and consequently, a reader may be deleted without + it being possible to remove it from rdary. The primary + reason rdary exists is to avoid locking the proxy writer + but this is less of an issue when we are deleting it, so + we fall back to using the GUIDs so that we can deliver all + samples we received from it. As writer being deleted any + reliable samples that are rejected are simply discarded. */ ddsrt_avl_iter_t it; struct pwr_rd_match *m; struct proxy_writer_info pwr_info; - dds_duration_t max_block_ms = nn_from_ddsi_duration (wr->xqos->reliability.max_blocking_time); + const struct ephash *gh = wr->e.gv->guid_hash; + dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time; ddsrt_mutex_unlock (&wr->rdary.rdary_lock); make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos); ddsrt_mutex_lock (&wr->e.lock); for (m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->local_readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it)) { struct reader *rd; - if ((rd = ephash_lookup_reader_guid (&m->rd_guid)) != NULL) + if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL) { - DDS_TRACE("reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid)); - /* Copied the return value ignore from DDSI deliver_user_data() function. */ + DDS_CTRACE (&wr->e.gv->logconfig, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid)); + /* Copied the return value ignore from DDSI deliver_user_data () function. */ if ((ret = try_store (rd->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK) break; } } ddsrt_mutex_unlock (&wr->e.lock); } + + if (ret == DDS_RETCODE_TIMEOUT) + { + DDS_CERROR (&wr->e.gv->logconfig, "The writer could not deliver data on time, probably due to a local reader resources being full\n"); + } return ret; } @@ -157,81 +158,72 @@ dds_return_t dds_write_impl (dds_writer *wr, const void * data, dds_time_t tstam int w_rc; if (data == NULL) - { - DDS_ERROR("No data buffer provided\n"); - return DDS_ERRNO (DDS_RETCODE_BAD_PARAMETER); - } + return DDS_RETCODE_BAD_PARAMETER; /* Check for topic filter */ if (wr->m_topic->filter_fn && !writekey) - if (!(wr->m_topic->filter_fn) (data, wr->m_topic->filter_ctx)) + if (! wr->m_topic->filter_fn (data, wr->m_topic->filter_ctx)) return DDS_RETCODE_OK; - thread_state_awake (ts1); + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); /* Serialize and write data or key */ d = ddsi_serdata_from_sample (ddsi_wr->topic, writekey ? SDK_KEY : SDK_DATA, data); - d->statusinfo = ((action & DDS_WR_DISPOSE_BIT) ? NN_STATUSINFO_DISPOSE : 0) | ((action & DDS_WR_UNREGISTER_BIT) ? NN_STATUSINFO_UNREGISTER : 0); + d->statusinfo = (((action & DDS_WR_DISPOSE_BIT) ? NN_STATUSINFO_DISPOSE : 0) | + ((action & DDS_WR_UNREGISTER_BIT) ? NN_STATUSINFO_UNREGISTER : 0)); d->timestamp.v = tstamp; ddsi_serdata_ref (d); - tk = ddsi_tkmap_lookup_instance_ref (d); + tk = ddsi_tkmap_lookup_instance_ref (wr->m_entity.m_domain->gv.m_tkmap, d); w_rc = write_sample_gc (ts1, wr->m_xp, ddsi_wr, d, tk); - if (w_rc >= 0) - { + if (w_rc >= 0) { /* Flush out write unless configured to batch */ - if (!config.whc_batch) + if (!wr->whc_batch) nn_xpack_send (wr->m_xp, false); ret = DDS_RETCODE_OK; - } else if (w_rc == Q_ERR_TIMEOUT) { - DDS_ERROR ("The writer could not deliver data on time, probably due to a reader resources being full\n"); - ret = DDS_ERRNO (DDS_RETCODE_TIMEOUT); - } else if (w_rc == Q_ERR_INVALID_DATA) { - DDS_ERROR ("Invalid data provided\n"); - ret = DDS_ERRNO (DDS_RETCODE_ERROR); + } else if (w_rc == DDS_RETCODE_TIMEOUT) { + ret = DDS_RETCODE_TIMEOUT; + } else if (w_rc == DDS_RETCODE_BAD_PARAMETER) { + ret = DDS_RETCODE_ERROR; } else { - DDS_ERROR ("Internal error\n"); - ret = DDS_ERRNO (DDS_RETCODE_ERROR); + ret = DDS_RETCODE_ERROR; } if (ret == DDS_RETCODE_OK) ret = deliver_locally (ddsi_wr, d, tk); ddsi_serdata_unref (d); - ddsi_tkmap_instance_unref (tk); + ddsi_tkmap_instance_unref (wr->m_entity.m_domain->gv.m_tkmap, tk); thread_state_asleep (ts1); return ret; } -dds_return_t dds_writecdr_impl_lowlevel (struct writer *ddsi_wr, struct nn_xpack *xp, struct ddsi_serdata *d) +dds_return_t dds_writecdr_impl_lowlevel (struct writer *ddsi_wr, struct nn_xpack *xp, struct ddsi_serdata *d, bool flush) { struct thread_state1 * const ts1 = lookup_thread_state (); struct ddsi_tkmap_instance * tk; int ret = DDS_RETCODE_OK; int w_rc; - thread_state_awake (ts1); + thread_state_awake (ts1, ddsi_wr->e.gv); ddsi_serdata_ref (d); - tk = ddsi_tkmap_lookup_instance_ref (d); + tk = ddsi_tkmap_lookup_instance_ref (ddsi_wr->e.gv->m_tkmap, d); w_rc = write_sample_gc (ts1, xp, ddsi_wr, d, tk); if (w_rc >= 0) { /* Flush out write unless configured to batch */ - if (!config.whc_batch && xp != NULL) + if (flush && xp != NULL) nn_xpack_send (xp, false); ret = DDS_RETCODE_OK; - } else if (w_rc == Q_ERR_TIMEOUT) { - DDS_ERROR ("The writer could not deliver data on time, probably due to a reader resources being full\n"); - ret = DDS_ERRNO(DDS_RETCODE_TIMEOUT); - } else if (w_rc == Q_ERR_INVALID_DATA) { - DDS_ERROR ("Invalid data provided\n"); - ret = DDS_ERRNO (DDS_RETCODE_ERROR); + } else if (w_rc == DDS_RETCODE_TIMEOUT) { + ret = DDS_RETCODE_TIMEOUT; + } else if (w_rc == DDS_RETCODE_BAD_PARAMETER) { + ret = DDS_RETCODE_ERROR; } else { - DDS_ERROR ("Internal error\n"); - ret = DDS_ERRNO (DDS_RETCODE_ERROR); + ret = DDS_RETCODE_ERROR; } if (ret == DDS_RETCODE_OK) ret = deliver_locally (ddsi_wr, d, tk); ddsi_serdata_unref (d); - ddsi_tkmap_instance_unref (tk); + ddsi_tkmap_instance_unref (ddsi_wr->e.gv->m_tkmap, tk); thread_state_asleep (ts1); return ret; } @@ -241,28 +233,22 @@ dds_return_t dds_writecdr_impl (dds_writer *wr, struct ddsi_serdata *d, dds_time if (wr->m_topic->filter_fn) abort (); /* Set if disposing or unregistering */ - d->statusinfo = ((action & DDS_WR_DISPOSE_BIT) ? NN_STATUSINFO_DISPOSE : 0) | ((action & DDS_WR_UNREGISTER_BIT) ? NN_STATUSINFO_UNREGISTER : 0); + d->statusinfo = (((action & DDS_WR_DISPOSE_BIT) ? NN_STATUSINFO_DISPOSE : 0) | + ((action & DDS_WR_UNREGISTER_BIT) ? NN_STATUSINFO_UNREGISTER : 0)); d->timestamp.v = tstamp; - return dds_writecdr_impl_lowlevel (wr->m_wr, wr->m_xp, d); -} - -void dds_write_set_batch (bool enable) -{ - config.whc_batch = enable ? 1 : 0; + return dds_writecdr_impl_lowlevel (wr->m_wr, wr->m_xp, d, !wr->whc_batch); } void dds_write_flush (dds_entity_t writer) { struct thread_state1 * const ts1 = lookup_thread_state (); dds_writer *wr; - dds_retcode_t rc; - thread_state_awake (ts1); - if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) - DDS_ERROR ("Error occurred on locking writer\n"); - else + dds_return_t rc; + if ((rc = dds_writer_lock (writer, &wr)) == DDS_RETCODE_OK) { + thread_state_awake (ts1, &wr->m_entity.m_domain->gv); nn_xpack_send (wr->m_xp, true); + thread_state_asleep (ts1); dds_writer_unlock (wr); } - thread_state_asleep (ts1); } diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index f144e35..5908116 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -13,6 +13,7 @@ #include "dds/dds.h" #include "dds/version.h" +#include "dds/ddsrt/static_assert.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_globals.h" #include "dds/ddsi/q_entity.h" @@ -20,45 +21,25 @@ #include "dds/ddsi/q_xmsg.h" #include "dds__writer.h" #include "dds__listener.h" -#include "dds__qos.h" -#include "dds__err.h" #include "dds__init.h" #include "dds__publisher.h" #include "dds__topic.h" +#include "dds__get_status.h" +#include "dds__qos.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__whc.h" -DECL_ENTITY_LOCK_UNLOCK(extern inline, dds_writer) +DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_writer) #define DDS_WRITER_STATUS_MASK \ - DDS_LIVELINESS_LOST_STATUS |\ - DDS_OFFERED_DEADLINE_MISSED_STATUS |\ - DDS_OFFERED_INCOMPATIBLE_QOS_STATUS |\ - DDS_PUBLICATION_MATCHED_STATUS + (DDS_LIVELINESS_LOST_STATUS |\ + DDS_OFFERED_DEADLINE_MISSED_STATUS |\ + DDS_OFFERED_INCOMPATIBLE_QOS_STATUS |\ + DDS_PUBLICATION_MATCHED_STATUS) -static dds_return_t -dds_writer_instance_hdl( - dds_entity *e, - dds_instance_handle_t *i) +static dds_return_t dds_writer_status_validate (uint32_t mask) { - assert(e); - assert(i); - *i = (dds_instance_handle_t)writer_instance_id(&e->m_guid); - return DDS_RETCODE_OK; -} - -static dds_return_t -dds_writer_status_validate( - uint32_t mask) -{ - dds_return_t ret = DDS_RETCODE_OK; - - if (mask & ~(DDS_WRITER_STATUS_MASK)) { - DDS_ERROR("Invalid status mask\n"); - ret = DDS_ERRNO(DDS_RETCODE_BAD_PARAMETER); - } - - return ret; + return (mask & ~DDS_WRITER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } /* @@ -77,7 +58,7 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data) { /* Release the initial claim that was done during the create. This * will indicate that further API deletion is now possible. */ - dds_handle_release (&entity->m_hdllink); + dds_handle_unpin (&entity->m_hdllink); return; } @@ -94,7 +75,7 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data) /* Reset the status for possible Listener call. * When a listener is not called, the status will be set (again). */ - dds_entity_status_reset (entity, 1u << status_id); + dds_entity_status_reset (entity, (status_mask_t) (1u << status_id)); /* Update status metrics. */ dds_writer * const wr = (dds_writer *) entity; @@ -166,7 +147,7 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data) } else { - dds_entity_status_set (entity, 1u << status_id); + dds_entity_status_set (entity, (status_mask_t) (1u << status_id)); } entity->m_cb_count--; @@ -174,422 +155,208 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data) ddsrt_mutex_unlock (&entity->m_observers_lock); } -static uint32_t -get_bandwidth_limit( - nn_transport_priority_qospolicy_t transport_priority) +static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transport_priority) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - struct config_channel_listelem *channel = find_channel (transport_priority); + struct config_channel_listelem *channel = find_channel (&config, transport_priority); return channel->data_bandwidth_limit; #else - (void)transport_priority; + (void) transport_priority; return 0; #endif } -static dds_return_t -dds_writer_close( - dds_entity *e) +static dds_return_t dds_writer_close (dds_entity *e) ddsrt_nonnull_all; + +static dds_return_t dds_writer_close (dds_entity *e) { - dds_return_t ret = DDS_RETCODE_OK; - dds_writer *wr = (dds_writer*)e; + dds_writer * const wr = (dds_writer *) e; + dds_return_t ret; + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + nn_xpack_send (wr->m_xp, false); + if ((ret = delete_writer (&e->m_domain->gv, &e->m_guid)) < 0) + ret = DDS_RETCODE_ERROR; + thread_state_asleep (lookup_thread_state ()); + return ret; +} - assert(e); +static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all; - thread_state_awake (lookup_thread_state ()); - nn_xpack_send (wr->m_xp, false); - if (delete_writer (&e->m_guid) != 0) { - DDS_ERROR("Internal error"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - } +static dds_return_t dds_writer_delete (dds_entity *e) +{ + dds_writer * const wr = (dds_writer *) e; + dds_return_t ret; + /* FIXME: not freeing WHC here because it is owned by the DDSI entity */ + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + nn_xpack_free (wr->m_xp); + thread_state_asleep (lookup_thread_state ()); + if ((ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK) + { + ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true); + if (ret == DDS_RETCODE_BAD_PARAMETER) + ret = DDS_RETCODE_OK; + } + return ret; +} + +static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled) +{ + /* note: e->m_qos is still the old one to allow for failure here */ + if (enabled) + { + struct writer *wr; + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + if ((wr = ephash_lookup_writer_guid (e->m_domain->gv.guid_hash, &e->m_guid)) != NULL) + update_writer_qos (wr, qos); thread_state_asleep (lookup_thread_state ()); - return ret; + } + return DDS_RETCODE_OK; } -static dds_return_t -dds_writer_delete( - dds_entity *e) -{ - dds_writer *wr = (dds_writer*)e; - dds_return_t ret; - /* FIXME: not freeing WHC here because it is owned by the DDSI entity */ - thread_state_awake (lookup_thread_state ()); - nn_xpack_free(wr->m_xp); - thread_state_asleep (lookup_thread_state ()); - ret = dds_delete(wr->m_topic->m_entity.m_hdllink.hdl); - if(ret == DDS_RETCODE_OK){ - ret = dds_delete_impl(e->m_parent->m_hdllink.hdl, true); - if(dds_err_nr(ret) == DDS_RETCODE_BAD_PARAMETER){ - ret = DDS_RETCODE_OK; - } - } - return ret; -} - - -static dds_return_t -dds_writer_qos_validate( - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = DDS_RETCODE_OK; - - assert(qos); - - /* Check consistency. */ - if(dds_qos_validate_common(qos) != true){ - DDS_ERROR("Provided inconsistent QoS policy\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if((qos->present & QP_USER_DATA) && validate_octetseq(&qos->user_data) != true){ - DDS_ERROR("User Data QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_DURABILITY_SERVICE) && validate_durability_service_qospolicy(&qos->durability_service) != 0){ - DDS_ERROR("Durability service QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_LIFESPAN) && validate_duration(&qos->lifespan.duration) != 0){ - DDS_ERROR("Lifespan QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if ((qos->present & QP_HISTORY) && (qos->present & QP_RESOURCE_LIMITS) && (validate_history_and_resource_limits(&qos->history, &qos->resource_limits) != 0)){ - DDS_ERROR("Resource limits QoS policy is inconsistent and caused an error\n"); - ret = DDS_ERRNO(DDS_RETCODE_INCONSISTENT_POLICY); - } - if(ret == DDS_RETCODE_OK && enabled) { - ret = dds_qos_validate_mutable_common(qos); - } - return ret; -} - -static dds_return_t -dds_writer_qos_set( - dds_entity *e, - const dds_qos_t *qos, - bool enabled) -{ - dds_return_t ret = dds_writer_qos_validate(qos, enabled); - if (ret == DDS_RETCODE_OK) { - /* - * TODO: CHAM-95: DDSI does not support changing QoS policies. - * - * Only Ownership is required for the minimum viable product. This seems - * to be the only QoS policy that DDSI supports changes on. - */ - if (qos->present & QP_OWNERSHIP_STRENGTH) { - dds_ownership_kind_t kind; - /* check for ownership before updating, ownership strength is applicable only if - * writer is exclusive */ - dds_qget_ownership (e->m_qos, &kind); - - if (kind == DDS_OWNERSHIP_EXCLUSIVE) { - struct writer * ddsi_wr = ((dds_writer*)e)->m_wr; - - dds_qset_ownership_strength (e->m_qos, qos->ownership_strength.value); - - thread_state_awake (lookup_thread_state ()); - - /* FIXME: with QoS changes being unsupported by the underlying stack I wonder what will happen; locking the underlying DDSI writer is of doubtful value as well */ - ddsrt_mutex_lock (&ddsi_wr->e.lock); - if (qos->ownership_strength.value != ddsi_wr->xqos->ownership_strength.value) { - ddsi_wr->xqos->ownership_strength.value = qos->ownership_strength.value; - } - ddsrt_mutex_unlock (&ddsi_wr->e.lock); - thread_state_asleep (lookup_thread_state ()); - } else { - DDS_ERROR("Setting ownership strength doesn't make sense when the ownership is shared\n"); - ret = DDS_ERRNO(DDS_RETCODE_ERROR); - } - } else { - if (enabled) { - DDS_ERROR(DDS_PROJECT_NAME" does not support changing QoS policies yet\n"); - ret = DDS_ERRNO(DDS_RETCODE_UNSUPPORTED); - } - } - } - return ret; -} - -static struct whc *make_whc(const dds_qos_t *qos) +static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos) { bool handle_as_transient_local; - unsigned hdepth, tldepth; + uint32_t hdepth, tldepth; /* Construct WHC -- if aggressive_keep_last1 is set, the WHC will - drop all samples for which a later update is available. This - forces it to maintain a tlidx. */ - handle_as_transient_local = (qos->durability.kind == NN_TRANSIENT_LOCAL_DURABILITY_QOS); - if (qos->history.kind == NN_KEEP_ALL_HISTORY_QOS) + drop all samples for which a later update is available. This + forces it to maintain a tlidx. */ + handle_as_transient_local = (qos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); + if (qos->history.kind == DDS_HISTORY_KEEP_ALL) hdepth = 0; else - hdepth = (unsigned)qos->history.depth; - if (handle_as_transient_local) { - if (qos->durability_service.history.kind == NN_KEEP_ALL_HISTORY_QOS) + hdepth = (unsigned) qos->history.depth; + if (!handle_as_transient_local) + tldepth = 0; + else + { + if (qos->durability_service.history.kind == DDS_HISTORY_KEEP_ALL) tldepth = 0; else - tldepth = (unsigned)qos->durability_service.history.depth; - } else { - tldepth = 0; + tldepth = (unsigned) qos->durability_service.history.depth; } - return whc_new (handle_as_transient_local, hdepth, tldepth); + return whc_new (&dom->gv, handle_as_transient_local, hdepth, tldepth); } +const struct dds_entity_deriver dds_entity_deriver_writer = { + .close = dds_writer_close, + .delete = dds_writer_delete, + .set_qos = dds_writer_qos_set, + .validate_status = dds_writer_status_validate +}; -dds_entity_t -dds_create_writer( - dds_entity_t participant_or_publisher, - dds_entity_t topic, - const dds_qos_t *qos, - const dds_listener_t *listener) +dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener) { - dds_retcode_t rc; - dds_qos_t * wqos; - dds_writer * wr; - dds_entity_t writer; - dds_publisher * pub = NULL; - dds_topic * tp; - dds_entity_t publisher; - ddsi_tran_conn_t conn = gv.data_conn_uc; - dds_return_t ret; + dds_return_t rc; + dds_qos_t *wqos; + dds_writer *wr; + dds_entity_t writer; + dds_publisher *pub = NULL; + dds_topic *tp; + dds_entity_t publisher; - { - dds_entity *p_or_p; - if ((rc = dds_entity_claim (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK) { - return DDS_ERRNO (rc); - } - if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT) { - publisher = dds_create_publisher(participant_or_publisher, qos, NULL); - } else { - publisher = participant_or_publisher; - } - dds_entity_release (p_or_p); - } + { + dds_entity *p_or_p; + if ((rc = dds_entity_pin (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK) + return rc; + if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT) + publisher = dds_create_publisher(participant_or_publisher, qos, NULL); + else + publisher = participant_or_publisher; + dds_entity_unpin (p_or_p); + } - if ((rc = dds_publisher_lock(publisher, &pub)) != DDS_RETCODE_OK) { - writer = DDS_ERRNO(rc); - goto err_pub_lock; - } + if ((rc = dds_publisher_lock (publisher, &pub)) != DDS_RETCODE_OK) + return rc; - if (publisher != participant_or_publisher) { - pub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT; - } + ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.data_conn_uc; + if (publisher != participant_or_publisher) + pub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT; - rc = dds_topic_lock(topic, &tp); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking topic\n"); - writer = DDS_ERRNO(rc); - goto err_tp_lock; - } - assert(tp->m_stopic); - assert(pub->m_entity.m_domain == tp->m_entity.m_domain); + if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK) + goto err_tp_lock; - /* Merge Topic & Publisher qos */ - wqos = dds_create_qos(); - if (qos) { - /* Only returns failure when one of the qos args is NULL, which - * is not the case here. */ - (void)dds_copy_qos(wqos, qos); - } + assert (tp->m_stopic); + assert (pub->m_entity.m_domain == tp->m_entity.m_domain); - if (pub->m_entity.m_qos) { - dds_merge_qos(wqos, pub->m_entity.m_qos); - } + /* Merge Topic & Publisher qos */ + wqos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK); + if (pub->m_entity.m_qos) + nn_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); + if (tp->m_entity.m_qos) + nn_xqos_mergein_missing (wqos, tp->m_entity.m_qos, ~(uint64_t)0); + nn_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0); - if (tp->m_entity.m_qos) { - /* merge topic qos data to writer qos */ - dds_merge_qos(wqos, tp->m_entity.m_qos); - } - nn_xqos_mergein_missing(wqos, &gv.default_xqos_wr); + if ((rc = nn_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0) + { + dds_delete_qos(wqos); + goto err_bad_qos; + } - ret = dds_writer_qos_validate(wqos, false); - if (ret != 0) { - dds_delete_qos(wqos); - writer = ret; - goto err_bad_qos; - } + /* Create writer */ + wr = dds_alloc (sizeof (*wr)); + writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, wqos, listener, DDS_WRITER_STATUS_MASK); - /* Create writer */ - wr = dds_alloc(sizeof (*wr)); - writer = dds_entity_init(&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, wqos, listener, DDS_WRITER_STATUS_MASK); + wr->m_topic = tp; + dds_entity_add_ref_locked (&tp->m_entity); + wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), pub->m_entity.m_domain->gv.config.xpack_send_async); + wr->m_whc = make_whc (pub->m_entity.m_domain, wqos); + wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch; - wr->m_topic = tp; - dds_entity_add_ref_nolock(&tp->m_entity); - wr->m_xp = nn_xpack_new(conn, get_bandwidth_limit(wqos->transport_priority), config.xpack_send_async); - wr->m_entity.m_deriver.close = dds_writer_close; - wr->m_entity.m_deriver.delete = dds_writer_delete; - wr->m_entity.m_deriver.set_qos = dds_writer_qos_set; - wr->m_entity.m_deriver.validate_status = dds_writer_status_validate; - wr->m_entity.m_deriver.get_instance_hdl = dds_writer_instance_hdl; - wr->m_whc = make_whc (wqos); + /* Extra claim of this writer to make sure that the delete waits until DDSI + * has deleted its writer as well. This can be known through the callback. */ + dds_handle_repin (&wr->m_entity.m_hdllink); - /* Extra claim of this writer to make sure that the delete waits until DDSI - * has deleted its writer as well. This can be known through the callback. */ - dds_handle_claim_inc (&wr->m_entity.m_hdllink); + ddsrt_mutex_unlock (&tp->m_entity.m_mutex); + ddsrt_mutex_unlock (&pub->m_entity.m_mutex); - ddsrt_mutex_unlock (&tp->m_entity.m_mutex); - ddsrt_mutex_unlock (&pub->m_entity.m_mutex); + thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv); + rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pub->m_entity.m_participant->m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); + ddsrt_mutex_lock (&pub->m_entity.m_mutex); + ddsrt_mutex_lock (&tp->m_entity.m_mutex); + assert(rc == DDS_RETCODE_OK); + thread_state_asleep (lookup_thread_state ()); - thread_state_awake (lookup_thread_state ()); - ret = new_writer(&wr->m_wr, &wr->m_entity.m_guid, NULL, &pub->m_entity.m_participant->m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); - ddsrt_mutex_lock (&pub->m_entity.m_mutex); - ddsrt_mutex_lock (&tp->m_entity.m_mutex); - assert(ret == DDS_RETCODE_OK); - thread_state_asleep (lookup_thread_state ()); - dds_topic_unlock(tp); - dds_publisher_unlock(pub); - return writer; + wr->m_entity.m_iid = get_entity_instance_id (&wr->m_entity.m_domain->gv, &wr->m_entity.m_guid); + dds_entity_register_child (&pub->m_entity, &wr->m_entity); + + dds_topic_unlock (tp); + dds_publisher_unlock (pub); + return writer; err_bad_qos: - dds_topic_unlock(tp); + dds_topic_unlock (tp); err_tp_lock: - dds_publisher_unlock(pub); - if((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){ - (void)dds_delete(publisher); - } -err_pub_lock: - return writer; + dds_publisher_unlock (pub); + if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){ + (void )dds_delete (publisher); + } + return rc; } -dds_entity_t -dds_get_publisher( - dds_entity_t writer) +dds_entity_t dds_get_publisher (dds_entity_t writer) { dds_entity *e; - dds_retcode_t rc; - if ((rc = dds_entity_claim (writer, &e)) != DDS_RETCODE_OK) - return DDS_ERRNO (rc); + dds_return_t rc; + if ((rc = dds_entity_pin (writer, &e)) != DDS_RETCODE_OK) + return rc; else { dds_entity_t pubh; if (dds_entity_kind (e) != DDS_KIND_WRITER) - pubh = DDS_ERRNO (DDS_RETCODE_ILLEGAL_OPERATION); + pubh = DDS_RETCODE_ILLEGAL_OPERATION; else { assert (dds_entity_kind (e->m_parent) == DDS_KIND_PUBLISHER); pubh = e->m_parent->m_hdllink.hdl; } - dds_entity_release (e); + dds_entity_unpin (e); return pubh; } } -dds_return_t -dds_get_publication_matched_status ( - dds_entity_t writer, - dds_publication_matched_status_t * status) -{ - dds_retcode_t rc; - dds_writer *wr; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking writer\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = wr->m_publication_matched_status; - } - ddsrt_mutex_lock (&wr->m_entity.m_observers_lock); - if (wr->m_entity.m_status_enable & DDS_PUBLICATION_MATCHED_STATUS) { - wr->m_publication_matched_status.total_count_change = 0; - wr->m_publication_matched_status.current_count_change = 0; - dds_entity_status_reset(&wr->m_entity, DDS_PUBLICATION_MATCHED_STATUS); - } - ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock); - dds_writer_unlock(wr); -fail: - return ret; -} - -dds_return_t -dds_get_liveliness_lost_status ( - dds_entity_t writer, - dds_liveliness_lost_status_t * status) -{ - dds_retcode_t rc; - dds_writer *wr; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking writer\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = wr->m_liveliness_lost_status; - } - ddsrt_mutex_lock (&wr->m_entity.m_observers_lock); - if (wr->m_entity.m_status_enable & DDS_LIVELINESS_LOST_STATUS) { - wr->m_liveliness_lost_status.total_count_change = 0; - dds_entity_status_reset(&wr->m_entity, DDS_LIVELINESS_LOST_STATUS); - } - ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock); - dds_writer_unlock(wr); -fail: - return ret; -} - -dds_return_t -dds_get_offered_deadline_missed_status( - dds_entity_t writer, - dds_offered_deadline_missed_status_t *status) -{ - dds_retcode_t rc; - dds_writer *wr; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking writer\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = wr->m_offered_deadline_missed_status; - } - ddsrt_mutex_lock (&wr->m_entity.m_observers_lock); - if (wr->m_entity.m_status_enable & DDS_OFFERED_DEADLINE_MISSED_STATUS) { - wr->m_offered_deadline_missed_status.total_count_change = 0; - dds_entity_status_reset(&wr->m_entity, DDS_OFFERED_DEADLINE_MISSED_STATUS); - } - ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock); - dds_writer_unlock(wr); -fail: - return ret; -} - -dds_return_t -dds_get_offered_incompatible_qos_status ( - dds_entity_t writer, - dds_offered_incompatible_qos_status_t * status) -{ - dds_retcode_t rc; - dds_writer *wr; - dds_return_t ret = DDS_RETCODE_OK; - - rc = dds_writer_lock(writer, &wr); - if (rc != DDS_RETCODE_OK) { - DDS_ERROR("Error occurred on locking writer\n"); - ret = DDS_ERRNO(rc); - goto fail; - } - /* status = NULL, application do not need the status, but reset the counter & triggered bit */ - if (status) { - *status = wr->m_offered_incompatible_qos_status; - } - ddsrt_mutex_lock (&wr->m_entity.m_observers_lock); - if (wr->m_entity.m_status_enable & DDS_OFFERED_INCOMPATIBLE_QOS_STATUS) { - wr->m_offered_incompatible_qos_status.total_count_change = 0; - dds_entity_status_reset(&wr->m_entity, DDS_OFFERED_INCOMPATIBLE_QOS_STATUS); - } - ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock); - dds_writer_unlock(wr); -fail: - return ret; -} +DDS_GET_STATUS(writer, publication_matched, PUBLICATION_MATCHED, total_count_change, current_count_change) +DDS_GET_STATUS(writer, liveliness_lost, LIVELINESS_LOST, total_count_change) +DDS_GET_STATUS(writer, offered_deadline_missed, OFFERED_DEADLINE_MISSED, total_count_change) +DDS_GET_STATUS(writer, offered_incompatible_qos, OFFERED_INCOMPATIBLE_QOS, total_count_change) diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c index b751a2c..76f92b0 100644 --- a/src/core/ddsc/tests/config.c +++ b/src/core/ddsc/tests/config.c @@ -49,7 +49,7 @@ static void config__check_env( } if ( !env_ok ) { - dds_retcode_t r; + dds_return_t r; r = ddsrt_setenv(env_variable, expected_value); CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); diff --git a/src/core/ddsc/tests/config_simple_udp.xml b/src/core/ddsc/tests/config_simple_udp.xml index 52eb377..c333d64 100644 --- a/src/core/ddsc/tests/config_simple_udp.xml +++ b/src/core/ddsc/tests/config_simple_udp.xml @@ -13,24 +13,23 @@ - - 3 + + + 127.0.0.1 + true + true + + + lax + + + warning + vortexdds-.${NON_EXISTENT_ENV_VARIABLE:-l}${CYCLONEDDS_URI:+o}g + + + ${MAX_PARTICIPANTS} + 100 ms + + - - 127.0.0.1 - true - true - - - lax - - - warning - vortexdds-.${NON_EXISTENT_ENV_VARIABLE:-l}${CYCLONEDDS_URI:+o}g - - - ${MAX_PARTICIPANTS} - 100 ms - - diff --git a/src/core/ddsc/tests/dispose.c b/src/core/ddsc/tests/dispose.c index 0e10c60..ef6435f 100644 --- a/src/core/ddsc/tests/dispose.c +++ b/src/core/ddsc/tests/dispose.c @@ -153,7 +153,7 @@ CU_Test(ddsc_writedispose, deleted, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose(g_writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -164,7 +164,7 @@ CU_Test(ddsc_writedispose, null, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose(g_writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -174,13 +174,12 @@ CU_TheoryDataPoints(ddsc_writedispose, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_writedispose, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose(writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -194,7 +193,7 @@ CU_Theory((dds_entity_t *writer), ddsc_writedispose, non_writers, .init=disposin DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose(*writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -290,7 +289,7 @@ CU_Test(ddsc_writedispose, timeout, .init=disposing_init, .fini=disposing_fini) ret = dds_writedispose(g_writer, &newInstance1); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_writedispose(g_writer, &newInstance2); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_TIMEOUT); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_TIMEOUT); } /*************************************************************************************************/ @@ -310,7 +309,7 @@ CU_Test(ddsc_writedispose_ts, deleted, .init=disposing_init, .fini=disposing_fin DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose_ts(g_writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -321,7 +320,7 @@ CU_Test(ddsc_writedispose_ts, null, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose_ts(g_writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -335,7 +334,7 @@ CU_Test(ddsc_writedispose_ts, timeout, .init=disposing_init, .fini=disposing_fin ret = dds_writedispose_ts(g_writer, &newInstance1, g_present); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_writedispose_ts(g_writer, &newInstance2, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_TIMEOUT); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_TIMEOUT); } /*************************************************************************************************/ @@ -345,13 +344,12 @@ CU_TheoryDataPoints(ddsc_writedispose_ts, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_writedispose_ts, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose_ts(writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -365,7 +363,7 @@ CU_Theory((dds_entity_t *writer), ddsc_writedispose_ts, non_writers, .init=dispo DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_writedispose_ts(*writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -510,7 +508,7 @@ CU_Test(ddsc_dispose, deleted, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose(g_writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -521,7 +519,7 @@ CU_Test(ddsc_dispose, null, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose(g_writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -535,7 +533,7 @@ CU_Test(ddsc_dispose, timeout, .init=disposing_init, .fini=disposing_fini) ret = dds_dispose(g_writer, &newInstance1); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_dispose(g_writer, &newInstance2); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_TIMEOUT); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_TIMEOUT); } /*************************************************************************************************/ @@ -545,13 +543,12 @@ CU_TheoryDataPoints(ddsc_dispose, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_dispose, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose(writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -563,9 +560,10 @@ CU_Theory((dds_entity_t *writer), ddsc_dispose, non_writers, .init=disposing_ini { dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ - ret = dds_dispose(*writer, NULL); + /* pass a non-null pointer that'll trigger a crash if it is read */ + ret = dds_dispose(*writer, (void *) 1); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -665,7 +663,7 @@ CU_Test(ddsc_dispose_ts, deleted, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose_ts(g_writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); /* Disable SAL warning on intentional misuse of the API */ - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -676,7 +674,7 @@ CU_Test(ddsc_dispose_ts, null, .init=disposing_init, .fini=disposing_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose_ts(g_writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -690,7 +688,7 @@ CU_Test(ddsc_dispose_ts, timeout, .init=disposing_init, .fini=disposing_fini) ret = dds_dispose_ts(g_writer, &newInstance1, g_present); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_dispose_ts(g_writer, &newInstance2, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_TIMEOUT); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_TIMEOUT); } /*************************************************************************************************/ @@ -700,13 +698,12 @@ CU_TheoryDataPoints(ddsc_dispose_ts, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_dispose_ts, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_dispose_ts(writer, NULL, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -718,9 +715,10 @@ CU_Theory((dds_entity_t *writer), ddsc_dispose_ts, non_writers, .init=disposing_ { dds_return_t ret; DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ - ret = dds_dispose_ts(*writer, NULL, g_present); + /* pass a non-null pointer that'll trigger a crash if it is read */ + ret = dds_dispose_ts(*writer, (void *) 1, g_present); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -861,7 +859,7 @@ CU_Test(ddsc_dispose_ih, deleted, .init=disposing_init, .fini=disposing_fini) dds_return_t ret; dds_delete(g_writer); ret = dds_dispose_ih(g_writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -873,7 +871,7 @@ CU_Theory((dds_instance_handle_t handle), ddsc_dispose_ih, invalid_handles, .ini { dds_return_t ret; ret = dds_dispose_ih(g_writer, handle); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -883,11 +881,10 @@ CU_TheoryDataPoints(ddsc_dispose_ih, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_dispose_ih, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_dispose_ih(writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -899,7 +896,7 @@ CU_Theory((dds_entity_t *writer), ddsc_dispose_ih, non_writers, .init=disposing_ { dds_return_t ret; ret = dds_dispose_ih(*writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -959,7 +956,7 @@ CU_Test(ddsc_dispose_ih_ts, deleted, .init=disposing_init, .fini=disposing_fini) dds_return_t ret; dds_delete(g_writer); ret = dds_dispose_ih_ts(g_writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -971,7 +968,7 @@ CU_Theory((dds_instance_handle_t handle), ddsc_dispose_ih_ts, invalid_handles, . { dds_return_t ret; ret = dds_dispose_ih_ts(g_writer, handle, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -981,11 +978,10 @@ CU_TheoryDataPoints(ddsc_dispose_ih_ts, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_dispose_ih_ts, invalid_writers, .init=disposing_init, .fini=disposing_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_dispose_ih_ts(writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -997,7 +993,7 @@ CU_Theory((dds_entity_t *writer), ddsc_dispose_ih_ts, non_writers, .init=disposi { dds_return_t ret; ret = dds_dispose_ih_ts(*writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/entity_api.c b/src/core/ddsc/tests/entity_api.c index 8befa14..d757f08 100644 --- a/src/core/ddsc/tests/entity_api.c +++ b/src/core/ddsc/tests/entity_api.c @@ -23,10 +23,8 @@ static dds_entity_t entity = -1; -#define cu_assert_status_eq(s1, s2) CU_ASSERT_FATAL(dds_err_nr(s1)== s2) - /* Fixture to create prerequisite entity */ -void create_entity(void) +static void create_entity(void) { CU_ASSERT_EQUAL_FATAL(entity, -1); entity = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); @@ -34,11 +32,11 @@ void create_entity(void) } /* Fixture to delete prerequisite entity */ -void delete_entity(void) +static void delete_entity(void) { CU_ASSERT_FATAL(entity > 0); dds_return_t ret = dds_delete(entity); - cu_assert_status_eq(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); entity = -1; } @@ -55,20 +53,20 @@ CU_Test(ddsc_entity, enable, .init = create_entity, .fini = delete_entity) /* Check enabling with bad parameters. */ status = dds_enable(0); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Check actual enabling. */ /* TODO: CHAM-96: Check enabling. status = dds_enable(&entity); - cu_assert_status_eq(status, dds_err_nr(DDS_RETCODE_OK), "dds_enable (delayed enable)"); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK, "dds_enable (delayed enable)"); */ /* Check re-enabling (should be a noop). */ status = dds_enable(entity); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); } -void entity_qos_get_set(dds_entity_t e, const char* info) +static void entity_qos_get_set(dds_entity_t e, const char* info) { dds_return_t status; dds_qos_t *qos = dds_create_qos(); @@ -77,10 +75,10 @@ void entity_qos_get_set(dds_entity_t e, const char* info) /* Get QoS. */ status = dds_get_qos (e, qos); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); status = dds_set_qos (e, qos); /* Doesn't change anything, so no need to forbid. But we return NOT_SUPPORTED anyway for now*/ - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_delete_qos(qos); } @@ -95,19 +93,19 @@ CU_Test(ddsc_entity, qos, .init = create_entity, .fini = delete_entity) /* Check getting QoS with bad parameters. */ status = dds_get_qos (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_qos (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_qos (0, qos); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Check setting QoS with bad parameters. */ status = dds_set_qos (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_set_qos (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_set_qos (0, qos); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Check set/get with entity without initial qos. */ entity_qos_get_set(entity, "{without initial qos}"); @@ -145,15 +143,15 @@ CU_Test(ddsc_entity, listener, .init = create_entity, .fini = delete_entity) /* Check getting Listener with bad parameters. */ status = dds_get_listener (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_listener (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_listener (0, l1); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Get Listener, which should be unset. */ status = dds_get_listener (entity, l1); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_lget_liveliness_changed (l1, (dds_on_liveliness_changed_fn*)&cb1); CU_ASSERT_EQUAL_FATAL(cb1, DDS_LUNSET); dds_lget_requested_deadline_missed (l1, (dds_on_requested_deadline_missed_fn*)&cb1); @@ -165,15 +163,15 @@ CU_Test(ddsc_entity, listener, .init = create_entity, .fini = delete_entity) /* Check setting Listener with bad parameters. */ status = dds_set_listener (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_set_listener (0, l2); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Getting after setting should return set listener. */ status = dds_set_listener (entity, l2); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); status = dds_get_listener (entity, l1); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_lget_liveliness_changed (l1, (dds_on_liveliness_changed_fn*)&cb1); dds_lget_liveliness_changed (l2, (dds_on_liveliness_changed_fn*)&cb2); CU_ASSERT_EQUAL_FATAL(cb1, cb2); @@ -189,9 +187,9 @@ CU_Test(ddsc_entity, listener, .init = create_entity, .fini = delete_entity) /* Reset listener. */ status = dds_set_listener (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); status = dds_get_listener (entity, l2); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_lget_liveliness_changed (l2, (dds_on_liveliness_changed_fn*)&cb2); CU_ASSERT_EQUAL_FATAL(cb2, DDS_LUNSET); dds_lget_requested_deadline_missed (l2, (dds_on_requested_deadline_missed_fn*)&cb2); @@ -215,46 +213,46 @@ CU_Test(ddsc_entity, status, .init = create_entity, .fini = delete_entity) /* Check getting Status with bad parameters. */ status1 = dds_get_status_mask (0, NULL); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_get_status_mask (entity, NULL); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_get_status_mask (0, &s1); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); /* Get Status, which should be 0 for a participant. */ status1 = dds_get_status_mask (entity, &s1); - cu_assert_status_eq(status1, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(s1, 0); /* Check setting Status with bad parameters. */ status1 = dds_set_status_mask (0, 0); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); /* I shouldn't be able to set statuses on a participant. */ status1 = dds_set_status_mask (entity, 0); - cu_assert_status_eq(status1, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); status1 = dds_set_status_mask (entity, DDS_DATA_AVAILABLE_STATUS); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); /* Check getting Status changes with bad parameters. */ status1 = dds_get_status_changes (0, NULL); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_get_status_changes (entity, NULL); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_get_status_changes (0, &s1); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_get_status_changes (entity, &s1); - cu_assert_status_eq(status1, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); /* Status read and take shouldn't work either. */ status1 = dds_read_status (0, &s1, 0); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_read_status (entity, &s1, 0); - cu_assert_status_eq(status1, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); status1 = dds_take_status (0, &s1, 0); - cu_assert_status_eq(status1, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_BAD_PARAMETER); status1 = dds_take_status (entity, &s1, 0); - cu_assert_status_eq(status1, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); } @@ -268,15 +266,15 @@ CU_Test(ddsc_entity, instance_handle, .init = create_entity, .fini = delete_enti /* Check getting Handle with bad parameters. */ status = dds_get_instance_handle (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_instance_handle (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_instance_handle (0, &hdl); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Get Instance Handle, which should not be 0 for a participant. */ status = dds_get_instance_handle (entity, &hdl); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); CU_ASSERT_NOT_EQUAL_FATAL(hdl, 0); } @@ -290,17 +288,17 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity) /* Check getting Parent with bad parameters. */ par = dds_get_parent (0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(par), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(par, DDS_RETCODE_BAD_PARAMETER); /* Get Parent, a participant doesn't have a parent. */ par = dds_get_parent (entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(par), DDS_ENTITY_NIL); + CU_ASSERT_EQUAL_FATAL(par, DDS_ENTITY_NIL); /* ---------- Get Participant ------------ */ /* Check getting Participant with bad parameters. */ par = dds_get_participant (0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(par), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(par, DDS_RETCODE_BAD_PARAMETER); /* Get Participant, a participants' participant is itself. */ par = dds_get_participant (entity); @@ -310,15 +308,15 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity) /* Check getting Children with bad parameters. */ status = dds_get_children (0, &child, 1); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_children (entity, NULL, 1); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_children (entity, &child, 0); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_children (0, NULL, 1); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_children (0, &child, 0); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Get Children, of which there are currently none. */ status = dds_get_children (entity, NULL, 0); @@ -338,30 +336,30 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity) CU_Test(ddsc_entity, get_domainid, .init = create_entity, .fini = delete_entity) { dds_return_t status; - dds_domainid_t id = -1; + dds_domainid_t id = DDS_DOMAIN_DEFAULT; /* Check getting ID with bad parameters. */ status = dds_get_domainid (0, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_domainid (entity, NULL); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_get_domainid (0, &id); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Get and check the domain id. */ status = dds_get_domainid (entity, &id); - cu_assert_status_eq(status, DDS_RETCODE_OK); - CU_ASSERT_FATAL(id != -1); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + CU_ASSERT_FATAL(id != DDS_DOMAIN_DEFAULT); } CU_Test(ddsc_entity, delete, .init = create_entity) { dds_return_t status; status = dds_delete(0); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); status = dds_delete(entity); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); entity = 0; } diff --git a/src/core/ddsc/tests/entity_hierarchy.c b/src/core/ddsc/tests/entity_hierarchy.c index ec7e2dc..a54f3cd 100644 --- a/src/core/ddsc/tests/entity_hierarchy.c +++ b/src/core/ddsc/tests/entity_hierarchy.c @@ -125,43 +125,43 @@ CU_Test(ddsc_entity_delete, recursive, .init=hierarchy_init, .fini=hierarchy_fin /* First be sure that 'dds_get_domainid' returns ok. */ ret = dds_get_domainid(g_participant, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_topic, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_publisher, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_subscriber, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_writer, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_reader, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_readcond, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_get_domainid(g_querycond, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* Deleting the top dog (participant) should delete all children. */ ret = dds_delete(g_participant); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* Check if all the entities are deleted now. */ ret = dds_get_domainid(g_participant, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_topic, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_publisher, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_subscriber, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_writer, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_reader, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_readcond, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_querycond, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -190,22 +190,22 @@ CU_Test(ddsc_entity_delete, recursive_with_deleted_topic) * reference to the topic and thus will delete it when it itself is * deleted. */ ret = dds_delete(g_topic); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* Third, deleting the participant should delete all children of which * the writer with the last topic reference is one. */ ret = dds_delete(g_participant); /* Before the CHAM-424 fix, we would not get here because of a crash, * or it (incidentally) continued but returned an error. */ - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* Check if the entities are actually deleted. */ ret = dds_get_domainid(g_participant, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER ); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER ); ret = dds_get_domainid(g_topic, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); ret = dds_get_domainid(g_writer, &id); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); dds_delete(g_keep); } @@ -240,7 +240,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_participant, deleted_entities, dds_entity_t participant; dds_delete(*entity); participant = dds_get_participant(*entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(participant), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -250,11 +250,10 @@ CU_TheoryDataPoints(ddsc_entity_get_participant, invalid_entities) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_participant, invalid_entities, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t participant; participant = dds_get_participant(entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(participant), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -314,7 +313,7 @@ CU_Test(ddsc_entity_get_parent, participant, .init=hierarchy_init, .fini=hierarc { dds_entity_t parent; parent = dds_get_parent(g_participant); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(parent), DDS_ENTITY_NIL); + CU_ASSERT_EQUAL_FATAL(parent, DDS_ENTITY_NIL); } /*************************************************************************************************/ @@ -327,7 +326,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_parent, deleted_entities, .ini dds_entity_t parent; dds_delete(*entity); parent = dds_get_parent(*entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(parent), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(parent, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -337,11 +336,10 @@ CU_TheoryDataPoints(ddsc_entity_get_parent, invalid_entities) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_parent, invalid_entities, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t parent; parent = dds_get_parent(entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(parent), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(parent, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -369,7 +367,7 @@ CU_Test(ddsc_entity_get_children, invalid_size, .init=hierarchy_init, .fini=hier dds_return_t ret; dds_entity_t child; ret = dds_get_children(g_participant, &child, INT32_MAX); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -478,7 +476,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_children, deleted_entities, .i dds_entity_t children[4]; dds_delete(*entity); ret = dds_get_children(*entity, children, 4); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -488,12 +486,11 @@ CU_TheoryDataPoints(ddsc_entity_get_children, invalid_entities) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_children, invalid_entities, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t children[4]; dds_return_t ret; ret = dds_get_children(entity, children, 4); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -527,7 +524,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_topic, deleted_entities, .init dds_entity_t topic; dds_delete(*entity); topic = dds_get_topic(*entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -537,11 +534,10 @@ CU_TheoryDataPoints(ddsc_entity_get_topic, invalid_entities) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_topic, invalid_entities, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t topic; topic = dds_get_topic(entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -553,7 +549,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_topic, non_data_entities, .ini { dds_entity_t topic; topic = dds_get_topic(*entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -581,7 +577,7 @@ CU_Test(ddsc_entity_get_publisher, deleted_writer, .init=hierarchy_init, .fini=h dds_entity_t publisher; dds_delete(g_writer); publisher = dds_get_publisher(g_writer); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(publisher), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(publisher, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -591,11 +587,10 @@ CU_TheoryDataPoints(ddsc_entity_get_publisher, invalid_writers) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_publisher, invalid_writers, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t publisher; publisher = dds_get_publisher(entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(publisher), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(publisher, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -607,7 +602,7 @@ CU_Theory((dds_entity_t *cond), ddsc_entity_get_publisher, non_writers, .init=hi { dds_entity_t publisher; publisher = dds_get_publisher(*cond); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(publisher), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(publisher, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -640,7 +635,7 @@ CU_Theory((dds_entity_t *entity), ddsc_entity_get_subscriber, deleted_readers, . dds_entity_t subscriber; dds_delete(*entity); subscriber = dds_get_subscriber(*entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(subscriber), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -650,11 +645,10 @@ CU_TheoryDataPoints(ddsc_entity_get_subscriber, invalid_readers) = { }; CU_Theory((dds_entity_t entity), ddsc_entity_get_subscriber, invalid_readers, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t subscriber; subscriber = dds_get_subscriber(entity); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(subscriber), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -666,7 +660,7 @@ CU_Theory((dds_entity_t *cond), ddsc_entity_get_subscriber, non_readers, .init=h { dds_entity_t subscriber; subscriber = dds_get_subscriber(*cond); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(subscriber), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -701,7 +695,7 @@ CU_Theory((dds_entity_t *cond), ddsc_entity_get_datareader, deleted_conds, .init dds_entity_t reader; dds_delete(*cond); reader = dds_get_datareader(*cond); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(reader), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -711,11 +705,10 @@ CU_TheoryDataPoints(ddsc_entity_get_datareader, invalid_conds) = { }; CU_Theory((dds_entity_t cond), ddsc_entity_get_datareader, invalid_conds, .init=hierarchy_init, .fini=hierarchy_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t reader; reader = dds_get_datareader(cond); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(reader), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -727,7 +720,7 @@ CU_Theory((dds_entity_t *cond), ddsc_entity_get_datareader, non_conds, .init=hie { dds_entity_t reader; reader = dds_get_datareader(*cond); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(reader), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -954,7 +947,7 @@ CU_Test(ddsc_entity_get_parent, implicit_publisher) dds_delete(writer); ret = dds_delete(parent); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); dds_delete(participant); } /*************************************************************************************************/ @@ -985,7 +978,7 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber) dds_delete(reader); ret = dds_delete(parent); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); dds_delete(participant); } diff --git a/src/core/ddsc/tests/entity_status.c b/src/core/ddsc/tests/entity_status.c index 45883fe..4f1f94d 100644 --- a/src/core/ddsc/tests/entity_status.c +++ b/src/core/ddsc/tests/entity_status.c @@ -41,7 +41,14 @@ static dds_time_t waitTimeout = DDS_SECS (2); static dds_time_t shortTimeout = DDS_MSECS (10); static dds_publication_matched_status_t publication_matched; static dds_subscription_matched_status_t subscription_matched; -static dds_resource_limits_qospolicy_t resource_limits = {1,1,1}; + +struct reslimits { + int32_t max_samples; + int32_t max_instances; + int32_t max_samples_per_instance; +}; + +static struct reslimits resource_limits = {1,1,1}; static dds_instance_handle_t reader_i_hdl = 0; static dds_instance_handle_t writer_i_hdl = 0; @@ -138,10 +145,19 @@ CU_Test(ddsc_entity_status, publication_matched, .init=init_entity_status, .fini CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 1); CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_i_hdl); + /* Second call should reset the changed count. */ + ret = dds_get_publication_matched_status(wri, &publication_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_i_hdl); + /* Getting the status should have reset the trigger, * meaning that the wait should timeout. */ ret = dds_waitset_wait(waitSetwr, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); /* Un-match the publication by deleting the reader. */ dds_delete(rea); @@ -156,6 +172,15 @@ CU_Test(ddsc_entity_status, publication_matched, .init=init_entity_status, .fini CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_i_hdl); + + /* Second call should reset the changed count. */ + ret = dds_get_publication_matched_status(wri, &publication_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_i_hdl); } CU_Test(ddsc_entity_status, subscription_matched, .init=init_entity_status, .fini=fini_entity_status) @@ -175,10 +200,19 @@ CU_Test(ddsc_entity_status, subscription_matched, .init=init_entity_status, .fin CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 1); CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_i_hdl); + /* Second call should reset the changed count. */ + ret = dds_get_subscription_matched_status(rea, &subscription_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_i_hdl); + /* Getting the status should have reset the trigger, * meaning that the wait should timeout. */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); /* Un-match the subscription by deleting the writer. */ dds_delete(wri); @@ -193,6 +227,15 @@ CU_Test(ddsc_entity_status, subscription_matched, .init=init_entity_status, .fin CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_i_hdl); + + /* Second call should reset the changed count. */ + ret = dds_get_subscription_matched_status(rea, &subscription_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_i_hdl); } CU_Test(ddsc_entity, incompatible_qos, .init=init_entity_status, .fini=fini_entity_status) @@ -231,9 +274,16 @@ CU_Test(ddsc_entity, incompatible_qos, .init=init_entity_status, .fini=fini_enti CU_ASSERT_EQUAL_FATAL(req_incompatible_qos.total_count_change, 1); CU_ASSERT_EQUAL_FATAL(req_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + /* Second call should reset the changed count. */ + ret = dds_get_requested_incompatible_qos_status (reader2, &req_incompatible_qos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(req_incompatible_qos.total_count, 1); + CU_ASSERT_EQUAL_FATAL(req_incompatible_qos.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(req_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + /*Getting the status should have reset the trigger, waitset should timeout */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); /* Wait for offered incompatible QoS status */ ret = dds_waitset_wait(waitSetwr, wsresults, wsresultsize, waitTimeout); @@ -244,9 +294,16 @@ CU_Test(ddsc_entity, incompatible_qos, .init=init_entity_status, .fini=fini_enti CU_ASSERT_EQUAL_FATAL(off_incompatible_qos.total_count_change, 1); CU_ASSERT_EQUAL_FATAL(off_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + /* Second call should reset the changed count. */ + ret = dds_get_offered_incompatible_qos_status (wri, &off_incompatible_qos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(off_incompatible_qos.total_count, 1); + CU_ASSERT_EQUAL_FATAL(off_incompatible_qos.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(off_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + /*Getting the status should have reset the trigger, waitset should timeout */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); ret = dds_waitset_detach(waitSetrd, reader2); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); @@ -278,9 +335,18 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0); CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl); + /* Second call should reset the changed count. */ + ret = dds_get_liveliness_changed_status (rea, &liveliness_changed); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 1); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl); + /*Getting the status should have reset the trigger, waitset should timeout */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); /* Reset writer */ ret = dds_waitset_detach(waitSetwr, wri); @@ -298,6 +364,15 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1); CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,1); CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl); + + /* Second call should reset the changed count. */ + ret = dds_get_liveliness_changed_status (rea, &liveliness_changed); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl); } CU_Test(ddsc_entity, sample_rejected, .init=init_entity_status, .fini=fini_entity_status) @@ -339,9 +414,16 @@ CU_Test(ddsc_entity, sample_rejected, .init=init_entity_status, .fini=fini_entit CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count_change, 4); CU_ASSERT_EQUAL_FATAL(sample_rejected.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); + /* Second call should reset the changed count. */ + ret = dds_get_sample_rejected_status (rea, &sample_rejected); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count, 4); + CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(sample_rejected.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); + /*Getting the status should have reset the trigger, waitset should timeout */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); } #if 0 @@ -370,7 +452,7 @@ Test(ddsc_entity, inconsistent_topic) /*Getting the status should have reset the trigger, waitset should timeout */ status = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), 0, "returned %d", dds_err_nr(status)); + CU_ASSERT_EQUAL_FATAL(status, 0, "returned %d", status); /* Wait for sub inconsistent topic status callback */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, waitTimeout); @@ -381,7 +463,7 @@ Test(ddsc_entity, inconsistent_topic) /*Getting the status should have reset the trigger, waitset should timeout */ status = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), 0); + CU_ASSERT_EQUAL_FATAL(status, 0); dds_delete(top); } @@ -426,12 +508,18 @@ CU_Test(ddsc_entity, sample_lost, .init=init_entity_status, .fini=fini_entity_st CU_ASSERT_EQUAL_FATAL(ret, (dds_return_t)wsresultsize); ret = dds_get_sample_lost_status (rea, &sample_lost); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(sample_lost.total_count, 1); + CU_ASSERT_EQUAL_FATAL(sample_lost.total_count, 1); CU_ASSERT_EQUAL_FATAL(sample_lost.total_count_change, 1); + /* Second call should reset the changed count. */ + ret = dds_get_sample_lost_status (rea, &sample_lost); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(sample_lost.total_count, 1); + CU_ASSERT_EQUAL_FATAL(sample_lost.total_count_change, 0); + /*Getting the status should have reset the trigger, waitset should timeout */ ret = dds_waitset_wait(waitSetrd, wsresults, wsresultsize, shortTimeout); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), 0); + CU_ASSERT_EQUAL_FATAL(ret, 0); } @@ -594,10 +682,9 @@ CU_TheoryDataPoints(ddsc_get_enabled_status, bad_param) = { CU_Theory((dds_entity_t e), ddsc_get_enabled_status, bad_param, .init=init_entity_status, .fini=fini_entity_status) { uint32_t mask; - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_status_mask(e, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_get_enabled_status, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) @@ -605,14 +692,14 @@ CU_Test(ddsc_get_enabled_status, deleted_reader, .init=init_entity_status, .fini uint32_t mask; dds_delete(rea); ret = dds_get_status_mask(rea, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_get_enabled_status, illegal, .init=init_entity_status, .fini=fini_entity_status) { uint32_t mask; ret = dds_get_status_mask(waitSetrd, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_TheoryDataPoints(ddsc_get_enabled_status, status_ok) = { @@ -632,23 +719,21 @@ CU_TheoryDataPoints(ddsc_set_enabled_status, bad_param) = { }; CU_Theory((dds_entity_t e), ddsc_set_enabled_status, bad_param, .init=init_entity_status, .fini=fini_entity_status) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; - ret = dds_set_status_mask(e, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_set_enabled_status, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) { dds_delete(rea); ret = dds_set_status_mask(rea, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_set_enabled_status, illegal, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_set_status_mask(waitSetrd, 0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_TheoryDataPoints(ddsc_set_enabled_status, status_ok) = { @@ -668,10 +753,9 @@ CU_TheoryDataPoints(ddsc_read_status, bad_param) = { CU_Theory((dds_entity_t e), ddsc_read_status, bad_param, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_read_status(e, &status, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_read_status, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) @@ -679,14 +763,14 @@ CU_Test(ddsc_read_status, deleted_reader, .init=init_entity_status, .fini=fini_e uint32_t status; dds_delete(rea); ret = dds_read_status(rea, &status, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_read_status, illegal, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; ret = dds_read_status(waitSetrd, &status, 0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_TheoryDataPoints(ddsc_read_status, status_ok) = { CU_DataPoints(dds_entity_t *,&rea, &wri, &participant, &top, &publisher, &subscriber), @@ -702,14 +786,14 @@ CU_Test(ddsc_read_status, invalid_status_on_reader, .init=init_entity_status, .f { uint32_t status; ret = dds_read_status(rea, &status, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_read_status, invalid_status_on_writer, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; ret = dds_read_status(wri, &status, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -720,10 +804,9 @@ CU_TheoryDataPoints(ddsc_take_status, bad_param) = { CU_Theory((dds_entity_t e), ddsc_take_status, bad_param, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_take_status(e, &status, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_take_status, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) @@ -731,13 +814,13 @@ CU_Test(ddsc_take_status, deleted_reader, .init=init_entity_status, .fini=fini_e uint32_t status; dds_delete(rea); ret = dds_take_status(rea, &status, 0 /*mask*/); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_take_status, illegal, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; ret = dds_take_status(waitSetrd, &status, 0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_TheoryDataPoints(ddsc_take_status, status_ok) = { @@ -759,10 +842,9 @@ CU_TheoryDataPoints(ddsc_get_status_changes, bad_param) = { CU_Theory((dds_entity_t e), ddsc_get_status_changes, bad_param, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_status_changes(e, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_get_status_changes, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) @@ -770,14 +852,14 @@ CU_Test(ddsc_get_status_changes, deleted_reader, .init=init_entity_status, .fini uint32_t status; dds_delete(rea); ret = dds_get_status_changes(rea, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_get_status_changes, illegal, .init=init_entity_status, .fini=fini_entity_status) { uint32_t status; ret = dds_get_status_changes(waitSetrd, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_TheoryDataPoints(ddsc_get_status_changes, status_ok) = { @@ -797,17 +879,15 @@ CU_TheoryDataPoints(ddsc_triggered, bad_param) = { }; CU_Theory((dds_entity_t e), ddsc_triggered, bad_param, .init=init_entity_status, .fini=fini_entity_status) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; - ret = dds_triggered(e); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_triggered, deleted_reader, .init=init_entity_status, .fini=fini_entity_status) { dds_delete(rea); ret = dds_triggered(rea); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_TheoryDataPoints(ddsc_triggered, status_ok) = { @@ -825,7 +905,7 @@ CU_Test(ddsc_get_inconsistent_topic_status, inconsistent_topic_status, .init=ini { dds_inconsistent_topic_status_t inconsistent_topic_status; ret = dds_get_inconsistent_topic_status(top, &inconsistent_topic_status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(inconsistent_topic_status.total_count, 0); CU_ASSERT_EQUAL_FATAL(inconsistent_topic_status.total_count_change, 0); } @@ -838,10 +918,9 @@ CU_TheoryDataPoints(ddsc_get_inconsistent_topic_status, bad_params) = { CU_Theory((dds_entity_t topic), ddsc_get_inconsistent_topic_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_inconsistent_topic_status_t topic_status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_inconsistent_topic_status(topic, &topic_status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -850,7 +929,7 @@ CU_Test(ddsc_get_inconsistent_topic_status, null, .init=init_entity_status, .fin { dds_set_status_mask(top, 0); ret = dds_get_inconsistent_topic_status(top, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -861,7 +940,7 @@ CU_TheoryDataPoints(ddsc_get_inconsistent_topic_status, non_topics) = { CU_Theory((dds_entity_t *topic), ddsc_get_inconsistent_topic_status, non_topics, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_inconsistent_topic_status(*topic, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -870,7 +949,7 @@ CU_Test(ddsc_get_inconsistent_topic_status, deleted_topic, .init=init_entity_sta { dds_delete(top); ret = dds_get_inconsistent_topic_status(top, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -881,10 +960,9 @@ CU_TheoryDataPoints(ddsc_get_publication_matched_status, bad_params) = { CU_Theory((dds_entity_t writer), ddsc_get_publication_matched_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_publication_matched_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_publication_matched_status(writer, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -893,7 +971,7 @@ CU_Test(ddsc_get_publication_matched_status, null, .init=init_entity_status, .fi { dds_set_status_mask(wri, 0); ret = dds_get_publication_matched_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -904,7 +982,7 @@ CU_TheoryDataPoints(ddsc_get_publication_matched_status, non_writers) = { CU_Theory((dds_entity_t *writer), ddsc_get_publication_matched_status, non_writers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_publication_matched_status(*writer, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -913,7 +991,7 @@ CU_Test(ddsc_get_publication_matched_status, deleted_writer, .init=init_entity_s { dds_delete(wri); ret = dds_get_publication_matched_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -922,7 +1000,7 @@ CU_Test(ddsc_get_liveliness_lost_status, liveliness_lost_status, .init=init_enti { dds_liveliness_lost_status_t liveliness_lost_status; ret = dds_get_liveliness_lost_status(wri, &liveliness_lost_status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(liveliness_lost_status.total_count, 0); CU_ASSERT_EQUAL_FATAL(liveliness_lost_status.total_count_change, 0); } @@ -935,10 +1013,9 @@ CU_TheoryDataPoints(ddsc_get_liveliness_lost_status, bad_params) = { CU_Theory((dds_entity_t writer), ddsc_get_liveliness_lost_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_liveliness_lost_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_liveliness_lost_status(writer, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -947,7 +1024,7 @@ CU_Test(ddsc_get_liveliness_lost_status, null, .init=init_entity_status, .fini=f { dds_set_status_mask(wri, 0); ret = dds_get_liveliness_lost_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -958,7 +1035,7 @@ CU_TheoryDataPoints(ddsc_get_liveliness_lost_status, non_writers) = { CU_Theory((dds_entity_t *writer), ddsc_get_liveliness_lost_status, non_writers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_liveliness_lost_status(*writer, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -967,7 +1044,7 @@ CU_Test(ddsc_get_liveliness_lost_status, deleted_writer, .init=init_entity_statu { dds_delete(wri); ret = dds_get_liveliness_lost_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -976,7 +1053,7 @@ CU_Test(ddsc_get_offered_deadline_missed_status, offered_deadline_missed_status, { dds_offered_deadline_missed_status_t offered_deadline_missed_status; ret = dds_get_offered_deadline_missed_status(wri, &offered_deadline_missed_status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(offered_deadline_missed_status.total_count, 0); CU_ASSERT_EQUAL_FATAL(offered_deadline_missed_status.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(offered_deadline_missed_status.last_instance_handle, 0); @@ -990,10 +1067,9 @@ CU_TheoryDataPoints(ddsc_get_offered_deadline_missed_status, bad_params) = { CU_Theory((dds_entity_t writer), ddsc_get_offered_deadline_missed_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_offered_deadline_missed_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_offered_deadline_missed_status(writer, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1002,7 +1078,7 @@ CU_Test(ddsc_get_offered_deadline_missed_status, null, .init=init_entity_status, { dds_set_status_mask(wri, 0); ret = dds_get_offered_deadline_missed_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1013,7 +1089,7 @@ CU_TheoryDataPoints(ddsc_get_offered_deadline_missed_status, non_writers) = { CU_Theory((dds_entity_t *writer), ddsc_get_offered_deadline_missed_status, non_writers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_offered_deadline_missed_status(*writer, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1022,7 +1098,7 @@ CU_Test(ddsc_get_offered_deadline_missed_status, deleted_writer, .init=init_enti { dds_delete(wri); ret = dds_get_offered_deadline_missed_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1033,10 +1109,9 @@ CU_TheoryDataPoints(ddsc_get_offered_incompatible_qos_status, bad_params) = { CU_Theory((dds_entity_t writer), ddsc_get_offered_incompatible_qos_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_offered_incompatible_qos_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_offered_incompatible_qos_status(writer, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1045,7 +1120,7 @@ CU_Test(ddsc_get_offered_incompatible_qos_status, null, .init=init_entity_status { dds_set_status_mask(wri, 0); ret = dds_get_offered_incompatible_qos_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1056,7 +1131,7 @@ CU_TheoryDataPoints(ddsc_get_offered_incompatible_qos_status, non_writers) = { CU_Theory((dds_entity_t *writer), ddsc_get_offered_incompatible_qos_status, non_writers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_offered_incompatible_qos_status(*writer, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1065,7 +1140,7 @@ CU_Test(ddsc_get_offered_incompatible_qos_status, deleted_writer, .init=init_ent { dds_delete(wri); ret = dds_get_offered_incompatible_qos_status(wri, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1076,10 +1151,9 @@ CU_TheoryDataPoints(ddsc_get_subscription_matched_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_subscription_matched_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_subscription_matched_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_subscription_matched_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1088,7 +1162,7 @@ CU_Test(ddsc_get_subscription_matched_status, null, .init=init_entity_status, .f { dds_set_status_mask(rea, 0); ret = dds_get_subscription_matched_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1099,7 +1173,7 @@ CU_TheoryDataPoints(ddsc_get_subscription_matched_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_subscription_matched_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_subscription_matched_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1108,7 +1182,7 @@ CU_Test(ddsc_get_subscription_matched_status, deleted_reader, .init=init_entity_ { dds_delete(rea); ret = dds_get_subscription_matched_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1119,10 +1193,9 @@ CU_TheoryDataPoints(ddsc_get_liveliness_changed_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_liveliness_changed_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_liveliness_changed_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_liveliness_changed_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1131,7 +1204,7 @@ CU_Test(ddsc_get_liveliness_changed_status, null, .init=init_entity_status, .fin { dds_set_status_mask(rea, 0); ret = dds_get_liveliness_changed_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1142,7 +1215,7 @@ CU_TheoryDataPoints(ddsc_get_liveliness_changed_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_liveliness_changed_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_liveliness_changed_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1151,7 +1224,7 @@ CU_Test(ddsc_get_liveliness_changed_status, deleted_reader, .init=init_entity_st { dds_delete(rea); ret = dds_get_liveliness_changed_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1162,10 +1235,9 @@ CU_TheoryDataPoints(ddsc_get_sample_rejected_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_sample_rejected_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_sample_rejected_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_sample_rejected_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1174,7 +1246,7 @@ CU_Test(ddsc_get_sample_rejected_status, null, .init=init_entity_status, .fini=f { dds_set_status_mask(rea, 0); ret = dds_get_sample_rejected_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1185,7 +1257,7 @@ CU_TheoryDataPoints(ddsc_get_sample_rejected_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_sample_rejected_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_sample_rejected_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1194,7 +1266,7 @@ CU_Test(ddsc_get_sample_rejected_status, deleted_reader, .init=init_entity_statu { dds_delete(rea); ret = dds_get_sample_rejected_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1205,10 +1277,9 @@ CU_TheoryDataPoints(ddsc_get_sample_lost_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_sample_lost_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_sample_lost_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_sample_lost_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1217,7 +1288,7 @@ CU_Test(ddsc_get_sample_lost_status, null, .init=init_entity_status, .fini=fini_ { dds_set_status_mask(rea, 0); ret = dds_get_sample_lost_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1228,7 +1299,7 @@ CU_TheoryDataPoints(ddsc_get_sample_lost_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_sample_lost_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_sample_lost_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1237,7 +1308,7 @@ CU_Test(ddsc_get_sample_lost_status, deleted_reader, .init=init_entity_status, . { dds_delete(rea); ret = dds_get_sample_lost_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1246,7 +1317,7 @@ CU_Test(ddsc_get_requested_deadline_missed_status, requested_deadline_missed_sta { dds_requested_deadline_missed_status_t requested_deadline_missed_status; ret = dds_get_requested_deadline_missed_status(rea, &requested_deadline_missed_status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(requested_deadline_missed_status.total_count, 0); CU_ASSERT_EQUAL_FATAL(requested_deadline_missed_status.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(requested_deadline_missed_status.last_instance_handle, DDS_HANDLE_NIL); @@ -1260,10 +1331,9 @@ CU_TheoryDataPoints(ddsc_get_requested_deadline_missed_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_requested_deadline_missed_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_requested_deadline_missed_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_requested_deadline_missed_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1272,7 +1342,7 @@ CU_Test(ddsc_get_requested_deadline_missed_status, null, .init=init_entity_statu { dds_set_status_mask(rea, 0); ret = dds_get_requested_deadline_missed_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1283,7 +1353,7 @@ CU_TheoryDataPoints(ddsc_get_requested_deadline_missed_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_requested_deadline_missed_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_requested_deadline_missed_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1292,7 +1362,7 @@ CU_Test(ddsc_get_requested_deadline_missed_status, deleted_reader, .init=init_en { dds_delete(rea); ret = dds_get_requested_deadline_missed_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1303,10 +1373,9 @@ CU_TheoryDataPoints(ddsc_get_requested_incompatible_qos_status, bad_params) = { CU_Theory((dds_entity_t reader), ddsc_get_requested_incompatible_qos_status, bad_params, .init=init_entity_status, .fini=fini_entity_status) { dds_requested_incompatible_qos_status_t status; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; ret = dds_get_requested_incompatible_qos_status(reader, &status); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1315,7 +1384,7 @@ CU_Test(ddsc_get_requested_incompatible_qos_status, null, .init=init_entity_stat { dds_set_status_mask(rea, 0); ret = dds_get_requested_incompatible_qos_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); } /*************************************************************************************************/ @@ -1326,7 +1395,7 @@ CU_TheoryDataPoints(ddsc_get_requested_incompatible_qos_status, non_readers) = { CU_Theory((dds_entity_t *reader), ddsc_get_requested_incompatible_qos_status, non_readers, .init=init_entity_status, .fini=fini_entity_status) { ret = dds_get_requested_incompatible_qos_status(*reader, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1335,7 +1404,7 @@ CU_Test(ddsc_get_requested_incompatible_qos_status, deleted_reader, .init=init_e { dds_delete(rea); ret = dds_get_requested_incompatible_qos_status(rea, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/instance_get_key.c b/src/core/ddsc/tests/instance_get_key.c index 48bd0d3..a0861b3 100644 --- a/src/core/ddsc/tests/instance_get_key.c +++ b/src/core/ddsc/tests/instance_get_key.c @@ -18,20 +18,40 @@ #include "dds/ddsrt/string.h" #include "RoundTrip.h" +#define MAX_SAMPLES 10 + static dds_entity_t participant = DDS_ENTITY_NIL; +static dds_entity_t waitset = DDS_ENTITY_NIL; static dds_entity_t topic = DDS_ENTITY_NIL; static dds_entity_t publisher = DDS_ENTITY_NIL; +static dds_entity_t subscriber = DDS_ENTITY_NIL; static dds_entity_t writer = DDS_ENTITY_NIL; - +static dds_entity_t reader = DDS_ENTITY_NIL; +static dds_entity_t readcondition = DDS_ENTITY_NIL; +static dds_entity_t querycondition = DDS_ENTITY_NIL; static dds_instance_handle_t handle = DDS_HANDLE_NIL; +static bool +filter(const void * sample) +{ + const RoundTripModule_Address *s = sample; + return (s->port == 1); +} + static RoundTripModule_Address data; /* Fixture to create prerequisite entity */ static void setup(void) { + uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + dds_return_t ret; + participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); + + waitset = dds_create_waitset(participant); + CU_ASSERT_FATAL(waitset > 0); + topic = dds_create_topic(participant, &RoundTripModule_Address_desc, "ddsc_instance_get_key", NULL, NULL); CU_ASSERT_FATAL(topic > 0); @@ -41,6 +61,24 @@ static void setup(void) writer = dds_create_writer(publisher, topic, NULL, NULL); CU_ASSERT_FATAL(writer > 0); + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + + readcondition = dds_create_readcondition(reader, mask); + CU_ASSERT_FATAL(readcondition > 0); + + ret = dds_waitset_attach(waitset, readcondition, readcondition); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + querycondition = dds_create_querycondition(reader, mask, filter); + CU_ASSERT_FATAL(querycondition > 0); + + ret = dds_waitset_attach(waitset, querycondition, querycondition); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + memset(&data, 0, sizeof(data)); data.ip = ddsrt_strdup("some data"); CU_ASSERT_PTR_NOT_NULL_FATAL(data.ip); @@ -52,9 +90,6 @@ static void teardown(void) { RoundTripModule_Address_free(&data, DDS_FREE_CONTENTS); - dds_delete(writer); - dds_delete(publisher); - dds_delete(topic); dds_delete(participant); } @@ -63,7 +98,7 @@ CU_Test(ddsc_instance_get_key, bad_entity, .init=setup, .fini=teardown) dds_return_t ret; ret = dds_instance_get_key(participant, handle, &data); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_Test(ddsc_instance_get_key, null_data, .init=setup, .fini=teardown) @@ -71,7 +106,7 @@ CU_Test(ddsc_instance_get_key, null_data, .init=setup, .fini=teardown) dds_return_t ret; ret = dds_register_instance(writer, &handle, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_instance_get_key, null_handle, .init=setup, .fini=teardown) @@ -81,7 +116,7 @@ CU_Test(ddsc_instance_get_key, null_handle, .init=setup, .fini=teardown) CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_instance_get_key(writer, DDS_HANDLE_NIL, &data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_instance_get_key, registered_instance, .init=setup, .fini=teardown) @@ -99,8 +134,67 @@ CU_Test(ddsc_instance_get_key, registered_instance, .init=setup, .fini=teardown) CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip); CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip); CU_ASSERT_EQUAL_FATAL(key_data.port, data.port); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); RoundTripModule_Address_free(&key_data, DDS_FREE_CONTENTS); } +CU_Test(ddsc_instance_get_key, readcondition, .init=setup, .fini=teardown) +{ + dds_return_t ret; + RoundTripModule_Address key_data; + + /* The instance handle of a successful write is by + * design the same as the instance handle for the + * readers,readconditions and queryconditions. + * For that reason there is no need to actually read + * the data. It is sufficient to do a successful write + * and use the instance handle to obtain the key_data + * for the readcondition. */ + ret = dds_write(writer, &data); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + handle = dds_lookup_instance (writer, &data); + CU_ASSERT_PTR_NOT_NULL_FATAL(handle); + + memset(&key_data, 0, sizeof(key_data)); + + ret = dds_instance_get_key(readcondition, handle, &key_data); + + CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip); + CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip); + CU_ASSERT_EQUAL_FATAL(key_data.port, data.port); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + RoundTripModule_Address_free(&key_data, DDS_FREE_CONTENTS); +} + +CU_Test(ddsc_instance_get_key, querycondition, .init=setup, .fini=teardown) +{ + dds_return_t ret; + RoundTripModule_Address key_data; + + /* The instance handle of a successful write is by + * design the same as the instance handle for the + * readers,readconditions and queryconditions. + * For that reason there is no need to actually read + * the data. It is sufficient to do a successful write + * and use the instance handle to obtain the key_data + * for the querycondition. */ + ret = dds_write(writer, &data); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + handle = dds_lookup_instance (writer, &data); + CU_ASSERT_PTR_NOT_NULL_FATAL(handle); + + memset(&key_data, 0, sizeof(key_data)); + + ret = dds_instance_get_key(querycondition, handle, &key_data); + + CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip); + CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip); + CU_ASSERT_EQUAL_FATAL(key_data.port, data.port); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + RoundTripModule_Address_free(&key_data, DDS_FREE_CONTENTS); +} diff --git a/src/core/ddsc/tests/listener.c b/src/core/ddsc/tests/listener.c index d049c85..b0b42a7 100644 --- a/src/core/ddsc/tests/listener.c +++ b/src/core/ddsc/tests/listener.c @@ -692,6 +692,7 @@ CU_Test(ddsc_listener, matched, .init=init_triggering_base, .fini=fini_triggerin CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fini_triggering_test) { + dds_publication_matched_status_t publication_matched; dds_instance_handle_t reader_hdl; dds_return_t ret; uint32_t triggered; @@ -716,6 +717,15 @@ CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fi CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + /* The listener should have reset the count_change. */ + ret = dds_get_publication_matched_status(g_writer, &publication_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl); + /* Reset the trigger flags. */ cb_called = 0; @@ -731,10 +741,20 @@ CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fi CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count, 1); CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.last_subscription_handle, reader_hdl); + + /* The listener should have reset the count_change. */ + ret = dds_get_publication_matched_status(g_writer, &publication_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl); } CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=fini_triggering_test) { + dds_subscription_matched_status_t subscription_matched; dds_instance_handle_t writer_hdl; dds_return_t ret; uint32_t triggered; @@ -759,6 +779,15 @@ CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=f CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + /* The listener should have reset the count_change. */ + ret = dds_get_subscription_matched_status(g_reader, &subscription_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl); + /* Reset the trigger flags. */ cb_called = 0; @@ -774,10 +803,21 @@ CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=f CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count, 1); CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count_change, 0); CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.last_publication_handle, writer_hdl); + + /* The listener should have reset the count_change. */ + ret = dds_get_subscription_matched_status(g_reader, &subscription_matched); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); + CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl); } CU_Test(ddsc_listener, incompatible_qos, .init=init_triggering_base, .fini=fini_triggering_base) { + dds_offered_incompatible_qos_status_t offered_incompatible_qos; + dds_requested_incompatible_qos_status_t requested_incompatible_qos; dds_return_t ret; uint32_t triggered; uint32_t status; @@ -815,6 +855,18 @@ CU_Test(ddsc_listener, incompatible_qos, .init=init_triggering_base, .fini=fini_ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + /* The listener should have reset the count_change. */ + ret = dds_get_offered_incompatible_qos_status(g_writer, &offered_incompatible_qos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_requested_incompatible_qos_status(g_reader, &requested_incompatible_qos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.total_count, 1); + CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.total_count, 1); + CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); + dds_delete(g_writer); dds_delete(g_reader); } @@ -997,6 +1049,7 @@ CU_Test(ddsc_listener, data_on_readers, .init=init_triggering_test, .fini=fini_t CU_Test(ddsc_listener, sample_lost, .init=init_triggering_test, .fini=fini_triggering_test) { + dds_sample_lost_status_t sample_lost; dds_return_t ret; uint32_t triggered; dds_time_t the_past; @@ -1031,10 +1084,17 @@ CU_Test(ddsc_listener, sample_lost, .init=init_triggering_test, .fini=fini_trigg ret = dds_read_status(g_reader, &status, DDS_SAMPLE_LOST_STATUS); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + + /* The listener should have reset the count_change. */ + ret = dds_get_sample_lost_status(g_reader, &sample_lost); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(sample_lost.total_count, 1); + CU_ASSERT_EQUAL_FATAL(sample_lost.total_count_change, 0); } CU_Test(ddsc_listener, sample_rejected, .init=init_triggering_test, .fini=fini_triggering_test) { + dds_sample_rejected_status_t sample_rejected; dds_return_t ret; uint32_t triggered; uint32_t status; @@ -1060,15 +1120,24 @@ CU_Test(ddsc_listener, sample_rejected, .init=init_triggering_test, .fini=fini_t CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.total_count, 2); CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.total_count_change, 1); + CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); /* The listener should have swallowed the status. */ ret = dds_read_status(g_reader, &status, DDS_SAMPLE_REJECTED_STATUS); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + + /* The listener should have reset the count_change. */ + ret = dds_get_sample_rejected_status(g_reader, &sample_rejected); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count, 2); + CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count_change, 0); + CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); } CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fini_triggering_base) { + dds_liveliness_changed_status_t liveliness_changed; dds_instance_handle_t writer_hdl; dds_return_t ret; uint32_t triggered; @@ -1095,6 +1164,15 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(status, 0); + /* The listener should have reset the count_change. */ + ret = dds_get_liveliness_changed_status(g_reader, &liveliness_changed); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 1); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl); + /* Reset the trigger flags. */ cb_called = 0; @@ -1110,6 +1188,15 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 1); CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 1); CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl); + + /* The listener should have reset the count_change. */ + ret = dds_get_liveliness_changed_status(g_reader, &liveliness_changed); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0); + CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl); } #if 0 diff --git a/src/core/ddsc/tests/participant.c b/src/core/ddsc/tests/participant.c index 14a8171..23d5d42 100644 --- a/src/core/ddsc/tests/participant.c +++ b/src/core/ddsc/tests/participant.c @@ -17,8 +17,6 @@ #include "dds/version.h" #include "dds/ddsrt/environ.h" -#define cu_assert_status_eq(s1, s2) CU_ASSERT_EQUAL_FATAL(dds_err_nr(s1), s2) - CU_Test(ddsc_participant, create_and_delete) { @@ -44,29 +42,25 @@ CU_Test(ddsc_participant, create_and_delete) { /* Test for creating participant with no configuration file */ CU_Test(ddsc_participant, create_with_no_conf_no_env) { - dds_entity_t participant, participant2, participant3; + dds_entity_t participant2, participant3; dds_return_t status; dds_domainid_t domain_id; dds_domainid_t valid_domain=3; ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI"); - //invalid domain - participant = dds_create_participant (-2, NULL, NULL); - CU_ASSERT_FATAL(participant < 0); - //valid specific domain value participant2 = dds_create_participant (valid_domain, NULL, NULL); CU_ASSERT_FATAL(participant2 > 0); status = dds_get_domainid(participant2, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(domain_id, valid_domain); //DDS_DOMAIN_DEFAULT from user participant3 = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant3 > 0); status = dds_get_domainid(participant3, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(domain_id, valid_domain); dds_delete(participant2); @@ -74,11 +68,41 @@ CU_Test(ddsc_participant, create_with_no_conf_no_env) } +/* Test for creating participants in multiple domains with no configuration file */ +CU_Test(ddsc_participant, create_multiple_domains) +{ + dds_entity_t participant1, participant2; + dds_return_t status; + dds_domainid_t domain_id; + + ddsrt_setenv("CYCLONEDDS_URI", "finestmulti-domain-1.log"); + + //valid specific domain value + participant1 = dds_create_participant (1, NULL, NULL); + CU_ASSERT_FATAL(participant1 > 0); + status = dds_get_domainid(participant1, &domain_id); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(domain_id, 1); + + ddsrt_setenv("CYCLONEDDS_URI", "finestmulti-domain-2.log"); + + //DDS_DOMAIN_DEFAULT from user + participant2 = dds_create_participant (2, NULL, NULL); + CU_ASSERT_FATAL(participant2 > 0); + status = dds_get_domainid(participant2, &domain_id); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(domain_id, 2); + + dds_delete(participant1); + dds_delete(participant2); +} + + ////WITH CONF /* Test for creating participant with valid configuration file */ CU_Test(ddsc_participant, create_with_conf_no_env) { - dds_entity_t participant, participant2, participant3; + dds_entity_t participant2, participant3; dds_return_t status; dds_domainid_t domain_id; dds_domainid_t valid_domain=3; @@ -90,16 +114,11 @@ CU_Test(ddsc_participant, create_with_conf_no_env) { ddsrt_getenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &env_uri); CU_ASSERT_PTR_NOT_EQUAL_FATAL(env_uri, NULL); - //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 participant2 = dds_create_participant (valid_domain, NULL, NULL); CU_ASSERT_FATAL(participant2 > 0); status = dds_get_domainid(participant2, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(domain_id, valid_domain); @@ -107,7 +126,7 @@ CU_Test(ddsc_participant, create_with_conf_no_env) { participant3 = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant3 > 0); status = dds_get_domainid(participant3, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(domain_id, valid_domain); dds_delete(participant2); @@ -128,7 +147,7 @@ CU_Test(ddsc_participant_lookup, one) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); num_of_found_pp = dds_lookup_participant( domain_id, participants, size); CU_ASSERT_EQUAL_FATAL(num_of_found_pp, 1); @@ -154,7 +173,7 @@ CU_Test(ddsc_participant_lookup, multiple) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); num_of_found_pp = dds_lookup_participant( domain_id, participants, size); CU_ASSERT_EQUAL_FATAL(num_of_found_pp, 2); @@ -186,7 +205,7 @@ CU_Test(ddsc_participant_lookup, array_too_small) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); num_of_found_pp = dds_lookup_participant( domain_id, participants, size); CU_ASSERT_EQUAL_FATAL(num_of_found_pp, 3); @@ -212,7 +231,7 @@ CU_Test(ddsc_participant_lookup, null_zero){ /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); num_of_found_pp = dds_lookup_participant( domain_id, NULL, size); CU_ASSERT_EQUAL_FATAL(num_of_found_pp, 1); @@ -233,10 +252,10 @@ CU_Test(ddsc_participant_lookup, null_nonzero){ /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); num_of_found_pp = dds_lookup_participant( domain_id, NULL, size); - cu_assert_status_eq(num_of_found_pp, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(num_of_found_pp, DDS_RETCODE_BAD_PARAMETER); dds_delete (participant); } @@ -255,7 +274,7 @@ CU_Test(ddsc_participant_lookup, unknown_id) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); domain_id ++; num_of_found_pp = dds_lookup_participant( domain_id, participants, size); @@ -288,7 +307,7 @@ CU_Test(ddsc_participant_lookup, no_more) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_delete (participant); @@ -313,7 +332,7 @@ CU_Test(ddsc_participant_lookup, deleted) { /* Get domain id */ status = dds_get_domainid(participant, &domain_id); - cu_assert_status_eq(status, DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_delete (participant2); diff --git a/src/core/ddsc/tests/publisher.c b/src/core/ddsc/tests/publisher.c index 78c5bb1..2035e4a 100644 --- a/src/core/ddsc/tests/publisher.c +++ b/src/core/ddsc/tests/publisher.c @@ -19,8 +19,6 @@ #pragma warning(disable: 28020) #endif -#define cu_assert_status_eq(s1, s2) CU_ASSERT_EQUAL_FATAL(dds_err_nr(s1), s2) - /* Dummy callback */ static void data_available_cb(dds_entity_t reader, void* arg) { @@ -42,7 +40,7 @@ CU_Test(ddsc_publisher, create) /* Use NULL participant */ publisher = dds_create_publisher(0, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(publisher), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(publisher, DDS_RETCODE_PRECONDITION_NOT_MET); participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); @@ -53,7 +51,7 @@ CU_Test(ddsc_publisher, create) /* Use entity that is not a participant */ publisher1 = dds_create_publisher(publisher, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(publisher1), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(publisher1, DDS_RETCODE_ILLEGAL_OPERATION); dds_delete(publisher); /* Create a non-null qos */ @@ -143,35 +141,35 @@ CU_Test(ddsc_publisher, suspend_resume) /* Suspend a 0 publisher */ status = dds_suspend(0); - cu_assert_status_eq(status, DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_PRECONDITION_NOT_MET); /* Resume a 0 publisher */ status = dds_resume(0); - cu_assert_status_eq(status, DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_PRECONDITION_NOT_MET); /* Uae dds_suspend on something else than a publisher */ participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); status = dds_suspend(participant); - cu_assert_status_eq(status, DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); /* Use dds_resume on something else than a publisher */ status = dds_resume(participant); - cu_assert_status_eq(status, DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); /* Use dds_resume without calling dds_suspend */ publisher = dds_create_publisher(participant, NULL, NULL); CU_ASSERT_FATAL(publisher > 0); status = dds_resume(publisher); /* Should be precondition not met? */ - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Use dds_suspend on non-null publisher */ status = dds_suspend(publisher); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Use dds_resume on non-null publisher */ status = dds_resume(publisher); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); dds_delete(publisher); dds_delete(participant); @@ -189,38 +187,38 @@ CU_Test(ddsc_publisher, wait_for_acks) /* Wait_for_acks on 0 publisher or writer and minusOneSec timeout */ status = dds_wait_for_acks(0, minusOneSec); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Wait_for_acks on NULL publisher or writer and zeroSec timeout */ status = dds_wait_for_acks(0, zeroSec); - cu_assert_status_eq(status, DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_PRECONDITION_NOT_MET); /* wait_for_acks on NULL publisher or writer and oneSec timeout */ status = dds_wait_for_acks(0, oneSec); - cu_assert_status_eq(status, DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_PRECONDITION_NOT_MET); /* wait_for_acks on NULL publisher or writer and DDS_INFINITE timeout */ status = dds_wait_for_acks(0, DDS_INFINITY); - cu_assert_status_eq(status, DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_PRECONDITION_NOT_MET); participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); /* Wait_for_acks on participant and minusOneSec timeout */ status = dds_wait_for_acks(participant, minusOneSec); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Wait_for_acks on participant and zeroSec timeout */ status = dds_wait_for_acks(participant, zeroSec); - cu_assert_status_eq(status, DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); /* Wait_for_acks on participant and oneSec timeout */ status = dds_wait_for_acks(participant, oneSec); - cu_assert_status_eq(status, DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); /* Wait_for_acks on participant and DDS_INFINITE timeout */ status = dds_wait_for_acks(participant, DDS_INFINITY); - cu_assert_status_eq(status, DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); publisher = dds_create_publisher(participant, NULL, NULL); CU_ASSERT_FATAL(publisher > 0); @@ -228,40 +226,40 @@ CU_Test(ddsc_publisher, wait_for_acks) /* Wait_for_acks on publisher and minusOneSec timeout -- either BAD_PARAMETER or UNSUPPORTED would be both be ok, really */ status = dds_wait_for_acks(publisher, minusOneSec); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Wait_for_acks on publisher and zeroSec timeout */ status = dds_wait_for_acks(publisher, zeroSec); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Wait_for_acks on publisher and oneSec timeout */ status = dds_wait_for_acks(publisher, oneSec); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Wait_for_acks on publisher and DDS_INFINITE timeout */ status = dds_wait_for_acks(publisher, DDS_INFINITY); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* TODO: create tests by calling dds_qwait_for_acks on writers */ status = dds_suspend(publisher); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Wait_for_acks on suspended publisher and minusOneSec timeout */ status = dds_wait_for_acks(publisher, minusOneSec); - cu_assert_status_eq(status, DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); /* Wait_for_acks on suspended publisher and zeroSec timeout */ status = dds_wait_for_acks(publisher, zeroSec); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Wait_for_acks on suspended publisher and oneSec timeout */ status = dds_wait_for_acks(publisher, oneSec); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); /* Wait_for_acks on suspended publisher and DDS_INFINITE timeout */ status = dds_wait_for_acks(publisher, DDS_INFINITY); - cu_assert_status_eq(status, DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_UNSUPPORTED); dds_delete(publisher); dds_delete(participant); diff --git a/src/core/ddsc/tests/qos.c b/src/core/ddsc/tests/qos.c index a947390..88fe4e6 100644 --- a/src/core/ddsc/tests/qos.c +++ b/src/core/ddsc/tests/qos.c @@ -234,7 +234,7 @@ CU_Test(ddsc_qos, copy_bad_source, .init=qos_init, .fini=qos_fini) dds_return_t result; result = dds_copy_qos(g_qos, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(result), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(result, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_qos, copy_bad_destination, .init=qos_init, .fini=qos_fini) @@ -242,7 +242,7 @@ CU_Test(ddsc_qos, copy_bad_destination, .init=qos_init, .fini=qos_fini) dds_return_t result; result = dds_copy_qos(NULL, g_qos); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(result), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(result, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_qos, copy_with_partition, .init=qos_init, .fini=qos_fini) diff --git a/src/core/ddsc/tests/querycondition.c b/src/core/ddsc/tests/querycondition.c index 107fdd1..d1afbf5 100644 --- a/src/core/ddsc/tests/querycondition.c +++ b/src/core/ddsc/tests/querycondition.c @@ -245,7 +245,7 @@ CU_Test(ddsc_querycondition_create, deleted_reader, .init=querycondition_init, . dds_entity_t cond; dds_delete(g_reader); cond = dds_create_querycondition(g_reader, mask, filter_mod2); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -256,11 +256,10 @@ CU_TheoryDataPoints(ddsc_querycondition_create, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_querycondition_create, invalid_readers, .init=querycondition_init, .fini=querycondition_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t cond; cond = dds_create_querycondition(rdr, mask, filter_mod2); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -273,7 +272,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_querycondition_create, non_readers, .init=qu uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_entity_t cond; cond = dds_create_querycondition(*rdr, mask, filter_mod2); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -297,7 +296,7 @@ CU_Test(ddsc_querycondition_get_mask, deleted, .init=querycondition_init, .fini= dds_delete(condition); mask = 0; ret = dds_get_mask(condition, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -312,7 +311,7 @@ CU_Test(ddsc_querycondition_get_mask, null, .init=querycondition_init, .fini=que DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_get_mask(condition, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); dds_delete(condition); } /*************************************************************************************************/ @@ -323,12 +322,11 @@ CU_TheoryDataPoints(ddsc_querycondition_get_mask, invalid_conditions) = { }; CU_Theory((dds_entity_t cond), ddsc_querycondition_get_mask, invalid_conditions, .init=querycondition_init, .fini=querycondition_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; uint32_t mask; ret = dds_get_mask(cond, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -341,7 +339,7 @@ CU_Theory((dds_entity_t *cond), ddsc_querycondition_get_mask, non_conditions, .i dds_return_t ret; uint32_t mask; ret = dds_get_mask(*cond, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -362,7 +360,7 @@ CU_Theory((uint32_t ss, uint32_t vs, uint32_t is), ddsc_querycondition_get_mask, CU_ASSERT_FATAL(condition > 0); ret = dds_get_mask(condition, &maskOut); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(maskIn, maskOut); dds_delete(condition); @@ -924,7 +922,7 @@ CU_Test(ddsc_querycondition_read, already_deleted, .init=querycondition_init, .f /* Try to read with a deleted condition. */ ret = dds_read(condition, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1487,7 +1485,7 @@ CU_Test(ddsc_querycondition_take, already_deleted, .init=querycondition_init, .f /* Try to take with a deleted condition. */ ret = dds_take(condition, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/read_instance.c b/src/core/ddsc/tests/read_instance.c index 063d003..db46759 100644 --- a/src/core/ddsc/tests/read_instance.c +++ b/src/core/ddsc/tests/read_instance.c @@ -299,7 +299,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, size_t bufsz, u * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_read_instance(*ent, buf, si, bufsz, maxs, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -320,7 +320,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, uint32_t maxs), * invalid and neither is the handle. So, don't test that. */ if ((buf != g_loans) || (si != g_info) || (maxs == 0)) { ret = dds_read_instance_wl(*ent, buf, si, maxs, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -350,7 +350,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, size_t bufsz, u * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_read_instance_mask(*ent, buf, si, bufsz, maxs, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -372,7 +372,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, uint32_t maxs), * invalid and neither is the handle. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_read_instance_mask_wl(*ent, buf, si, maxs, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -394,7 +394,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_read_instance, in { dds_return_t ret; ret = dds_read_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, hdl); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -407,7 +407,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_read_instance_wl, { dds_return_t ret; ret = dds_read_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, hdl); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -421,7 +421,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_read_instance_mas uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, hdl, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -435,7 +435,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_read_instance_mas uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, hdl, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -454,11 +454,10 @@ CU_TheoryDataPoints(ddsc_read_instance, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read_instance, invalid_readers, .init=read_instance_init, .fini=read_instance_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_instance(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -468,11 +467,10 @@ CU_TheoryDataPoints(ddsc_read_instance_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read_instance_wl, invalid_readers, .init=read_instance_init, .fini=read_instance_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_instance_wl(rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -483,11 +481,10 @@ CU_TheoryDataPoints(ddsc_read_instance_mask, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_read_instance_mask, invalid_readers, .init=read_instance_init, .fini=read_instance_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_instance_mask(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -498,11 +495,10 @@ CU_TheoryDataPoints(ddsc_read_instance_mask_wl, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_read_instance_mask_wl, invalid_readers, .init=read_instance_init, .fini=read_instance_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_instance_mask_wl(rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -524,7 +520,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance, non_readers, .init=read_insta { dds_return_t ret; ret = dds_read_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -536,7 +532,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_wl, non_readers, .init=read_in { dds_return_t ret; ret = dds_read_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -549,7 +545,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_mask, non_readers, .init=read_ uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -562,7 +558,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_mask_wl, non_readers, .init=re uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -586,7 +582,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance, already_deleted, .init=read_i ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -600,7 +596,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_wl, already_deleted, .init=rea ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -615,7 +611,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_mask, already_deleted, .init=r ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -630,7 +626,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_instance_mask_wl, already_deleted, .ini ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/readcondition.c b/src/core/ddsc/tests/readcondition.c index 694d463..4566d0c 100644 --- a/src/core/ddsc/tests/readcondition.c +++ b/src/core/ddsc/tests/readcondition.c @@ -227,7 +227,7 @@ CU_Test(ddsc_readcondition_create, deleted_reader, .init=readcondition_init, .fi dds_entity_t cond; dds_delete(g_reader); cond = dds_create_readcondition(g_reader, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -238,11 +238,10 @@ CU_TheoryDataPoints(ddsc_readcondition_create, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_readcondition_create, invalid_readers, .init=readcondition_init, .fini=readcondition_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t cond; cond = dds_create_readcondition(rdr, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -255,7 +254,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_readcondition_create, non_readers, .init=rea uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_entity_t cond; cond = dds_create_readcondition(*rdr, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(cond), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(cond, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -279,7 +278,7 @@ CU_Test(ddsc_readcondition_get_mask, deleted, .init=readcondition_init, .fini=re dds_delete(condition); mask = 0; ret = dds_get_mask(condition, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -294,7 +293,7 @@ CU_Test(ddsc_readcondition_get_mask, null, .init=readcondition_init, .fini=readc DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_get_mask(condition, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); dds_delete(condition); } /*************************************************************************************************/ @@ -305,12 +304,11 @@ CU_TheoryDataPoints(ddsc_readcondition_get_mask, invalid_conditions) = { }; CU_Theory((dds_entity_t cond), ddsc_readcondition_get_mask, invalid_conditions, .init=readcondition_init, .fini=readcondition_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; uint32_t mask; ret = dds_get_mask(cond, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -323,7 +321,7 @@ CU_Theory((dds_entity_t *cond), ddsc_readcondition_get_mask, non_conditions, .in dds_return_t ret; uint32_t mask; ret = dds_get_mask(*cond, &mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -344,7 +342,7 @@ CU_Theory((uint32_t ss, uint32_t vs, uint32_t is), ddsc_readcondition_get_mask, CU_ASSERT_FATAL(condition > 0); ret = dds_get_mask(condition, &maskOut); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(maskIn, maskOut); dds_delete(condition); @@ -906,7 +904,7 @@ CU_Test(ddsc_readcondition_read, already_deleted, .init=readcondition_init, .fin /* Try to read with a deleted condition. */ ret = dds_read(condition, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1462,7 +1460,7 @@ CU_Test(ddsc_readcondition_take, already_deleted, .init=readcondition_init, .fin /* Try to take with a deleted condition. */ ret = dds_take(condition, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/reader.c b/src/core/ddsc/tests/reader.c index ad80be7..2b53b99 100644 --- a/src/core/ddsc/tests/reader.c +++ b/src/core/ddsc/tests/reader.c @@ -241,7 +241,7 @@ CU_Test(ddsc_reader_create, invalid_qos_participant, .init=reader_init, .fini=re dds_qset_reader_data_lifecycle(qos, DDS_SECS(-1), DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); rdr = dds_create_reader(g_participant, g_topic, qos, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(rdr), DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(qos); } /*************************************************************************************************/ @@ -256,7 +256,7 @@ CU_Test(ddsc_reader_create, invalid_qos_subscriber, .init=reader_init, .fini=rea dds_qset_reader_data_lifecycle(qos, DDS_SECS(-1), DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); rdr = dds_create_reader(g_subscriber, g_topic, qos, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(rdr), DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(qos); } /*************************************************************************************************/ @@ -273,7 +273,7 @@ CU_Theory((dds_entity_t *par, dds_entity_t *top), ddsc_reader_create, non_partic * actually the topic. So, don't test that permutation. */ CU_ASSERT_FATAL((par != &g_participant) || (top != &g_topic)); rdr = dds_create_reader(*par, *top, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(rdr), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -307,7 +307,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs), ddsc * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_read(g_reader, buf, si, bufsz, maxs); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -320,11 +320,10 @@ CU_TheoryDataPoints(ddsc_read, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read, invalid_readers, .init=reader_init, .fini=reader_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -336,7 +335,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read, non_readers, .init=reader_init, .fini= { dds_return_t ret; ret = dds_read(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -347,7 +346,7 @@ CU_Test(ddsc_read, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_read(g_reader, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -420,7 +419,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, uint32_t maxs), ddsc_read_wl, inva * invalid. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_read_wl(g_reader, buf, si, maxs); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -430,11 +429,10 @@ CU_TheoryDataPoints(ddsc_read_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read_wl, invalid_readers, .init=reader_init, .fini=reader_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_wl(rdr, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -446,7 +444,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_wl, non_readers, .init=reader_init, .fi { dds_return_t ret; ret = dds_read_wl(*rdr, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -457,7 +455,7 @@ CU_Test(ddsc_read_wl, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_read_wl(g_reader, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -541,7 +539,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs), ddsc * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_read_mask(g_reader, buf, si, bufsz, maxs, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -555,11 +553,10 @@ CU_TheoryDataPoints(ddsc_read_mask, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_read_mask, invalid_readers, .init=reader_init, .fini=reader_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_mask(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -572,7 +569,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_mask, non_readers, .init=reader_init, . uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -584,7 +581,7 @@ CU_Test(ddsc_read_mask, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_read_mask(g_reader, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1092,7 +1089,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, uint32_t maxs), ddsc_read_mask_wl, * invalid. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_read_mask_wl(g_reader, buf, si, maxs, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1103,11 +1100,10 @@ CU_TheoryDataPoints(ddsc_read_mask_wl, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_read_mask_wl, invalid_readers, .init=reader_init, .fini=reader_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_mask_wl(rdr, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1120,7 +1116,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_mask_wl, non_readers, .init=reader_init uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_read_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1132,7 +1128,7 @@ CU_Test(ddsc_read_mask_wl, already_deleted, .init=reader_init, .fini=reader_fini /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_read_mask_wl(g_reader, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1677,7 +1673,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs), ddsc * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_take(g_reader, buf, si, bufsz, maxs); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -1690,11 +1686,10 @@ CU_TheoryDataPoints(ddsc_take, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take, invalid_readers, .init=reader_init, .fini=reader_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1706,7 +1701,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take, non_readers, .init=reader_init, .fini= { dds_return_t ret; ret = dds_take(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1717,7 +1712,7 @@ CU_Test(ddsc_take, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to take with a deleted reader. */ dds_delete(g_reader); ret = dds_take(g_reader, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1790,7 +1785,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, uint32_t maxs), ddsc_take_wl, inva * invalid. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_take_wl(g_reader, buf, si, maxs); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1800,11 +1795,10 @@ CU_TheoryDataPoints(ddsc_take_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take_wl, invalid_readers, .init=reader_init, .fini=reader_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_wl(rdr, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1816,7 +1810,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_wl, non_readers, .init=reader_init, .fi { dds_return_t ret; ret = dds_take_wl(*rdr, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1827,7 +1821,7 @@ CU_Test(ddsc_take_wl, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_take_wl(g_reader, g_loans, g_info, MAX_SAMPLES); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1912,7 +1906,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs), ddsc * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_take_mask(g_reader, buf, si, bufsz, maxs, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -1926,11 +1920,10 @@ CU_TheoryDataPoints(ddsc_take_mask, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_take_mask, invalid_readers, .init=reader_init, .fini=reader_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_mask(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -1943,7 +1936,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_mask, non_readers, .init=reader_init, . uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1955,7 +1948,7 @@ CU_Test(ddsc_take_mask, already_deleted, .init=reader_init, .fini=reader_fini) /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_take_mask(g_reader, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -2596,7 +2589,7 @@ CU_Theory((void **buf, dds_sample_info_t *si, uint32_t maxs), ddsc_take_mask_wl, * invalid. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_take_mask_wl(g_reader, buf, si, maxs, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -2607,11 +2600,10 @@ CU_TheoryDataPoints(ddsc_take_mask_wl, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_take_mask_wl, invalid_readers, .init=reader_init, .fini=reader_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_mask_wl(rdr, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -2624,7 +2616,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_mask_wl, non_readers, .init=reader_init uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -2636,7 +2628,7 @@ CU_Test(ddsc_take_mask_wl, already_deleted, .init=reader_init, .fini=reader_fini /* Try to read with a deleted reader. */ dds_delete(g_reader); ret = dds_take_mask_wl(g_reader, g_loans, g_info, MAX_SAMPLES, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/reader_iterator.c b/src/core/ddsc/tests/reader_iterator.c index c0dbe6a..a714a67 100644 --- a/src/core/ddsc/tests/reader_iterator.c +++ b/src/core/ddsc/tests/reader_iterator.c @@ -360,11 +360,10 @@ CU_TheoryDataPoints(ddsc_read_next, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read_next, invalid_readers, .init=reader_iterator_init, .fini=reader_iterator_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_next(rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -376,7 +375,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_next, non_readers, .init=reader_iterato { dds_return_t ret; ret = dds_read_next(*rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -390,7 +389,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_next, already_deleted, .init=reader_ite ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_next(*rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -405,7 +404,7 @@ CU_Theory((void **buf, dds_sample_info_t *si), ddsc_read_next, invalid_buffers, dds_return_t ret; if ((buf != g_samples || si != g_info) && (buf != g_loans)) { ret = dds_read_next(g_reader, buf, si); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -476,11 +475,10 @@ CU_TheoryDataPoints(ddsc_read_next_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_read_next_wl, invalid_readers, .init=reader_iterator_init, .fini=reader_iterator_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_read_next_wl(rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -492,7 +490,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_next_wl, non_readers, .init=reader_iter { dds_return_t ret; ret = dds_read_next_wl(*rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -506,7 +504,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_read_next_wl, already_deleted, .init=reader_ ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_read_next_wl(*rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -521,7 +519,7 @@ CU_Theory((void **buf, dds_sample_info_t *si), ddsc_read_next_wl, invalid_buffer dds_return_t ret; if (buf != g_loans || si != g_info) { ret = dds_read_next_wl(g_reader, buf, si); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -586,11 +584,10 @@ CU_TheoryDataPoints(ddsc_take_next, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take_next, invalid_readers, .init=reader_iterator_init, .fini=reader_iterator_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_next(rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -602,7 +599,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_next, non_readers, .init=reader_iterato { dds_return_t ret; ret = dds_take_next(*rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -616,7 +613,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_next, already_deleted, .init=reader_ite ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_next(*rdr, g_samples, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -631,7 +628,7 @@ CU_Theory((void **buf, dds_sample_info_t *si), ddsc_take_next, invalid_buffers, dds_return_t ret; if ((buf != g_samples || si != g_info) && (buf != g_loans)) { ret = dds_take_next(g_reader, buf, si); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -699,11 +696,10 @@ CU_TheoryDataPoints(ddsc_take_next_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take_next_wl, invalid_readers, .init=reader_iterator_init, .fini=reader_iterator_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_next_wl(rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -715,7 +711,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_next_wl, non_readers, .init=reader_iter { dds_return_t ret; ret = dds_take_next_wl(*rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -729,7 +725,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_next_wl, already_deleted, .init=reader_ ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_next_wl(*rdr, g_loans, g_info); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -743,7 +739,7 @@ CU_Theory((void **buf, dds_sample_info_t *si), ddsc_take_next_wl, invalid_buffer dds_return_t ret; if (buf != g_loans || si != g_info) { ret = dds_take_next_wl(g_reader, buf, si); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } diff --git a/src/core/ddsc/tests/register.c b/src/core/ddsc/tests/register.c index 11249dd..b04d35f 100644 --- a/src/core/ddsc/tests/register.c +++ b/src/core/ddsc/tests/register.c @@ -150,7 +150,7 @@ CU_Test(ddsc_register_instance, deleted_entity, .init=registering_init, .fini=re dds_instance_handle_t handle; dds_delete(g_writer); ret = dds_register_instance(g_writer, &handle, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } static dds_instance_handle_t hndle = 0; @@ -169,7 +169,7 @@ CU_Theory((dds_instance_handle_t *hndl2, void *datap), ddsc_register_instance, i DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ ret = dds_register_instance(g_writer, hndl2, datap); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_TheoryDataPoints(ddsc_register_instance, invalid_writers) = { @@ -177,12 +177,11 @@ CU_TheoryDataPoints(ddsc_register_instance, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_register_instance, invalid_writers, .init=registering_init, .fini=registering_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; dds_instance_handle_t handle; ret = dds_register_instance(writer, &handle, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } CU_TheoryDataPoints(ddsc_register_instance, non_writers) = { @@ -193,7 +192,7 @@ CU_Theory((dds_entity_t *writer), ddsc_register_instance, non_writers, .init=reg dds_return_t ret; dds_instance_handle_t handle; ret = dds_register_instance(*writer, &handle, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } CU_Test(ddsc_register_instance, registering_new_instance, .init=registering_init, .fini=registering_fini) diff --git a/src/core/ddsc/tests/return_loan.c b/src/core/ddsc/tests/return_loan.c index 365ea76..812e024 100644 --- a/src/core/ddsc/tests/return_loan.c +++ b/src/core/ddsc/tests/return_loan.c @@ -15,9 +15,9 @@ #include #include "CUnit/Test.h" -dds_entity_t participant = 0, topic = 0, reader = 0, read_condition = 0; +static dds_entity_t participant = 0, topic = 0, reader = 0, read_condition = 0; -void create_entities(void) +static void create_entities(void) { participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); @@ -32,11 +32,11 @@ void create_entities(void) CU_ASSERT_FATAL(read_condition > 0); } -void delete_entities(void) +static void delete_entities(void) { dds_return_t result; result = dds_delete(participant); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(result), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(result, DDS_RETCODE_OK); dds_delete(read_condition); } @@ -86,7 +86,7 @@ CU_Test(ddsc_reader, return_loan_bad_params, .init = create_entities, .fini = de void **buf = NULL; result = dds_return_loan(reader, NULL, 0); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); #ifdef _MSC_VER #pragma warning(push) @@ -96,7 +96,7 @@ CU_Test(ddsc_reader, return_loan_bad_params, .init = create_entities, .fini = de #ifdef _MSC_VER #pragma warning(pop) #endif - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); buf = create_loan_buf(10, false); #ifdef _MSC_VER @@ -107,10 +107,10 @@ CU_Test(ddsc_reader, return_loan_bad_params, .init = create_entities, .fini = de #ifdef _MSC_VER #pragma warning(pop) #endif - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); result = dds_return_loan(participant, buf, 0); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL(result, DDS_RETCODE_ILLEGAL_OPERATION); delete_loan_buf(buf, 10, false); } @@ -124,17 +124,17 @@ CU_Test(ddsc_reader, return_loan_success, .init = create_entities, .fini = delet buf = create_loan_buf(10, false); result = dds_return_loan(reader, buf, 10); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_OK); + CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); result = dds_return_loan(reader, &buf2, 0); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_OK); + CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); delete_loan_buf(buf, 10, true); buf = create_loan_buf(10, false); result = dds_return_loan(read_condition, buf, 10); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_OK); + CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); result = dds_return_loan(read_condition, &buf2, 0); - CU_ASSERT_EQUAL(dds_err_nr(result), DDS_RETCODE_OK); + CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); delete_loan_buf(buf, 10, true); } diff --git a/src/core/ddsc/tests/subscriber.c b/src/core/ddsc/tests/subscriber.c index 7e881d1..46696cb 100644 --- a/src/core/ddsc/tests/subscriber.c +++ b/src/core/ddsc/tests/subscriber.c @@ -10,6 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" +#include "dds/ddsrt/misc.h" #include #include "CUnit/Test.h" @@ -48,7 +49,7 @@ CU_Test(ddsc_subscriber, notify_readers) { /* todo implement tests */ ret = dds_notify_readers(subscriber); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_UNSUPPORTED); dds_delete(subscriber); dds_delete(participant); @@ -67,7 +68,7 @@ CU_Test(ddsc_subscriber, create) { /*** Verify participant parameter ***/ subscriber = dds_create_subscriber(0, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(subscriber), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_BAD_PARAMETER); subscriber = dds_create_subscriber(participant, NULL, NULL); CU_ASSERT_FATAL(subscriber > 0); @@ -82,16 +83,20 @@ CU_Test(ddsc_subscriber, create) { dds_delete_qos(sqos); sqos = dds_create_qos(); + DDSRT_WARNING_CLANG_OFF(assign-enum); dds_qset_destination_order(sqos, 3); /* Set invalid dest. order (ignored, not applicable for subscriber) */ + DDSRT_WARNING_CLANG_ON(assign-enum); subscriber = dds_create_subscriber(participant, sqos, NULL); CU_ASSERT_FATAL(subscriber > 0); dds_delete(subscriber); dds_delete_qos(sqos); sqos = dds_create_qos(); + DDSRT_WARNING_CLANG_OFF(assign-enum); dds_qset_presentation(sqos, 123, 1, 1); /* Set invalid presentation policy */ + DDSRT_WARNING_CLANG_ON(assign-enum); subscriber = dds_create_subscriber(participant, sqos, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(subscriber), DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(sqos); /*** Verify listener parameter ***/ diff --git a/src/core/ddsc/tests/take_instance.c b/src/core/ddsc/tests/take_instance.c index 6fba4a6..e8cba48 100644 --- a/src/core/ddsc/tests/take_instance.c +++ b/src/core/ddsc/tests/take_instance.c @@ -299,7 +299,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, size_t bufsz, u * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_take_instance(*ent, buf, si, bufsz, maxs, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -320,7 +320,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, uint32_t maxs), * invalid and neither is the handle. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_take_instance_wl(*ent, buf, si, maxs, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -347,7 +347,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, size_t bufsz, u * However, that's not the case yet. So don't test it. */ if (buf != g_loans) { ret = dds_take_instance_mask(*ent, buf, si, bufsz, maxs, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } else { CU_PASS("Skipped"); } @@ -369,7 +369,7 @@ CU_Theory((dds_entity_t *ent, void **buf, dds_sample_info_t *si, uint32_t maxs), * invalid and neither is the handle. So, don't test that. */ CU_ASSERT_FATAL((buf != g_loans) || (si != g_info) || (maxs == 0)); ret = dds_take_instance_mask_wl(*ent, buf, si, maxs, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -391,7 +391,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_take_instance, in { dds_return_t ret; ret = dds_take_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, hdl); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -404,7 +404,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_take_instance_wl, { dds_return_t ret; ret = dds_take_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, hdl); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -418,7 +418,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_take_instance_mas uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, hdl, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -432,7 +432,7 @@ CU_Theory((dds_entity_t *rdr, dds_instance_handle_t hdl), ddsc_take_instance_mas uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, hdl, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -451,11 +451,10 @@ CU_TheoryDataPoints(ddsc_take_instance, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take_instance, invalid_readers, .init=take_instance_init, .fini=take_instance_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_instance(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -465,11 +464,10 @@ CU_TheoryDataPoints(ddsc_take_instance_wl, invalid_readers) = { }; CU_Theory((dds_entity_t rdr), ddsc_take_instance_wl, invalid_readers, .init=take_instance_init, .fini=take_instance_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_instance_wl(rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -480,11 +478,10 @@ CU_TheoryDataPoints(ddsc_take_instance_mask, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_take_instance_mask, invalid_readers, .init=take_instance_init, .fini=take_instance_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_instance_mask(rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -495,11 +492,10 @@ CU_TheoryDataPoints(ddsc_take_instance_mask_wl, invalid_readers) = { CU_Theory((dds_entity_t rdr), ddsc_take_instance_mask_wl, invalid_readers, .init=take_instance_init, .fini=take_instance_fini) { uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_take_instance_mask_wl(rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -521,7 +517,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance, non_readers, .init=take_insta { dds_return_t ret; ret = dds_take_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -533,7 +529,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_wl, non_readers, .init=take_in { dds_return_t ret; ret = dds_take_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -546,7 +542,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_mask, non_readers, .init=take_ uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -559,7 +555,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_mask_wl, non_readers, .init=ta uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; dds_return_t ret; ret = dds_take_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -583,7 +579,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance, already_deleted, .init=take_i ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_instance(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -597,7 +593,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_wl, already_deleted, .init=tak ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_instance_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -612,7 +608,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_mask, already_deleted, .init=t ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_instance_mask(*rdr, g_samples, g_info, MAX_SAMPLES, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -627,7 +623,7 @@ CU_Theory((dds_entity_t *rdr), ddsc_take_instance_mask_wl, already_deleted, .ini ret = dds_delete(*rdr); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_take_instance_mask_wl(*rdr, g_loans, g_info, MAX_SAMPLES, g_hdl_valid, mask); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/topic.c b/src/core/ddsc/tests/topic.c index 43dde13..d71c8d5 100644 --- a/src/core/ddsc/tests/topic.c +++ b/src/core/ddsc/tests/topic.c @@ -105,10 +105,10 @@ CU_Test(ddsc_topic_create, invalid_qos, .init=ddsc_topic_init, .fini=ddsc_topic_ dds_entity_t topic; dds_qos_t *qos = dds_create_qos(); DDSRT_WARNING_MSVC_OFF(28020); /* Disable SAL warning on intentional misuse of the API */ - dds_qset_lifespan(qos, DDS_SECS(-1)); + dds_qset_resource_limits(qos, 1, 1, 2); DDSRT_WARNING_MSVC_OFF(28020); topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, "inconsistent", qos, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_INCONSISTENT_POLICY); dds_delete_qos(qos); } /*************************************************************************************************/ @@ -118,7 +118,7 @@ CU_Test(ddsc_topic_create, non_participants, .init=ddsc_topic_init, .fini=ddsc_t { dds_entity_t topic; topic = dds_create_topic(g_topicRtmDataType, &RoundTripModule_DataType_desc, "non_participant", NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -141,7 +141,7 @@ CU_Test(ddsc_topic_create, same_name, .init=ddsc_topic_init, .fini=ddsc_topic_fi dds_entity_t topic; /* Creating the different topic with same name should fail. */ topic = dds_create_topic(g_participant, &RoundTripModule_Address_desc, g_topicRtmDataTypeName, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -169,7 +169,7 @@ CU_Test(ddsc_topic_create, desc_null, .init=ddsc_topic_init, .fini=ddsc_topic_fi DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ topic = dds_create_topic (g_participant, NULL, "desc_null", NULL, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -183,7 +183,7 @@ CU_Theory((char *name), ddsc_topic_create, invalid_names, .init=ddsc_topic_init, { dds_entity_t topic; topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, name, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -213,7 +213,7 @@ CU_Test(ddsc_topic_find, non_participants, .init=ddsc_topic_init, .fini=ddsc_top { dds_entity_t topic; topic = dds_find_topic(g_topicRtmDataType, "non_participant"); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -224,7 +224,7 @@ CU_Test(ddsc_topic_find, null, .init=ddsc_topic_init, .fini=ddsc_topic_fini) DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ topic = dds_find_topic(g_participant, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -233,7 +233,7 @@ CU_Test(ddsc_topic_find, unknown, .init=ddsc_topic_init, .fini=ddsc_topic_fini) { dds_entity_t topic; topic = dds_find_topic(g_participant, "unknown"); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -243,7 +243,7 @@ CU_Test(ddsc_topic_find, deleted, .init=ddsc_topic_init, .fini=ddsc_topic_fini) dds_entity_t topic; dds_delete(g_topicRtmDataType); topic = dds_find_topic(g_participant, g_topicRtmDataTypeName); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(topic), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -289,7 +289,7 @@ CU_Test(ddsc_topic_get_name, non_topic, .init=ddsc_topic_init, .fini=ddsc_topic_ char name[MAX_NAME_SIZE]; dds_return_t ret; ret = dds_get_name(g_participant, name, MAX_NAME_SIZE); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -303,7 +303,7 @@ CU_Theory((char *name, size_t size), ddsc_topic_get_name, invalid_params, .init= dds_return_t ret; CU_ASSERT_FATAL((name != g_nameBuffer) || (size != MAX_NAME_SIZE)); ret = dds_get_name(g_topicRtmDataType, name, size); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -314,7 +314,7 @@ CU_Test(ddsc_topic_get_name, deleted, .init=ddsc_topic_init, .fini=ddsc_topic_fi dds_return_t ret; dds_delete(g_topicRtmDataType); ret = dds_get_name(g_topicRtmDataType, name, MAX_NAME_SIZE); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -362,7 +362,7 @@ CU_Test(ddsc_topic_get_type_name, non_topic, .init=ddsc_topic_init, .fini=ddsc_t char name[MAX_NAME_SIZE]; dds_return_t ret; ret = dds_get_type_name(g_participant, name, MAX_NAME_SIZE); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -376,7 +376,7 @@ CU_Theory((char *name, size_t size), ddsc_topic_get_type_name, invalid_params, . dds_return_t ret; CU_ASSERT_FATAL((name != g_nameBuffer) || (size != MAX_NAME_SIZE)); ret = dds_get_type_name(g_topicRtmDataType, name, size); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -387,7 +387,7 @@ CU_Test(ddsc_topic_get_type_name, deleted, .init=ddsc_topic_init, .fini=ddsc_top dds_return_t ret; dds_delete(g_topicRtmDataType); ret = dds_get_type_name(g_topicRtmDataType, name, MAX_NAME_SIZE); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -405,7 +405,7 @@ CU_Test(ddsc_topic_set_qos, valid, .init=ddsc_topic_init, .fini=ddsc_topic_fini) /* Latency is the only one allowed to change. */ dds_qset_latency_budget(g_qos, DDS_SECS(1)); ret = dds_set_qos(g_topicRtmDataType, g_qos); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_UNSUPPORTED); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_UNSUPPORTED); } /*************************************************************************************************/ @@ -417,7 +417,7 @@ CU_Test(ddsc_topic_set_qos, inconsistent, .init=ddsc_topic_init, .fini=ddsc_topi dds_qset_lifespan(g_qos, DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); ret = dds_set_qos(g_topicRtmDataType, g_qos); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -427,6 +427,6 @@ CU_Test(ddsc_topic_set_qos, immutable, .init=ddsc_topic_init, .fini=ddsc_topic_f dds_return_t ret; dds_qset_destination_order(g_qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); /* Immutable */ ret = dds_set_qos(g_topicRtmDataType, g_qos); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_IMMUTABLE_POLICY); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/types.c b/src/core/ddsc/tests/types.c index a2f6c28..427fe53 100644 --- a/src/core/ddsc/tests/types.c +++ b/src/core/ddsc/tests/types.c @@ -30,7 +30,7 @@ CU_ASSERT_FATAL(wri > 0); \ \ status = dds_write(wri, &data); \ - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); \ + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); \ \ dds_delete(wri); \ dds_delete(top); \ @@ -114,7 +114,7 @@ CU_Test(ddsc_types, alltypeskey) CU_ASSERT_FATAL(wri > 0); status = dds_write(wri, &atk_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_delete(wri); dds_delete(top); diff --git a/src/core/ddsc/tests/unregister.c b/src/core/ddsc/tests/unregister.c index e27eb32..538c661 100644 --- a/src/core/ddsc/tests/unregister.c +++ b/src/core/ddsc/tests/unregister.c @@ -152,7 +152,7 @@ CU_Test(ddsc_unregister_instance, deleted, .init=unregistering_init, .fini=unreg dds_delete(g_writer); ret = dds_unregister_instance(g_writer, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -161,7 +161,7 @@ CU_Test(ddsc_unregister_instance, null, .init=unregistering_init, .fini=unregist { dds_return_t ret; ret = dds_unregister_instance(g_writer, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -171,11 +171,10 @@ CU_TheoryDataPoints(ddsc_unregister_instance, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_unregister_instance, invalid_writers, .init=unregistering_init, .fini=unregistering_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_unregister_instance(writer, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -187,7 +186,7 @@ CU_Theory((dds_entity_t *writer), ddsc_unregister_instance, non_writers, .init=u { dds_return_t ret; ret = dds_unregister_instance(*writer, g_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -246,7 +245,7 @@ CU_Test(ddsc_unregister_instance_ts, deleted, .init=unregistering_init, .fini=un dds_return_t ret; dds_delete(g_writer); ret = dds_unregister_instance_ts(g_writer, g_data, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -255,7 +254,7 @@ CU_Test(ddsc_unregister_instance_ts, null, .init=unregistering_init, .fini=unreg { dds_return_t ret; ret = dds_unregister_instance_ts(g_writer, NULL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -265,11 +264,10 @@ CU_TheoryDataPoints(ddsc_unregister_instance_ts, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_unregister_instance_ts, invalid_writers, .init=unregistering_init, .fini=unregistering_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_unregister_instance_ts(writer, g_data, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -281,7 +279,7 @@ CU_Theory((dds_entity_t *writer), ddsc_unregister_instance_ts, non_writers, .ini { dds_return_t ret; ret = dds_unregister_instance_ts(*writer, g_data, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -383,7 +381,7 @@ CU_Test(ddsc_unregister_instance_ih, deleted, .init=unregistering_init, .fini=un dds_return_t ret; dds_delete(g_writer); ret = dds_unregister_instance_ih(g_writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -395,7 +393,7 @@ CU_Theory((dds_instance_handle_t handle), ddsc_unregister_instance_ih, invalid_h { dds_return_t ret; ret = dds_unregister_instance_ih(g_writer, handle); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -405,11 +403,10 @@ CU_TheoryDataPoints(ddsc_unregister_instance_ih, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_unregister_instance_ih, invalid_writers, .init=unregistering_init, .fini=unregistering_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_unregister_instance_ih(writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -421,7 +418,7 @@ CU_Theory((dds_entity_t *writer), ddsc_unregister_instance_ih, non_writers, .ini { dds_return_t ret; ret = dds_unregister_instance_ih(*writer, DDS_HANDLE_NIL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -481,7 +478,7 @@ CU_Test(ddsc_unregister_instance_ih_ts, deleted, .init=unregistering_init, .fini dds_return_t ret; dds_delete(g_writer); ret = dds_unregister_instance_ih_ts(g_writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -493,7 +490,7 @@ CU_Theory((dds_instance_handle_t handle), ddsc_unregister_instance_ih_ts, invali { dds_return_t ret; ret = dds_unregister_instance_ih_ts(g_writer, handle, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -503,11 +500,10 @@ CU_TheoryDataPoints(ddsc_unregister_instance_ih_ts, invalid_writers) = { }; CU_Theory((dds_entity_t writer), ddsc_unregister_instance_ih_ts, invalid_writers, .init=unregistering_init, .fini=unregistering_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_unregister_instance_ih_ts(writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -519,7 +515,7 @@ CU_Theory((dds_entity_t *writer), ddsc_unregister_instance_ih_ts, non_writers, . { dds_return_t ret; ret = dds_unregister_instance_ih_ts(*writer, DDS_HANDLE_NIL, g_present); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -609,6 +605,37 @@ CU_Test(ddsc_unregister_instance_ih_ts, unregistering_past_sample, .init=unregis } /*************************************************************************************************/ +/*************************************************************************************************/ +CU_Test(ddsc_unregister_instance_ih_ts, unregistering_instance) +{ + Space_Type1 testData = { 0, 22, 22 }; + dds_instance_handle_t ih = 0; + dds_return_t ret; + char name[100]; + + /* Create a writer that WILL automatically dispose unregistered samples. */ + g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(g_participant > 0); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_unregistering_instance_test", name, 100), NULL, NULL); + CU_ASSERT_FATAL(g_topic > 0); + g_writer = dds_create_writer(g_participant, g_topic, NULL, NULL); + CU_ASSERT_FATAL(g_writer > 0); + + /* Register the instance. */ + ret = dds_register_instance(g_writer, &ih, &testData); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + CU_ASSERT_NOT_EQUAL_FATAL(ih, DDS_HANDLE_NIL); + + /* Unregister the instance. */ + ret = dds_unregister_instance_ih_ts(g_writer, ih, dds_time()); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + dds_delete(g_writer); + dds_delete(g_topic); + dds_delete(g_participant); +} +/*************************************************************************************************/ + /*************************************************************************************************/ CU_Test(ddsc_unregister_instance, dispose_unregistered_sample, .init=unregistering_init, .fini=unregistering_fini) { diff --git a/src/core/ddsc/tests/unsupported.c b/src/core/ddsc/tests/unsupported.c index 68bf4a5..b7e63cb 100644 --- a/src/core/ddsc/tests/unsupported.c +++ b/src/core/ddsc/tests/unsupported.c @@ -76,11 +76,11 @@ CU_Test(ddsc_unsupported, dds_begin_end_coherent, .init = setup, .fini = teardow {BAD, DDS_RETCODE_BAD_PARAMETER} }; - for (int i=0; i < 5; i++) { + for (size_t i=0; i < sizeof (pars) / sizeof (pars[0]);i++) { result = dds_begin_coherent(e[pars[i].index]); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); result = dds_end_coherent(e[pars[i].index]); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); } } @@ -93,9 +93,9 @@ CU_Test(ddsc_unsupported, dds_wait_for_acks, .init = setup, .fini = teardown) {BAD, DDS_RETCODE_BAD_PARAMETER} }; - for (int i=0; i< 3; i++) { + for (size_t i=0; i < sizeof (pars) / sizeof (pars[0]);i++) { result = dds_wait_for_acks(e[pars[i].index], 0); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); } } @@ -108,11 +108,11 @@ CU_Test(ddsc_unsupported, dds_suspend_resume, .init = setup, .fini = teardown) {BAD, DDS_RETCODE_BAD_PARAMETER} }; - for (int i=0; i< 3; i++) { + for (size_t i=0; i < sizeof (pars) / sizeof (pars[0]);i++) { result = dds_suspend(e[pars[i].index]); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); result = dds_resume(e[pars[i].index]); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); } } @@ -121,16 +121,19 @@ CU_Test(ddsc_unsupported, dds_get_instance_handle, .init = setup, .fini = teardo dds_return_t result; dds_instance_handle_t ih; static struct index_result pars[] = { - {TOP, DDS_RETCODE_ILLEGAL_OPERATION}, /* TODO: Shouldn't this be either supported or unsupported? */ - {PUB, DDS_RETCODE_UNSUPPORTED}, - {SUB, DDS_RETCODE_UNSUPPORTED}, - {RCD, DDS_RETCODE_ILLEGAL_OPERATION}, + {TOP, DDS_RETCODE_OK}, + {PUB, DDS_RETCODE_OK}, + {SUB, DDS_RETCODE_OK}, + {RCD, DDS_RETCODE_OK}, {BAD, DDS_RETCODE_BAD_PARAMETER} }; - for (int i=0; i < 5; i++) { + for (size_t i=0; i < sizeof (pars) / sizeof (pars[0]);i++) { result = dds_get_instance_handle(e[pars[i].index], &ih); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); + if (pars[i].exp_res == DDS_RETCODE_OK) { + CU_ASSERT(ih > 0); + } } } @@ -139,20 +142,14 @@ CU_Test(ddsc_unsupported, dds_set_qos, .init = setup, .fini = teardown) dds_return_t result; dds_qos_t *qos; static struct index_result pars[] = { - {PAR, DDS_RETCODE_UNSUPPORTED}, - {TOP, DDS_RETCODE_UNSUPPORTED}, - {PUB, DDS_RETCODE_UNSUPPORTED}, - {WRI, DDS_RETCODE_UNSUPPORTED}, - {SUB, DDS_RETCODE_UNSUPPORTED}, - {REA, DDS_RETCODE_UNSUPPORTED}, {RCD, DDS_RETCODE_ILLEGAL_OPERATION}, {BAD, DDS_RETCODE_BAD_PARAMETER} }; qos = dds_create_qos(); - for (int i=0; i < 8;i++) { + for (size_t i=0; i < sizeof (pars) / sizeof (pars[0]);i++) { result = dds_set_qos(e[pars[i].index], qos); - CU_ASSERT_EQUAL(dds_err_nr(result), pars[i].exp_res); + CU_ASSERT_EQUAL(result, pars[i].exp_res); } dds_delete_qos(qos); } diff --git a/src/core/ddsc/tests/waitset.c b/src/core/ddsc/tests/waitset.c index 9c401cb..42e4a82 100644 --- a/src/core/ddsc/tests/waitset.c +++ b/src/core/ddsc/tests/waitset.c @@ -20,6 +20,7 @@ #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "dds/ddsrt/atomics.h" #include "dds/ddsrt/time.h" /************************************************************************************************** @@ -36,7 +37,7 @@ typedef enum thread_state_t { typedef struct thread_arg_t { ddsrt_thread_t tid; - thread_state_t state; + ddsrt_atomic_uint32_t state; dds_entity_t expected; } thread_arg_t; @@ -226,7 +227,7 @@ CU_Test(ddsc_waitset_create, deleted_participant, .init=ddsc_waitset_basic_init, deleted = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); dds_delete(deleted); ws = dds_create_waitset(deleted); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ws), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ws, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -236,11 +237,10 @@ CU_TheoryDataPoints(ddsc_waitset_create, invalid_params) = { }; CU_Theory((dds_entity_t par), ddsc_waitset_create, invalid_params, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { - dds_entity_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t ws; ws = dds_create_waitset(par); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ws), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ws, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -252,7 +252,7 @@ CU_Theory((dds_entity_t *par), ddsc_waitset_create, non_participants, .init=ddsc { dds_entity_t ws; ws = dds_create_waitset(*par); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ws), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ws, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -276,7 +276,7 @@ CU_Theory((dds_entity_t e, dds_attach_t a), ddsc_waitset_attach, invalid_params, { dds_return_t ret; ret = dds_waitset_attach(waitset, e, a); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -287,11 +287,10 @@ CU_TheoryDataPoints(ddsc_waitset_attach, invalid_waitsets) = { }; CU_Theory((dds_entity_t ws, dds_attach_t a), ddsc_waitset_attach, invalid_waitsets, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_waitset_attach(ws, participant, a); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -305,7 +304,7 @@ CU_Theory((dds_entity_t *ws, dds_entity_t *e, dds_attach_t a), ddsc_waitset_atta { dds_return_t ret; ret = dds_waitset_attach(*ws, *e, a); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -315,7 +314,7 @@ CU_Test(ddsc_waitset_attach, deleted_waitset, .init=ddsc_waitset_basic_init, .fi dds_return_t ret; dds_delete(waitset); ret = dds_waitset_attach(waitset, participant, 0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -347,7 +346,7 @@ CU_Theory((dds_entity_t *ws, dds_entity_t *e, dds_attach_t a), ddsc_waitset_atta /* Try to attach. */ ret = dds_waitset_attach(*ws, *e, a); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), exp); + CU_ASSERT_EQUAL_FATAL(ret, exp); /* Detach when needed. */ if (ret == DDS_RETCODE_OK) { @@ -366,13 +365,13 @@ CU_Test(ddsc_waitset_attach_detach, second, .init=ddsc_waitset_basic_init, .fini CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_waitset_attach(waitset, waitset, 0); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); ret = dds_waitset_detach(waitset, waitset); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ret = dds_waitset_detach(waitset, waitset); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_PRECONDITION_NOT_MET); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); } /*************************************************************************************************/ @@ -399,7 +398,7 @@ CU_Theory((dds_entity_t e), ddsc_waitset_detach, invalid_params, .init=ddsc_wait { dds_return_t ret; ret = dds_waitset_detach(waitset, e); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -409,11 +408,10 @@ CU_TheoryDataPoints(ddsc_waitset_detach, invalid_waitsets) = { }; CU_Theory((dds_entity_t ws), ddsc_waitset_detach, invalid_waitsets, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_waitset_detach(ws, participant); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -436,7 +434,7 @@ CU_Theory((dds_entity_t *ws, dds_entity_t *e), ddsc_waitset_detach, valid_entiti } ret = dds_waitset_detach(*ws, *e); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), exp); + CU_ASSERT_EQUAL_FATAL(ret, exp); } /*************************************************************************************************/ @@ -580,7 +578,7 @@ CU_Test(ddsc_waitset_set_trigger, deleted_waitset, .init=ddsc_waitset_basic_init dds_return_t ret; dds_delete(waitset); ret = dds_waitset_set_trigger(waitset, true); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -590,11 +588,10 @@ CU_TheoryDataPoints(ddsc_waitset_set_trigger, invalid_params) = { }; CU_Theory((dds_entity_t ws), ddsc_waitset_set_trigger, invalid_params, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_waitset_set_trigger(ws, true); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -606,7 +603,7 @@ CU_Theory((dds_entity_t *ws), ddsc_waitset_set_trigger, non_waitsets, .init=ddsc { dds_return_t ret; ret = dds_waitset_set_trigger(*ws, true); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -625,7 +622,7 @@ CU_Test(ddsc_waitset_wait, deleted_waitset, .init=ddsc_waitset_attached_init, .f dds_return_t ret; dds_delete(waitset); ret = dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -636,11 +633,10 @@ CU_TheoryDataPoints(ddsc_waitset_wait, invalid_waitsets) = { CU_Theory((dds_entity_t ws), ddsc_waitset_wait, invalid_waitsets, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { dds_attach_t triggered; - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_waitset_wait(ws, &triggered, 1, DDS_SECS(1)); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -653,7 +649,7 @@ CU_Theory((dds_entity_t *ws), ddsc_waitset_wait, non_waitsets, .init=ddsc_waitse dds_attach_t triggered; dds_return_t ret; ret = dds_waitset_wait(*ws, &triggered, 1, DDS_SECS(1)); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -672,7 +668,7 @@ CU_Theory((dds_attach_t *a, size_t size, int msec), ddsc_waitset_wait, invalid_p CU_ASSERT_FATAL(((a == NULL) && (size != 0)) || ((a != NULL) && (size == 0)) || (msec < 0)); ret = dds_waitset_wait(waitset, a, size, DDS_MSECS(msec)); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -683,7 +679,7 @@ CU_Test(ddsc_waitset_wait_until, deleted_waitset, .init=ddsc_waitset_attached_in dds_return_t ret; dds_delete(waitset); ret = dds_waitset_wait_until(waitset, &triggered, 1, dds_time()); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -694,11 +690,10 @@ CU_TheoryDataPoints(ddsc_waitset_wait_until, invalid_waitsets) = { CU_Theory((dds_entity_t ws), ddsc_waitset_wait_until, invalid_waitsets, .init=ddsc_waitset_basic_init, .fini=ddsc_waitset_basic_fini) { dds_attach_t triggered; - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_return_t ret; ret = dds_waitset_wait_until(ws, &triggered, 1, dds_time()); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -711,7 +706,7 @@ CU_Theory((dds_entity_t *ws), ddsc_waitset_wait_until, non_waitsets, .init=ddsc_ dds_attach_t triggered; dds_return_t ret; ret = dds_waitset_wait_until(*ws, &triggered, 1, dds_time()); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -729,7 +724,7 @@ CU_Theory((dds_attach_t *a, size_t size), ddsc_waitset_wait_until, invalid_param CU_ASSERT_FATAL(((a == NULL) && (size != 0)) || ((a != NULL) && (size == 0))); ret = dds_waitset_wait_until(waitset, a, size, dds_time()); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -843,7 +838,7 @@ CU_Test(ddsc_waitset_get_entities, deleted_waitset, .init=ddsc_waitset_attached_ dds_entity_t entities[MAX_ENTITIES_CNT]; dds_delete(waitset); ret = dds_waitset_get_entities(waitset, entities, MAX_ENTITIES_CNT); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -853,12 +848,11 @@ CU_TheoryDataPoints(ddsc_waitset_get_entities, invalid_params) = { }; CU_Theory((dds_entity_t ws), ddsc_waitset_get_entities, invalid_params, .init=ddsc_waitset_attached_init, .fini=ddsc_waitset_attached_fini) { - dds_return_t exp = DDS_RETCODE_BAD_PARAMETER * -1; dds_entity_t entities[MAX_ENTITIES_CNT]; dds_return_t ret; ret = dds_waitset_get_entities(ws, entities, MAX_ENTITIES_CNT); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), dds_err_nr(exp)); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ @@ -871,7 +865,7 @@ CU_Theory((dds_entity_t *ws), ddsc_waitset_get_entities, non_waitsets, .init=dds dds_entity_t entities[MAX_ENTITIES_CNT]; dds_return_t ret; ret = dds_waitset_get_entities(*ws, entities, MAX_ENTITIES_CNT); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(ret), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ILLEGAL_OPERATION); } /*************************************************************************************************/ @@ -1063,26 +1057,26 @@ waiting_thread(void *a) dds_attach_t triggered; dds_return_t ret; - arg->state = WAITING; + ddsrt_atomic_st32 (&arg->state, WAITING); /* This should block until the main test released all claims. */ ret = dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1000)); CU_ASSERT_EQUAL_FATAL(ret, 1); CU_ASSERT_EQUAL_FATAL(arg->expected, (dds_entity_t)(intptr_t)triggered); - arg->state = STOPPED; + ddsrt_atomic_st32 (&arg->state, STOPPED); return 0; } -static dds_retcode_t -thread_reached_state(thread_state_t *actual, thread_state_t expected, int32_t msec) +static dds_return_t +thread_reached_state(ddsrt_atomic_uint32_t *actual, thread_state_t expected, int32_t msec) { /* Convenience function. */ dds_time_t msec10 = DDS_MSECS(10); - while ((msec > 0) && (*actual != expected)) { + while ((msec > 0) && ((thread_state_t) ddsrt_atomic_ld32 (actual) != expected)) { dds_sleepfor(msec10); msec -= 10; } - return (*actual == expected) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; + return ((thread_state_t) ddsrt_atomic_ld32 (actual) == expected) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; } static void @@ -1090,13 +1084,13 @@ waiting_thread_start(struct thread_arg_t *arg, dds_entity_t expected) { ddsrt_thread_t thread_id; ddsrt_threadattr_t thread_attr; - dds_retcode_t rc; + dds_return_t rc; assert(arg); /* Create an other thread that will blocking wait on the waitset. */ arg->expected = expected; - arg->state = STARTING; + ddsrt_atomic_st32 (&arg->state, STARTING); ddsrt_threadattr_init(&thread_attr); rc = ddsrt_thread_create(&thread_id, "waiting_thread", &thread_attr, waiting_thread, arg); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); @@ -1115,7 +1109,7 @@ waiting_thread_start(struct thread_arg_t *arg, dds_entity_t expected) static dds_return_t waiting_thread_expect_exit(struct thread_arg_t *arg) { - dds_retcode_t rc; + dds_return_t rc; assert(arg); rc = thread_reached_state(&(arg->state), STOPPED, 5000); if (rc == DDS_RETCODE_OK) { diff --git a/src/core/ddsc/tests/write.c b/src/core/ddsc/tests/write.c index 2cd3f15..b5523ce 100644 --- a/src/core/ddsc/tests/write.c +++ b/src/core/ddsc/tests/write.c @@ -65,7 +65,7 @@ CU_Test(ddsc_write, basic, .init = setup, .fini = teardown) dds_return_t status; status = dds_write(writer, &data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); } CU_Test(ddsc_write, null_writer, .init = setup, .fini = teardown) @@ -76,7 +76,7 @@ CU_Test(ddsc_write, null_writer, .init = setup, .fini = teardown) DDSRT_WARNING_MSVC_OFF(28020); status = dds_write(0, &data); DDSRT_WARNING_MSVC_ON(28020); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_write, bad_writer, .init = setup, .fini = teardown) @@ -84,7 +84,7 @@ CU_Test(ddsc_write, bad_writer, .init = setup, .fini = teardown) dds_return_t status; status = dds_write(publisher, &data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_ILLEGAL_OPERATION); } CU_Test(ddsc_write, closed_writer, .init = setup, .fini = teardown) @@ -92,10 +92,10 @@ CU_Test(ddsc_write, closed_writer, .init = setup, .fini = teardown) dds_return_t status; status = dds_delete(writer); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); status = dds_write(writer, &data); writer = 0; - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_write, null_sample, .init = setup, .fini = teardown) @@ -107,7 +107,7 @@ CU_Test(ddsc_write, null_sample, .init = setup, .fini = teardown) status = dds_write(writer, NULL); DDSRT_WARNING_MSVC_ON(6387); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_write_ts, basic, .init = setup, .fini = teardown) @@ -115,7 +115,7 @@ CU_Test(ddsc_write_ts, basic, .init = setup, .fini = teardown) dds_return_t status; status = dds_write_ts(writer, &data, dds_time()); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); } CU_Test(ddsc_write_ts, bad_timestamp, .init = setup, .fini = teardown) @@ -123,7 +123,7 @@ CU_Test(ddsc_write_ts, bad_timestamp, .init = setup, .fini = teardown) dds_return_t status; status = dds_write_ts(writer, &data, -1); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_write, simpletypes) @@ -152,7 +152,7 @@ CU_Test(ddsc_write, simpletypes) CU_ASSERT_FATAL(wri > 0); status = dds_write(wri, &st_data); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(status), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); dds_delete(wri); dds_delete(top); diff --git a/src/core/ddsc/tests/writer.c b/src/core/ddsc/tests/writer.c index 66ce1ea..4a9a8c2 100644 --- a/src/core/ddsc/tests/writer.c +++ b/src/core/ddsc/tests/writer.c @@ -57,13 +57,13 @@ CU_Test(ddsc_create_writer, null_parent, .init = setup, .fini = teardown) DDSRT_WARNING_MSVC_OFF(28020); /* Disable SAL warning on intentional misuse of the API */ writer = dds_create_writer(0, topic, NULL, NULL); DDSRT_WARNING_MSVC_ON(28020); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_create_writer, bad_parent, .init = setup, .fini = teardown) { writer = dds_create_writer(topic, topic, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_ILLEGAL_OPERATION); } CU_Test(ddsc_create_writer, participant, .init = setup, .fini = teardown) @@ -83,7 +83,7 @@ CU_Test(ddsc_create_writer, deleted_publisher, .init = setup, .fini = teardown) dds_delete(publisher); writer = dds_create_writer(publisher, topic, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_create_writer, null_topic, .init = setup, .fini = teardown) @@ -91,13 +91,13 @@ CU_Test(ddsc_create_writer, null_topic, .init = setup, .fini = teardown) DDSRT_WARNING_MSVC_OFF(28020); /* Disable SAL warning on intentional misuse of the API */ writer = dds_create_writer(publisher, 0, NULL, NULL); DDSRT_WARNING_MSVC_ON(28020); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER); } CU_Test(ddsc_create_writer, bad_topic, .init = setup, .fini = teardown) { writer = dds_create_writer(publisher, publisher, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_ILLEGAL_OPERATION); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_ILLEGAL_OPERATION); } CU_Test(ddsc_create_writer, deleted_topic, .init = setup, .fini = teardown) @@ -105,5 +105,5 @@ CU_Test(ddsc_create_writer, deleted_topic, .init = setup, .fini = teardown) dds_delete(topic); writer = dds_create_writer(publisher, topic, NULL, NULL); - CU_ASSERT_EQUAL_FATAL(dds_err_nr(writer), DDS_RETCODE_BAD_PARAMETER); + CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER); } diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index 4a6bb0f..c245722 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -22,7 +22,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" ddsi_serdata_default.c ddsi_sertopic.c ddsi_sertopic_default.c - ddsi_rhc_plugin.c ddsi_iid.c ddsi_tkmap.c ddsi_vendor.c @@ -54,6 +53,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" q_transmit.c q_inverse_uint32_set.c q_whc.c + q_rhc.c q_xevent.c q_xmsg.c q_freelist.c @@ -73,11 +73,11 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" ddsi_serdata.h ddsi_sertopic.h ddsi_serdata_default.h - ddsi_rhc_plugin.h ddsi_iid.h ddsi_tkmap.h ddsi_vendor.h ddsi_threadmon.h + ddsi_builtin_topic_if.h q_addrset.h q_bitset.h q_bswap.h @@ -86,7 +86,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_debmon.h q_entity.h q_ephash.h - q_error.h q_feature_check.h q_freelist.h q_gc.h @@ -103,10 +102,10 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_qosmatch.h q_radmin.h q_receive.h + q_rhc.h q_rtps.h q_security.h q_sockwaitset.h - q_static_assert.h q_thread.h q_time.h q_transmit.h diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h b/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h new file mode 100644 index 0000000..0032160 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h @@ -0,0 +1,53 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef _DDSI_BUILTIN_TOPIC_IF_H_ +#define _DDSI_BUILTIN_TOPIC_IF_H_ + +#include "dds/ddsi/ddsi_vendor.h" +#include "dds/ddsi/q_time.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +struct entity_common; +struct ddsi_tkmap_instance; +struct ddsi_sertopic; +struct nn_guid; + +struct ddsi_builtin_topic_interface { + void *arg; + + bool (*builtintopic_is_builtintopic) (const struct ddsi_sertopic *topic, void *arg); + bool (*builtintopic_is_visible) (const struct nn_guid *guid, nn_vendorid_t vendorid, void *arg); + struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct nn_guid *guid, void *arg); + void (*builtintopic_write) (const struct entity_common *e, nn_wctime_t timestamp, bool alive, void *arg); +}; + +inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid) { + return btif ? btif->builtintopic_is_visible (guid, vendorid, btif->arg) : false; +} +inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic) { + return btif ? btif->builtintopic_is_builtintopic (topic, btif->arg) : false; +} +inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid) { + return btif ? btif->builtintopic_get_tkmap_entry (guid, btif->arg) : NULL; +} +inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive) { + if (btif) btif->builtintopic_write (e, timestamp, alive, btif->arg); +} + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h b/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h index 9c7f1d3..96257fa 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h @@ -18,7 +18,7 @@ extern "C" { #endif -enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface *interf); +enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface *interf); enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str, int32_t kind); int ddsi_ipaddr_compare (const struct sockaddr *const sa1, const struct sockaddr *const sa2); char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h b/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h index f4dc36f..37b403c 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h @@ -22,10 +22,10 @@ struct nn_group_membership; struct nn_group_membership *new_group_membership (void); void free_group_membership (struct nn_group_membership *mship); -int ddsi_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip); -int ddsi_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip); -void ddsi_transfer_group_membership (ddsi_tran_conn_t conn, ddsi_tran_conn_t newconn); -int ddsi_rejoin_transferred_mcgroups (ddsi_tran_conn_t conn); +int ddsi_join_mc (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip); +int ddsi_leave_mc (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip); +void ddsi_transfer_group_membership (struct nn_group_membership *mship, ddsi_tran_conn_t conn, ddsi_tran_conn_t newconn); +int ddsi_rejoin_transferred_mcgroups (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h b/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h index da60a24..54b4479 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h @@ -16,7 +16,7 @@ extern "C" { #endif -int ddsi_raweth_init (void); +int ddsi_raweth_init (struct q_globals *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_rhc_plugin.h b/src/core/ddsi/include/dds/ddsi/ddsi_rhc_plugin.h deleted file mode 100644 index 1d37ecf..0000000 --- a/src/core/ddsi/include/dds/ddsi/ddsi_rhc_plugin.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 DDSI_RHC_PLUGIN_H -#define DDSI_RHC_PLUGIN_H - -#if defined (__cplusplus) -extern "C" { -#endif - -struct rhc; -struct nn_xqos; -struct ddsi_tkmap_instance; -struct ddsi_serdata; -struct ddsi_sertopic; -struct entity_common; - -struct proxy_writer_info -{ - nn_guid_t guid; - bool auto_dispose; - int32_t ownership_strength; - uint64_t iid; -}; - -struct ddsi_rhc_plugin -{ - void (*rhc_free_fn) (struct rhc *rhc); - bool (*rhc_store_fn) - (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, - struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); - void (*rhc_unregister_wr_fn) - (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); - void (*rhc_relinquish_ownership_fn) - (struct rhc * __restrict rhc, const uint64_t wr_iid); - void (*rhc_set_qos_fn) (struct rhc * rhc, const struct nn_xqos * qos); -}; - -DDS_EXPORT void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct nn_xqos *xqos); - -#if defined (__cplusplus) -} -#endif - -#endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h index c61bb97..ae582ff 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h @@ -13,7 +13,7 @@ #define DDSI_SERDATA_DEFAULT_H #include "dds/ddsrt/endian.h" -#include "dds/ddsi/q_plist.h" /* for nn_prismtech_writer_info */ +#include "dds/ddsi/q_protocol.h" /* for nn_parameterid_t */ #include "dds/ddsi/q_freelist.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_serdata.h" @@ -43,33 +43,58 @@ struct serdatapool { struct nn_freelist freelist; }; -typedef struct dds_key_hash { - char m_hash [16]; /* Key hash value. Also possibly key. Suitably aligned for accessing as uint32_t's */ +typedef struct dds_keyhash { + unsigned char m_hash [16]; /* Key hash value. Also possibly key. Suitably aligned for accessing as uint32_t's */ unsigned m_set : 1; /* has it been initialised? */ unsigned m_iskey : 1; /* m_hash is key value */ -} -dds_key_hash_t; +} dds_keyhash_t; + +/* Debug builds may want to keep some additional state */ +#ifndef NDEBUG +#define DDSI_SERDATA_DEFAULT_DEBUG_FIELDS \ + bool fixed; +#else +#define DDSI_SERDATA_DEFAULT_DEBUG_FIELDS +#endif + +/* There is an alignment requirement on the raw data (it must be at + offset mod 8 for the conversion to/from a dds_stream to work). + So we define two types: one without any additional padding, and + one where the appropriate amount of padding is inserted */ +#define DDSI_SERDATA_DEFAULT_PREPAD \ + struct ddsi_serdata c; \ + uint32_t pos; \ + uint32_t size; \ + DDSI_SERDATA_DEFAULT_DEBUG_FIELDS \ + dds_keyhash_t keyhash; \ + struct serdatapool *serpool; \ + struct ddsi_serdata_default *next /* in pool->freelist */ +#define DDSI_SERDATA_DEFAULT_POSTPAD \ + struct CDRHeader hdr; \ + char data[] + +struct ddsi_serdata_default_unpadded { + DDSI_SERDATA_DEFAULT_PREPAD; + DDSI_SERDATA_DEFAULT_POSTPAD; +}; + +#ifdef __GNUC__ +#define DDSI_SERDATA_DEFAULT_PAD(n) ((n) % 8) +#else +#define DDSI_SERDATA_DEFAULT_PAD(n) (n) +#endif struct ddsi_serdata_default { - struct ddsi_serdata c; - uint32_t pos; - uint32_t size; -#ifndef NDEBUG - bool fixed; -#endif - dds_key_hash_t keyhash; - - struct serdatapool *pool; - struct ddsi_serdata_default *next; /* in pool->freelist */ - - /* padding to ensure CDRHeader is at an offset 4 mod 8 from the - start of the memory, so that data is 8-byte aligned provided - serdata is 8-byte aligned */ - char pad[8 - ((sizeof (struct ddsi_serdata) + 4) % 8)]; - struct CDRHeader hdr; - char data[1]; + DDSI_SERDATA_DEFAULT_PREPAD; + char pad[DDSI_SERDATA_DEFAULT_PAD (8 - (offsetof (struct ddsi_serdata_default_unpadded, data) % 8))]; + DDSI_SERDATA_DEFAULT_POSTPAD; }; +#undef DDSI_SERDATA_DEFAULT_PAD +#undef DDSI_SERDATA_DEFAULT_POSTPAD +#undef DDSI_SERDATA_DEFAULT_PREPAD +#undef DDSI_SERDATA_DEFAULT_FIXED_FIELD + struct dds_key_descriptor; struct dds_topic_descriptor; @@ -81,6 +106,7 @@ typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx); struct ddsi_sertopic_default { struct ddsi_sertopic c; uint16_t native_encoding_identifier; /* (PL_)?CDR_(LE|BE) */ + struct serdatapool *serpool; struct dds_topic_descriptor * type; unsigned nkeys; diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h b/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h index 3f7ae75..e23333c 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h @@ -22,27 +22,32 @@ extern "C" { struct ddsi_serdata; struct ddsi_serdata_ops; - -struct dds_topic; -typedef void (*topic_cb_t) (struct dds_topic * topic); - struct ddsi_sertopic_ops; struct ddsi_sertopic { - ddsrt_avl_node_t avlnode; /* index on name_typename */ const struct ddsi_sertopic_ops *ops; const struct ddsi_serdata_ops *serdata_ops; uint32_t serdata_basehash; + bool topickind_no_key; char *name_type_name; char *name; char *type_name; uint64_t iid; ddsrt_atomic_uint32_t refc; /* counts refs from entities, not from data */ - - topic_cb_t status_cb; - struct dds_topic * status_cb_entity; }; +/* The old and the new happen to have the same memory layout on a 64-bit machine + and so any user that memset's the ddsi_sertopic to 0 before filling out the + required fields gets unchanged behaviour. 32-bit machines have a different + layout and no such luck. + + There are presumably very few users of this type outside Cyclone DDS itself, + but the ROS2 RMW implementation does use it -- indeed, it prompted the change. + This define makes it possible to have a single version of the source that is + compatible with the old and the new definition, even if it is only partially + binary compatible. */ +#define DDSI_SERTOPIC_HAS_TOPICKIND_NO_KEY 1 + /* Called when the refcount dropped to zero */ typedef void (*ddsi_sertopic_free_t) (struct ddsi_sertopic *tp); @@ -63,6 +68,9 @@ struct ddsi_sertopic_ops { ddsi_sertopic_free_samples_t free_samples; }; +DDS_EXPORT void ddsi_sertopic_init (struct ddsi_sertopic *tp, const char *name, const char *type_name, const struct ddsi_sertopic_ops *sertopic_ops, const struct ddsi_serdata_ops *serdata_ops, bool topickind_no_key); +DDS_EXPORT void ddsi_sertopic_init_anon (struct ddsi_sertopic *tp, const struct ddsi_sertopic_ops *sertopic_ops, const struct ddsi_serdata_ops *serdata_ops, bool topickind_no_key); +DDS_EXPORT void ddsi_sertopic_fini (struct ddsi_sertopic *tp); DDS_EXPORT struct ddsi_sertopic *ddsi_sertopic_ref (const struct ddsi_sertopic *tp); DDS_EXPORT void ddsi_sertopic_unref (struct ddsi_sertopic *tp); DDS_EXPORT uint32_t ddsi_sertopic_compute_serdata_basehash (const struct ddsi_serdata_ops *ops); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h b/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h index 380dac3..d6d5eb7 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h @@ -24,28 +24,28 @@ extern "C" { struct ddsi_ssl_plugins { - bool (*init) (void); + bool (*init) (struct q_globals *gv); void (*fini) (void); void (*ssl_free) (SSL *ssl); void (*bio_vfree) (BIO *bio); - ssize_t (*read) (SSL *ssl, void *buf, size_t len, dds_retcode_t *err); - ssize_t (*write) (SSL *ssl, const void *msg, size_t len, dds_retcode_t *err); - SSL * (*connect) (ddsrt_socket_t sock); + ssize_t (*read) (SSL *ssl, void *buf, size_t len, dds_return_t *err); + ssize_t (*write) (SSL *ssl, const void *msg, size_t len, dds_return_t *err); + SSL * (*connect) (const struct q_globals *gv, ddsrt_socket_t sock); BIO * (*listen) (ddsrt_socket_t sock); - SSL * (*accept) (BIO *bio, ddsrt_socket_t *sock); + SSL * (*accept) (const struct q_globals *gv, BIO *bio, ddsrt_socket_t *sock); }; #if defined (__cplusplus) } #endif -#endif +#endif /* DDSI_INCLUDE_SSL */ #if defined (__cplusplus) extern "C" { #endif -int ddsi_tcp_init (void); +int ddsi_tcp_init (struct q_globals *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h b/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h index 7d9d346..18d5bc7 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h @@ -17,12 +17,14 @@ extern "C" { #endif struct ddsi_threadmon; +struct q_globals; -struct ddsi_threadmon *ddsi_threadmon_new (void); -int ddsi_threadmon_start (struct ddsi_threadmon *sl); +struct ddsi_threadmon *ddsi_threadmon_new (int64_t liveliness_monitoring_interval, bool noprogress_log_stacktraces); +dds_return_t ddsi_threadmon_start (struct ddsi_threadmon *sl, const char *name); +void ddsi_threadmon_register_domain (struct ddsi_threadmon *sl, const struct q_globals *gv); +void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct q_globals *gv); void ddsi_threadmon_stop (struct ddsi_threadmon *sl); void ddsi_threadmon_free (struct ddsi_threadmon *sl); -void ddsi_threadmon_statechange_barrier (struct ddsi_threadmon *sl); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h index 2029bd7..3461d63 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h @@ -22,22 +22,23 @@ extern "C" { struct ddsi_tkmap; struct ddsi_serdata; struct dds_topic; +struct q_globals; struct ddsi_tkmap_instance { - struct ddsi_serdata * m_sample; + struct ddsi_serdata *m_sample; uint64_t m_iid; ddsrt_atomic_uint32_t m_refc; }; -DDS_EXPORT struct ddsi_tkmap * ddsi_tkmap_new (void); +DDS_EXPORT struct ddsi_tkmap *ddsi_tkmap_new (struct q_globals *gv); DDS_EXPORT void ddsi_tkmap_free (struct ddsi_tkmap *tkmap); DDS_EXPORT void ddsi_tkmap_instance_ref (struct ddsi_tkmap_instance *tk); DDS_EXPORT uint64_t ddsi_tkmap_lookup (struct ddsi_tkmap *tkmap, const struct ddsi_serdata *serdata); -DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find(struct ddsi_serdata *sd, const bool rd, const bool create); +DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find(struct ddsi_tkmap *map, struct ddsi_serdata *sd, const bool create); DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find_by_id (struct ddsi_tkmap *map, uint64_t iid); -DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_lookup_instance_ref (struct ddsi_serdata * sd); -DDS_EXPORT void ddsi_tkmap_instance_unref (struct ddsi_tkmap_instance *tk); +DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_lookup_instance_ref (struct ddsi_tkmap *map, struct ddsi_serdata * sd); +DDS_EXPORT void ddsi_tkmap_instance_unref (struct ddsi_tkmap *map, struct ddsi_tkmap_instance *tk); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h index 11b48cb..a3e5d89 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h @@ -17,6 +17,7 @@ #include "dds/ddsrt/ifaddrs.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsi/q_protocol.h" +#include "dds/ddsi/q_config.h" #if defined (__cplusplus) extern "C" { @@ -51,16 +52,16 @@ typedef struct ddsi_tran_qos * ddsi_tran_qos_t; typedef ssize_t (*ddsi_tran_read_fn_t) (ddsi_tran_conn_t, unsigned char *, size_t, bool, nn_locator_t *); typedef ssize_t (*ddsi_tran_write_fn_t) (ddsi_tran_conn_t, const nn_locator_t *, size_t, const ddsrt_iovec_t *, uint32_t); -typedef int (*ddsi_tran_locator_fn_t) (ddsi_tran_base_t, nn_locator_t *); -typedef bool (*ddsi_tran_supports_fn_t) (int32_t); +typedef int (*ddsi_tran_locator_fn_t) (ddsi_tran_factory_t, ddsi_tran_base_t, nn_locator_t *); +typedef bool (*ddsi_tran_supports_fn_t) (const struct ddsi_tran_factory *, int32_t); typedef ddsrt_socket_t (*ddsi_tran_handle_fn_t) (ddsi_tran_base_t); typedef int (*ddsi_tran_listen_fn_t) (ddsi_tran_listener_t); -typedef void (*ddsi_tran_free_fn_t) (void); +typedef void (*ddsi_tran_free_fn_t) (ddsi_tran_factory_t); typedef void (*ddsi_tran_peer_locator_fn_t) (ddsi_tran_conn_t, nn_locator_t *); typedef void (*ddsi_tran_disable_multiplexing_fn_t) (ddsi_tran_conn_t); typedef ddsi_tran_conn_t (*ddsi_tran_accept_fn_t) (ddsi_tran_listener_t); -typedef ddsi_tran_conn_t (*ddsi_tran_create_conn_fn_t) (uint32_t, ddsi_tran_qos_t); -typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (int port, ddsi_tran_qos_t); +typedef ddsi_tran_conn_t (*ddsi_tran_create_conn_fn_t) (ddsi_tran_factory_t fact, uint32_t, ddsi_tran_qos_t); +typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t); typedef void (*ddsi_tran_release_conn_fn_t) (ddsi_tran_conn_t); typedef void (*ddsi_tran_close_conn_fn_t) (ddsi_tran_conn_t); typedef void (*ddsi_tran_unblock_listener_fn_t) (ddsi_tran_listener_t); @@ -76,7 +77,7 @@ enum ddsi_nearby_address_result { DNAR_SAME }; -typedef enum ddsi_nearby_address_result (*ddsi_is_nearby_address_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface *interf); +typedef enum ddsi_nearby_address_result (*ddsi_is_nearby_address_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface *interf); enum ddsi_locator_from_string_result { AFSR_OK, /* conversion succeeded */ @@ -89,10 +90,10 @@ typedef enum ddsi_locator_from_string_result (*ddsi_locator_from_string_fn_t) (d typedef char * (*ddsi_locator_to_string_fn_t) (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port); -typedef int (*ddsi_enumerate_interfaces_fn_t) (ddsi_tran_factory_t tran, ddsrt_ifaddrs_t **interfs); +typedef int (*ddsi_enumerate_interfaces_fn_t) (ddsi_tran_factory_t tran, enum transport_selector transport_selector, ddsrt_ifaddrs_t **interfs); /* Data types */ - +struct q_globals; struct ddsi_tran_base { /* Data */ @@ -100,10 +101,10 @@ struct ddsi_tran_base uint32_t m_port; uint32_t m_trantype; bool m_multicast; + struct q_globals *gv; /* Functions */ - ddsi_tran_locator_fn_t m_locator_fn; ddsi_tran_handle_fn_t m_handle_fn; }; @@ -117,6 +118,7 @@ struct ddsi_tran_conn ddsi_tran_write_fn_t m_write_fn; ddsi_tran_peer_locator_fn_t m_peer_locator_fn; ddsi_tran_disable_multiplexing_fn_t m_disable_multiplexing_fn; + ddsi_tran_locator_fn_t m_locator_fn; /* Data */ @@ -141,6 +143,7 @@ struct ddsi_tran_listener ddsi_tran_listen_fn_t m_listen_fn; ddsi_tran_accept_fn_t m_accept_fn; + ddsi_tran_locator_fn_t m_locator_fn; /* Relationships */ @@ -173,10 +176,11 @@ struct ddsi_tran_factory /* Data */ int32_t m_kind; - const char * m_typename; - const char * m_default_spdp_address; + const char *m_typename; + const char *m_default_spdp_address; bool m_connless; bool m_stream; + struct q_globals *gv; /* Relationships */ @@ -191,21 +195,21 @@ struct ddsi_tran_qos int m_diffserv; }; -void ddsi_tran_factories_fini (void); -void ddsi_factory_add (ddsi_tran_factory_t factory); +void ddsi_tran_factories_fini (struct q_globals *gv); +void ddsi_factory_add (struct q_globals *gv, ddsi_tran_factory_t factory); void ddsi_factory_free (ddsi_tran_factory_t factory); -ddsi_tran_factory_t ddsi_factory_find (const char * type); -ddsi_tran_factory_t ddsi_factory_find_supported_kind (int32_t kind); -void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn); +ddsi_tran_factory_t ddsi_factory_find (const struct q_globals *gv, const char * type); +ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct q_globals *gv, int32_t kind); +void ddsi_factory_conn_init (const struct ddsi_tran_factory *factory, ddsi_tran_conn_t conn); -inline bool ddsi_factory_supports (ddsi_tran_factory_t factory, int32_t kind) { - return factory->m_supports_fn (kind); +inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind) { + return factory->m_supports_fn (factory, kind); } inline ddsi_tran_conn_t ddsi_factory_create_conn (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos) { - return factory->m_create_conn_fn (port, qos); + return factory->m_create_conn_fn (factory, port, qos); } inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos) { - return factory->m_create_listener_fn (port, qos); + return factory->m_create_listener_fn (factory, port, qos); } void ddsi_tran_free (ddsi_tran_base_t base); @@ -214,10 +218,6 @@ ddsi_tran_qos_t ddsi_tran_create_qos (void); inline ddsrt_socket_t ddsi_tran_handle (ddsi_tran_base_t base) { return base->m_handle_fn (base); } -inline int ddsi_tran_locator (ddsi_tran_base_t base, nn_locator_t * loc) { - return base->m_locator_fn (base, loc); -} - inline ddsrt_socket_t ddsi_conn_handle (ddsi_tran_conn_t conn) { return conn->m_base.m_handle_fn (&conn->m_base); } @@ -228,7 +228,7 @@ inline uint32_t ddsi_conn_port (ddsi_tran_conn_t conn) { return conn->m_base.m_port; } inline int ddsi_conn_locator (ddsi_tran_conn_t conn, nn_locator_t * loc) { - return conn->m_base.m_locator_fn (&conn->m_base, loc); + return conn->m_locator_fn (conn->m_factory, &conn->m_base, loc); } inline ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const ddsrt_iovec_t *iov, uint32_t flags) { return conn->m_closed ? -1 : (conn->m_write_fn) (conn, dst, niov, iov, flags); @@ -244,11 +244,11 @@ int ddsi_conn_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const n int ddsi_conn_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcip, const nn_locator_t *mcip, const struct nn_interface *interf); void ddsi_conn_transfer_group_membership (ddsi_tran_conn_t conn, ddsi_tran_conn_t newconn); int ddsi_conn_rejoin_transferred_mcgroups (ddsi_tran_conn_t conn); -int ddsi_is_mcaddr (const nn_locator_t *loc); -int ddsi_is_ssm_mcaddr (const nn_locator_t *loc); -enum ddsi_nearby_address_result ddsi_is_nearby_address (const nn_locator_t *loc, size_t ninterf, const struct nn_interface *interf); +int ddsi_is_mcaddr (const struct q_globals *gv, const nn_locator_t *loc); +int ddsi_is_ssm_mcaddr (const struct q_globals *gv, const nn_locator_t *loc); +enum ddsi_nearby_address_result ddsi_is_nearby_address (const struct q_globals *gv, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface *interf); -enum ddsi_locator_from_string_result ddsi_locator_from_string (nn_locator_t *loc, const char *str); +enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct q_globals *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory); /* 8 for transport/ 1 for [ @@ -261,13 +261,13 @@ enum ddsi_locator_from_string_result ddsi_locator_from_string (nn_locator_t *loc */ #define DDSI_LOCSTRLEN 70 -char *ddsi_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc); -char *ddsi_locator_to_string_no_port (char *dst, size_t sizeof_dst, const nn_locator_t *loc); +char *ddsi_locator_to_string (const struct q_globals *gv, char *dst, size_t sizeof_dst, const nn_locator_t *loc); +char *ddsi_locator_to_string_no_port (const struct q_globals *gv, char *dst, size_t sizeof_dst, const nn_locator_t *loc); -int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, ddsrt_ifaddrs_t **interfs); +int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, enum transport_selector transport_selector, ddsrt_ifaddrs_t **interfs); -inline int ddsi_listener_locator (ddsi_tran_listener_t listener, nn_locator_t * loc) { - return listener->m_base.m_locator_fn (&listener->m_base, loc); +inline int ddsi_listener_locator (ddsi_tran_listener_t listener, nn_locator_t *loc) { + return listener->m_locator_fn (listener->m_factory, &listener->m_base, loc); } inline int ddsi_listener_listen (ddsi_tran_listener_t listener) { return listener->m_listen_fn (listener); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_udp.h b/src/core/ddsi/include/dds/ddsi/ddsi_udp.h index 1305dab..888452c 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_udp.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_udp.h @@ -16,7 +16,15 @@ extern "C" { #endif -int ddsi_udp_init (void); +typedef struct nn_udpv4mcgen_address { + /* base IPv4 MC address is ipv4, host bits are bits base .. base+count-1, this machine is bit idx */ + struct in_addr ipv4; + uint8_t base; + uint8_t count; + uint8_t idx; /* must be last: then sorting will put them consecutively */ +} nn_udpv4mcgen_address_t; + +int ddsi_udp_init (struct q_globals *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_vendor.h b/src/core/ddsi/include/dds/ddsi/ddsi_vendor.h index 02c277b..c6faa62 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_vendor.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_vendor.h @@ -60,6 +60,9 @@ inline bool vendor_is_opensplice (nn_vendorid_t vendor) { inline bool vendor_is_twinoaks (nn_vendorid_t vendor) { return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_TWINOAKS }}); } +inline bool vendor_is_eprosima (nn_vendorid_t vendor) { + return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_EPROSIMA }}); +} inline bool vendor_is_cloud (nn_vendorid_t vendor) { return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_CLOUD }}); } diff --git a/src/core/ddsi/include/dds/ddsi/q_addrset.h b/src/core/ddsi/include/dds/ddsi/q_addrset.h index 22476d5..669061f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_addrset.h +++ b/src/core/ddsi/include/dds/ddsi/q_addrset.h @@ -39,16 +39,16 @@ typedef ssize_t (*addrset_forone_fun_t) (const nn_locator_t *loc, void *arg); struct addrset *new_addrset (void); struct addrset *ref_addrset (struct addrset *as); void unref_addrset (struct addrset *as); -void add_to_addrset (struct addrset *as, const nn_locator_t *loc); -void remove_from_addrset (struct addrset *as, const nn_locator_t *loc); +void add_to_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc); +void remove_from_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc); int addrset_purge (struct addrset *as); int compare_locators (const nn_locator_t *a, const nn_locator_t *b); /* These lock ASADD, then lock/unlock AS any number of times, then unlock ASADD */ -void copy_addrset_into_addrset_uc (struct addrset *as, const struct addrset *asadd); -void copy_addrset_into_addrset_mc (struct addrset *as, const struct addrset *asadd); -void copy_addrset_into_addrset (struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset_uc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset_mc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd); size_t addrset_count (const struct addrset *as); size_t addrset_count_uc (const struct addrset *as); @@ -63,7 +63,7 @@ int addrset_any_mc (const struct addrset *as, nn_locator_t *dst); int addrset_forone (struct addrset *as, addrset_forone_fun_t f, void *arg); void addrset_forall (struct addrset *as, addrset_forall_fun_t f, void *arg); size_t addrset_forall_count (struct addrset *as, addrset_forall_fun_t f, void *arg); -void nn_log_addrset (uint32_t tf, const char *prefix, const struct addrset *as); +void nn_log_addrset (struct q_globals *gv, uint32_t tf, const char *prefix, const struct addrset *as); /* Tries to lock A then B for a decent check, returning false if trylock B fails */ @@ -72,15 +72,15 @@ int addrset_eq_onesidederr (const struct addrset *a, const struct addrset *b); int is_unspec_locator (const nn_locator_t *loc); void set_unspec_locator (nn_locator_t *loc); -int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc); +struct q_globals; +int add_addresses_to_addrset (const struct q_globals *gv, struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc); #ifdef DDSI_INCLUDE_SSM -int addrset_contains_ssm (const struct addrset *as); -int addrset_any_ssm (const struct addrset *as, nn_locator_t *dst); -int addrset_any_non_ssm_mc (const struct addrset *as, nn_locator_t *dst); -void copy_addrset_into_addrset_no_ssm_mc (struct addrset *as, const struct addrset *asadd); -void copy_addrset_into_addrset_no_ssm (struct addrset *as, const struct addrset *asadd); -void addrset_pruge_ssm (struct addrset *as); +int addrset_contains_ssm (const struct q_globals *gv, const struct addrset *as); +int addrset_any_ssm (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst); +int addrset_any_non_ssm_mc (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst); +void copy_addrset_into_addrset_no_ssm_mc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset_no_ssm (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd); #endif #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/q_bswap.h b/src/core/ddsi/include/dds/ddsi/q_bswap.h index 6f8cbff..b186f69 100644 --- a/src/core/ddsi/include/dds/ddsi/q_bswap.h +++ b/src/core/ddsi/include/dds/ddsi/q_bswap.h @@ -95,10 +95,10 @@ nn_entityid_t nn_ntoh_entityid (nn_entityid_t e); nn_guid_t nn_hton_guid (nn_guid_t g); nn_guid_t nn_ntoh_guid (nn_guid_t g); -void bswap_sequence_number_set_hdr (nn_sequence_number_set_t *snset); -void bswap_sequence_number_set_bitmap (nn_sequence_number_set_t *snset); -void bswap_fragment_number_set_hdr (nn_fragment_number_set_t *fnset); -void bswap_fragment_number_set_bitmap (nn_fragment_number_set_t *fnset); +void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset); +void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits); +void bswap_fragment_number_set_hdr (nn_fragment_number_set_header_t *fnset); +void bswap_fragment_number_set_bitmap (nn_fragment_number_set_header_t *fnset, uint32_t *bits); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h index 08f3d6e..ffd1ede 100644 --- a/src/core/ddsi/include/dds/ddsi/q_config.h +++ b/src/core/ddsi/include/dds/ddsi/q_config.h @@ -18,9 +18,7 @@ #include "dds/ddsi/q_security.h" #endif /* DDSI_INCLUDE_ENCRYPTION */ #include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/q_feature_check.h" -#include "dds/ddsi/ddsi_rhc_plugin.h" #if defined (__cplusplus) extern "C" { @@ -38,8 +36,8 @@ enum nn_standards_conformance { NN_SC_LAX }; -#define NN_PEDANTIC_P (config.standards_conformance <= NN_SC_PEDANTIC) -#define NN_STRICT_P (config.standards_conformance <= NN_SC_STRICT) +#define NN_PEDANTIC_P(config) ((config).standards_conformance <= NN_SC_PEDANTIC) +#define NN_STRICT_P(config) ((config).standards_conformance <= NN_SC_STRICT) enum besmode { BESMODE_FULL, @@ -184,7 +182,7 @@ struct prune_deleted_ppant { int enforce_delay; }; -/* allow multicast bits: */ +/* allow multicast bits (default depends on network type): */ #define AMC_FALSE 0u #define AMC_SPDP 1u #define AMC_ASM 2u @@ -194,6 +192,7 @@ struct prune_deleted_ppant { #else #define AMC_TRUE (AMC_SPDP | AMC_ASM) #endif +#define AMC_DEFAULT 0x80000000u /* FIXME: this should be fully dynamic ... but this is easier for a quick hack */ enum transport_selector { @@ -225,7 +224,7 @@ struct ssl_min_version { struct config { int valid; - uint32_t enabled_logcats; + uint32_t tracemask; uint32_t enabled_xchecks; char *servicename; char *pcap_file; @@ -234,20 +233,21 @@ struct config char **networkRecvAddressStrings; char *externalAddressString; char *externalMaskString; - FILE *tracingOutputFile; - char *tracingOutputFileName; + FILE *tracefp; + char *tracefile; int tracingTimestamps; int tracingAppendToFile; - unsigned allowMulticast; + uint32_t allowMulticast; + int prefer_multicast; enum transport_selector transport_selector; enum boolean_default compat_use_ipv6; enum boolean_default compat_tcp_enable; int dontRoute; int enableMulticastLoopback; - struct config_maybe_int32 domainId; + uint32_t domainId; int participantIndex; int maxAutoParticipantIndex; - int port_base; + uint32_t port_base; char *spdpMulticastAddressString; char *defaultMulticastAddressString; char *assumeMulticastCapable; @@ -329,7 +329,6 @@ struct config uint32_t rmsg_chunk_size; /**<< size of a chunk in the receive buffer */ uint32_t rbuf_size; /* << size of a single receiver buffer */ enum besmode besmode; - int conservative_builtin_reader_startup; int meas_hb_to_ack_latency; int unicast_response_to_spdp_messages; int synchronous_delivery_priority_threshold; @@ -372,15 +371,14 @@ struct config enum nn_standards_conformance standards_conformance; int explicitly_publish_qos_set_to_default; enum many_sockets_mode many_sockets_mode; - int arrival_of_data_asserts_pp_and_ep_liveliness; int assume_rti_has_pmd_endpoints; - int port_dg; - int port_pg; - int port_d0; - int port_d1; - int port_d2; - int port_d3; + uint32_t port_dg; + uint32_t port_pg; + uint32_t port_d0; + uint32_t port_d1; + uint32_t port_d2; + uint32_t port_d3; int monitor_port; @@ -393,35 +391,20 @@ struct config struct prune_deleted_ppant prune_deleted_ppant; }; -struct ddsi_plugin -{ - int (*init_fn) (void); - void (*fini_fn) (void); - - bool (*builtintopic_is_visible) (nn_entityid_t entityid, bool onlylocal, nn_vendorid_t vendorid); - struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct nn_guid *guid); - void (*builtintopic_write) (const struct entity_common *e, nn_wctime_t timestamp, bool alive); - - /* Read cache */ - struct ddsi_rhc_plugin rhc_plugin; -}; - -extern struct config DDS_EXPORT config; -extern struct ddsi_plugin ddsi_plugin; - struct cfgst; -struct cfgst *config_init (const char *configfile); -void config_print_cfgst (struct cfgst *cfgst); +struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid); +void config_print_cfgst (struct cfgst *cfgst, const struct ddsrt_log_cfg *logcfg); +void config_free_source_info (struct cfgst *cfgst); void config_fini (struct cfgst *cfgst); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -struct config_partitionmapping_listelem *find_partitionmapping (const char *partition, const char *topic); -struct config_networkpartition_listelem *find_networkpartition_by_id (uint32_t id); -int is_ignored_partition (const char *partition, const char *topic); +struct config_partitionmapping_listelem *find_partitionmapping (const struct config *cfg, const char *partition, const char *topic); +struct config_networkpartition_listelem *find_networkpartition_by_id (const struct config *cfg, uint32_t id); +int is_ignored_partition (const struct config *cfg, const char *partition, const char *topic); #endif #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -struct config_channel_listelem *find_channel (nn_transport_priority_qospolicy_t transport_priority); +struct config_channel_listelem *find_channel (const struct config *cfg, nn_transport_priority_qospolicy_t transport_priority); #endif #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h b/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h index 72b5de6..ea0e29a 100644 --- a/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h +++ b/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h @@ -35,8 +35,6 @@ int sedp_dispose_unregister_reader (struct reader *rd); int sedp_write_topic (struct participant *pp, const struct nn_plist *datap); int sedp_write_cm_participant (struct participant *pp, int alive); -int sedp_write_cm_publisher (const struct nn_plist *datap, int alive); -int sedp_write_cm_subscriber (const struct nn_plist *datap, int alive); int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg); diff --git a/src/core/ddsi/include/dds/ddsi/q_debmon.h b/src/core/ddsi/include/dds/ddsi/q_debmon.h index 77348c2..defb83e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_debmon.h +++ b/src/core/ddsi/include/dds/ddsi/q_debmon.h @@ -20,7 +20,7 @@ struct debug_monitor; typedef int (*debug_monitor_cpf_t) (ddsi_tran_conn_t conn, const char *fmt, ...); typedef int (*debug_monitor_plugin_t) (ddsi_tran_conn_t conn, debug_monitor_cpf_t cpf, void *arg); -struct debug_monitor *new_debug_monitor (int port); +struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port); void add_debug_monitor_plugin (struct debug_monitor *dm, debug_monitor_plugin_t fn, void *arg); void free_debug_monitor (struct debug_monitor *dm); diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h index 4c0c4bd..fb5b825 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -38,7 +38,7 @@ struct nn_rdata; struct addrset; struct ddsi_sertopic; struct whc; -struct nn_xqos; +struct dds_qos; struct nn_plist; struct lease; @@ -123,7 +123,6 @@ struct pwr_rd_match { union { struct { seqno_t end_of_tl_seq; /* when seq >= end_of_tl_seq, it's in sync, =0 when not tl */ - seqno_t end_of_out_of_sync_seq; /* when seq >= end_of_tl_seq, it's in sync, =0 when not tl */ struct nn_reorder *reorder; /* can be done (mostly) per proxy writer, but that is harder; only when state=OUT_OF_SYNC */ } not_in_sync; } u; @@ -142,13 +141,25 @@ struct entity_common { struct ddsi_tkmap_instance *tk; ddsrt_mutex_t lock; bool onlylocal; + struct q_globals *gv; + + /* QoS changes always lock the entity itself, and additionally + (and within the scope of the entity lock) acquire qos_lock + while manipulating the QoS. So any thread that needs to read + the QoS without acquiring the entity's lock can still do so + (e.g., the materialisation of samples for built-in topics + when connecting a reader to a writer for a built-in topic). + + qos_lock lock order across entities in is in increasing + order of entity addresses cast to uintptr_t. */ + ddsrt_mutex_t qos_lock; }; struct local_reader_ary { ddsrt_mutex_t rdary_lock; unsigned valid: 1; /* always true until (proxy-)writer is being deleted; !valid => !fastpath_ok */ unsigned fastpath_ok: 1; /* if not ok, fall back to using GUIDs (gives access to the reader-writer match data for handling readers that bumped into resource limits, hence can flip-flop, unlike "valid") */ - unsigned n_readers; + uint32_t n_readers; struct reader **rdary; /* for efficient delivery, null-pointer terminated */ }; @@ -159,9 +170,9 @@ struct avail_entityid_set { struct participant { struct entity_common e; - long long lease_duration; /* constant */ - unsigned bes; /* built-in endpoint set */ - unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */ + dds_duration_t lease_duration; /* constant */ + uint32_t bes; /* built-in endpoint set */ + uint32_t prismtech_bes; /* prismtech-specific extension of built-in endpoints set */ unsigned is_ddsi2_pp: 1; /* true for the "federation leader", the ddsi2 participant itself in OSPL; FIXME: probably should use this for broker mode as well ... */ struct nn_plist *plist; /* settings/QoS for this participant */ struct xevent *spdp_xevent; /* timed event for periodically publishing SPDP */ @@ -229,7 +240,7 @@ struct writer nn_count_t hbfragcount; /* last hb frag seq number */ int throttling; /* non-zero when some thread is waiting for the WHC to shrink */ struct hbcontrol hbcontrol; /* controls heartbeat timing, piggybacking */ - struct nn_xqos *xqos; + struct dds_qos *xqos; enum writer_state state; unsigned reliable: 1; /* iff 1, writer is reliable <=> heartbeat_xevent != NULL */ unsigned handle_as_transient_local: 1; /* controls whether data is retained in WHC */ @@ -243,7 +254,7 @@ struct writer struct addrset *as; /* set of addresses to publish to */ struct addrset *as_group; /* alternate case, used for SPDP, when using Cloud with multiple bootstrap locators */ struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */ - long long lease_duration; + dds_duration_t lease_duration; struct whc *whc; /* WHC tracking history, T-L durability service history + samples by sequence number for retransmit */ uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */ nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */ @@ -271,7 +282,7 @@ struct reader status_cb_t status_cb; void * status_cb_entity; struct rhc * rhc; /* reader history, tracks registrations and data */ - struct nn_xqos *xqos; + struct dds_qos *xqos; unsigned reliable: 1; /* 1 iff reader is reliable */ unsigned handle_as_transient_local: 1; /* 1 iff reader wants historical data from proxy writers */ #ifdef DDSI_INCLUDE_SSM @@ -302,6 +313,7 @@ struct proxy_participant struct addrset *as_meta; /* default address set to use for discovery traffic */ struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */ ddsrt_avl_tree_t groups; /* table of all groups (publisher, subscriber), see struct proxy_group */ + seqno_t seq; /* sequence number of most recent SPDP message */ unsigned kernel_sequence_numbers : 1; /* whether this proxy participant generates OSPL kernel sequence numbers */ unsigned implicitly_created : 1; /* participants are implicitly created for Cloud/Fog discovered endpoints */ unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */ @@ -324,7 +336,7 @@ struct proxy_group { nn_guid_t guid; char *name; struct proxy_participant *proxypp; /* uncounted backref to proxy participant */ - struct nn_xqos *xqos; /* publisher/subscriber QoS */ + struct dds_qos *xqos; /* publisher/subscriber QoS */ }; struct proxy_endpoint_common @@ -332,11 +344,12 @@ struct proxy_endpoint_common struct proxy_participant *proxypp; /* counted backref to proxy participant */ struct proxy_endpoint_common *next_ep; /* next \ endpoint belonging to this proxy participant */ struct proxy_endpoint_common *prev_ep; /* prev / -- this is in arbitrary ordering */ - struct nn_xqos *xqos; /* proxy endpoint QoS lives here; FIXME: local ones should have it moved to common as well */ + struct dds_qos *xqos; /* proxy endpoint QoS lives here; FIXME: local ones should have it moved to common as well */ struct ddsi_sertopic * topic; /* topic may be NULL: for built-ins, but also for never-yet matched proxies (so we don't have to know the topic; when we match, we certainly do know) */ struct addrset *as; /* address set to use for communicating with this endpoint */ nn_guid_t group_guid; /* 0:0:0:0 if not available */ nn_vendorid_t vendor; /* cached from proxypp->vendor */ + seqno_t seq; /* sequence number of most recent SEDP message */ }; struct proxy_writer { @@ -352,7 +365,6 @@ struct proxy_writer { unsigned last_fragnum_reset: 1; /* iff set, heartbeat advertising last_seq as highest seq resets last_fragnum */ unsigned deliver_synchronously: 1; /* iff 1, delivery happens straight from receive thread for non-historical data; else through delivery queue "dqueue" */ unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */ - unsigned assert_pp_lease: 1; /* iff 1, renew the proxy-participant's lease when data comes in */ unsigned local_matching_inprogress: 1; /* iff 1, we are still busy matching local readers; this is so we don't deliver incoming data to some but not all readers initially */ #ifdef DDSI_INCLUDE_SSM unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */ @@ -371,7 +383,6 @@ struct proxy_reader { struct proxy_endpoint_common c; unsigned deleting: 1; /* set when being deleted */ unsigned is_fict_trans_reader: 1; /* only true when it is certain that is a fictitious transient data reader (affects built-in topic generation) */ - unsigned assert_pp_lease: 1; /* iff 1, renew the proxy-participant's lease when data comes in */ #ifdef DDSI_INCLUDE_SSM unsigned favours_ssm: 1; /* iff 1, this proxy reader favours SSM when available */ #endif @@ -388,10 +399,10 @@ extern const ddsrt_avl_treedef_t deleted_participants_treedef; #define DPG_LOCAL 1 #define DPG_REMOTE 2 - -int deleted_participants_admin_init (void); -void deleted_participants_admin_fini (void); -int is_deleted_participant_guid (const struct nn_guid *guid, unsigned for_what); +struct deleted_participants_admin; +struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay); +void deleted_participants_admin_free (struct deleted_participants_admin *admin); +int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what); nn_entityid_t to_entityid (unsigned u); int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid); @@ -399,11 +410,9 @@ int is_builtin_endpoint (nn_entityid_t id, nn_vendorid_t vendorid); bool is_local_orphan_endpoint (const struct entity_common *e); int is_writer_entityid (nn_entityid_t id); int is_reader_entityid (nn_entityid_t id); +int is_keyed_endpoint_entityid (nn_entityid_t id); nn_vendorid_t get_entity_vendorid (const struct entity_common *e); -int pp_allocate_entityid (nn_entityid_t *id, unsigned kind, struct participant *pp); -void pp_release_entityid(struct participant *pp, nn_entityid_t id); - /* Interface for glue code between the OpenSplice kernel and the DDSI entities. These all return 0 iff successful. All GIDs supplied __MUST_BE_UNIQUE__. All hell may break loose if they aren't. @@ -457,20 +466,84 @@ void pp_release_entityid(struct participant *pp, nn_entityid_t id); /* Set this flag to mark the participant as an local entity only. */ #define RTPS_PF_ONLY_LOCAL 16u -/* To create a DDSI participant given a GUID. May return ERR_OUT_OF_IDS - (a.o.) */ -int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const struct nn_plist *plist); +/** + * @brief Create a new participant with a given GUID in the domain. + * + * @param[in] ppguid + * The GUID of the new participant. + * @param[in] flags + * Zero or more of: + * - RTPS_PF_NO_BUILTIN_READERS do not create discovery readers in new ppant + * - RTPS_PF_NO_BUILTIN_WRITERS do not create discvoery writers in new ppant + * - RTPS_PF_PRIVILEGED_PP FIXME: figure out how to describe this ... + * - RTPS_PF_IS_DDSI2_PP FIXME: OSPL holdover - there is no DDSI2E here + * - RTPS_PF_ONLY_LOCAL FIXME: not used, it seems + * @param[in] plist + * Parameters/QoS for this participant + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * All parameters valid (or ignored), dest and *nextafterplist have been set + * accordingly. + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * A participant with GUID *ppguid already exists. + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * The configured maximum number of participants has been reached. + */ +dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist); -int new_participant (struct nn_guid *ppguid, unsigned flags, const struct nn_plist *plist); +/** + * @brief Create a new participant in the domain. See also new_participant_guid. + * + * @param[out] ppguid + * On successful return: the GUID of the new participant; + * Undefined on error. + * @param[in] flags + * See new_participant_guid + * @param[in] plist + * See new_participant_guid + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Success, there is now a local participant with the GUID stored in + * *ppguid + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * Failed to allocate a new GUID (note: currently this will always + * happen after 2**24-1 successful calls to new_participant ...). + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * The configured maximum number of participants has been reached. +*/ +dds_return_t new_participant (struct nn_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist); -/* To delete a DDSI participant: this only removes the participant - from the hash tables and schedules the actual delete operation, - which will start doing scary things once all but the DDSI built-in - endpoints are gone. It is acceptable to call delete_participant() - before all its readers and writers have been deleted (which also - fits nicely with model where the glue calls merely schedules - garbage-collection). */ -int delete_participant (const struct nn_guid *ppguid); +/** + * @brief Initiate the deletion of the participant: + * - dispose/unregister built-in topic + * - list it as one of the recently deleted participants + * - remote it from the GUID hash tables + * - schedule the scare stuff to really delete it via the GC + * + * It is ok to call delete_participant without deleting all DDSI-level + * readers/writers: those will simply be deleted. (New ones can't be + * created anymore because the participant can no longer be located via + * the hash tables). + * + * @param[in] ppguid + * GUID of the participant to be deleted. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Success, it is no longer visible and GC events have + * been scheduled for eventual deleting of all remaining + * readers and writers and freeing of memory + * @retval DDS_RETCODE_BAD_PARAMETER + * ppguid lookup failed. +*/ +dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid); +void update_participant_plist (struct participant *pp, const struct nn_plist *plist); +uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_guid *guid); /* To obtain the builtin writer to be used for publishing SPDP, SEDP, PMD stuff for PP and its endpoints, given the entityid. If PP has @@ -481,9 +554,12 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity GUID "ppguid". May return NULL if participant unknown or writer/reader already known. */ -dds_retcode_t new_writer (struct writer **wr_out, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); -dds_retcode_t new_reader (struct reader **rd_out, struct nn_guid *rdguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct rhc * rhc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct nn_guid *rdguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc * rhc, status_cb_t status_cb, void *status_cb_arg); + +void update_reader_qos (struct reader *rd, const struct dds_qos *xqos); +void update_writer_qos (struct writer *wr, const struct dds_qos *xqos); struct whc_node; struct whc_state; @@ -493,17 +569,16 @@ int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_sta void writer_set_retransmitting (struct writer *wr); void writer_clear_retransmitting (struct writer *wr); -int delete_writer (const struct nn_guid *guid); -int delete_writer_nolinger (const struct nn_guid *guid); -int delete_writer_nolinger_locked (struct writer *wr); +dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid); +dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid); +dds_return_t delete_writer_nolinger_locked (struct writer *wr); -int delete_reader (const struct nn_guid *guid); -uint64_t reader_instance_id (const struct nn_guid *guid); +dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid); struct local_orphan_writer { struct writer wr; }; -struct local_orphan_writer *new_local_orphan_writer (nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc *whc); +struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc); void delete_local_orphan_writer (struct local_orphan_writer *wr); /* To create or delete a new proxy participant: "guid" MUST have the @@ -530,25 +605,24 @@ void delete_local_orphan_writer (struct local_orphan_writer *wr); /* Set when this proxy participant is not to be announced on the built-in topics yet */ #define CF_PROXYPP_NO_SPDP (1 << 3) -void new_proxy_participant (const struct nn_guid *guid, unsigned bes, unsigned prismtech_bes, const struct nn_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, int64_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp); -int delete_proxy_participant_by_guid (const struct nn_guid * guid, nn_wctime_t timestamp, int isimplicit); -uint64_t participant_instance_id (const struct nn_guid *guid); +void new_proxy_participant (struct q_globals *gv, const struct nn_guid *guid, unsigned bes, unsigned prismtech_bes, const struct nn_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq); +int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); enum update_proxy_participant_source { UPD_PROXYPP_SPDP, UPD_PROXYPP_CM }; -int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp); -int update_proxy_participant_plist (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp); +int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp); +int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp); void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease); -void purge_proxy_participants (const nn_locator_t *loc, bool delete_from_as_disc); +void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc); /* To create a new proxy writer or reader; the proxy participant is determined from the GUID and must exist. */ -int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp); -int new_proxy_reader (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp + int new_proxy_writer (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq); +int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq #ifdef DDSI_INCLUDE_SSM , int favours_ssm #endif @@ -559,20 +633,21 @@ int new_proxy_reader (const struct nn_guid *ppguid, const struct nn_guid *guid, reader or writer. Actual deletion is scheduled in the future, when no outstanding references may still exist (determined by checking thread progress, &c.). */ -int delete_proxy_writer (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); -int delete_proxy_reader (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); +int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); +int delete_proxy_reader (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); -void update_proxy_reader (struct proxy_reader * prd, struct addrset *as); -void update_proxy_writer (struct proxy_writer * pwr, struct addrset *as); +void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp); +void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp); -int new_proxy_group (const struct nn_guid *guid, const char *name, const struct nn_xqos *xqos, nn_wctime_t timestamp); -void delete_proxy_group (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); - -uint64_t writer_instance_id (const struct nn_guid *guid); +int new_proxy_group (const struct nn_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp); +void delete_proxy_group (struct ephash *guid_hash, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit); /* Call this to empty all address sets of all writers to stop all outgoing traffic, or to rebuild them all (which only makes sense after previously having emptied them all). */ -void rebuild_or_clear_writer_addrsets(int rebuild); +void rebuild_or_clear_writer_addrsets(struct q_globals *gv, int rebuild); + + +void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_ephash.h b/src/core/ddsi/include/dds/ddsi/q_ephash.h index cf218c3..7af049b 100644 --- a/src/core/ddsi/include/dds/ddsi/q_ephash.h +++ b/src/core/ddsi/include/dds/ddsi/q_ephash.h @@ -62,32 +62,33 @@ struct ephash_enum at the protocol level slightly before the network reader can use it to transmit data. */ -struct ephash *ephash_new (void); +struct q_globals; +struct ephash *ephash_new (struct q_globals *gv); void ephash_free (struct ephash *ephash); -void ephash_insert_participant_guid (struct participant *pp); -void ephash_insert_proxy_participant_guid (struct proxy_participant *proxypp); -void ephash_insert_writer_guid (struct writer *wr); -void ephash_insert_reader_guid (struct reader *rd); -void ephash_insert_proxy_writer_guid (struct proxy_writer *pwr); -void ephash_insert_proxy_reader_guid (struct proxy_reader *prd); +void ephash_insert_participant_guid (struct ephash *eh, struct participant *pp); +void ephash_insert_proxy_participant_guid (struct ephash *eh, struct proxy_participant *proxypp); +void ephash_insert_writer_guid (struct ephash *eh, struct writer *wr); +void ephash_insert_reader_guid (struct ephash *eh, struct reader *rd); +void ephash_insert_proxy_writer_guid (struct ephash *eh, struct proxy_writer *pwr); +void ephash_insert_proxy_reader_guid (struct ephash *eh, struct proxy_reader *prd); -void ephash_remove_participant_guid (struct participant *pp); -void ephash_remove_proxy_participant_guid (struct proxy_participant *proxypp); -void ephash_remove_writer_guid (struct writer *wr); -void ephash_remove_reader_guid (struct reader *rd); -void ephash_remove_proxy_writer_guid (struct proxy_writer *pwr); -void ephash_remove_proxy_reader_guid (struct proxy_reader *prd); +void ephash_remove_participant_guid (struct ephash *eh, struct participant *pp); +void ephash_remove_proxy_participant_guid (struct ephash *eh, struct proxy_participant *proxypp); +void ephash_remove_writer_guid (struct ephash *eh, struct writer *wr); +void ephash_remove_reader_guid (struct ephash *eh, struct reader *rd); +void ephash_remove_proxy_writer_guid (struct ephash *eh, struct proxy_writer *pwr); +void ephash_remove_proxy_reader_guid (struct ephash *eh, struct proxy_reader *prd); -void *ephash_lookup_guid_untyped (const struct nn_guid *guid); -void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind); +void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct nn_guid *guid); +void *ephash_lookup_guid (const struct ephash *eh, const struct nn_guid *guid, enum entity_kind kind); -struct participant *ephash_lookup_participant_guid (const struct nn_guid *guid); -struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct nn_guid *guid); -struct writer *ephash_lookup_writer_guid (const struct nn_guid *guid); -struct reader *ephash_lookup_reader_guid (const struct nn_guid *guid); -struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct nn_guid *guid); -struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct nn_guid *guid); +struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct nn_guid *guid); +struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct nn_guid *guid); +struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct nn_guid *guid); +struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct nn_guid *guid); +struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct nn_guid *guid); +struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct nn_guid *guid); /* Enumeration of entries in the hash table: @@ -110,16 +111,16 @@ struct ephash_enum_proxy_participant { struct ephash_enum st; }; struct ephash_enum_proxy_writer { struct ephash_enum st; }; struct ephash_enum_proxy_reader { struct ephash_enum st; }; -void ephash_enum_init (struct ephash_enum *st, enum entity_kind kind); +void ephash_enum_init (struct ephash_enum *st, const struct ephash *eh, enum entity_kind kind); void *ephash_enum_next (struct ephash_enum *st); void ephash_enum_fini (struct ephash_enum *st); -void ephash_enum_writer_init (struct ephash_enum_writer *st); -void ephash_enum_reader_init (struct ephash_enum_reader *st); -void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st); -void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st); -void ephash_enum_participant_init (struct ephash_enum_participant *st); -void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st); +void ephash_enum_writer_init (struct ephash_enum_writer *st, const struct ephash *eh); +void ephash_enum_reader_init (struct ephash_enum_reader *st, const struct ephash *eh); +void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st, const struct ephash *eh); +void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st, const struct ephash *eh); +void ephash_enum_participant_init (struct ephash_enum_participant *st, const struct ephash *eh); +void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st, const struct ephash *eh); struct writer *ephash_enum_writer_next (struct ephash_enum_writer *st); struct reader *ephash_enum_reader_next (struct ephash_enum_reader *st); diff --git a/src/core/ddsi/include/dds/ddsi/q_error.h b/src/core/ddsi/include/dds/ddsi/q_error.h deleted file mode 100644 index 8c4f840..0000000 --- a/src/core/ddsi/include/dds/ddsi/q_error.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 NN_ERROR_H -#define NN_ERROR_H - -#define Q_ERR_UNSPECIFIED -1 -#define Q_ERR_INVALID -2 -#define Q_ERR_OUT_OF_MEMORY -3 -#define Q_ERR_ENTITY_EXISTS -4 -#define Q_ERR_UNKNOWN_ENTITY -5 -#define Q_ERR_OUT_OF_IDS -6 -#define Q_ERR_INVALID_DATA -7 -#define Q_ERR_BUSY -8 -#define Q_ERR_NO_ADDRESS -9 -#define Q_ERR_TIMEOUT -10 -#define Q_ERR_INCOMPATIBLE -11 - -#endif /* NN_ERROR_H */ diff --git a/src/core/ddsi/include/dds/ddsi/q_gc.h b/src/core/ddsi/include/dds/ddsi/q_gc.h index 6a155fd..2b02bd3 100644 --- a/src/core/ddsi/include/dds/ddsi/q_gc.h +++ b/src/core/ddsi/include/dds/ddsi/q_gc.h @@ -21,6 +21,7 @@ extern "C" { struct gcreq; struct gcreq_queue; +struct q_globals; struct writer; struct reader; @@ -30,7 +31,7 @@ struct proxy_reader; typedef void (*gcreq_cb_t) (struct gcreq *gcreq); struct idx_vtime { - unsigned idx; + uint32_t idx; vtime_t vtime; }; @@ -39,11 +40,11 @@ struct gcreq { struct gcreq_queue *queue; gcreq_cb_t cb; void *arg; - unsigned nvtimes; - struct idx_vtime vtimes[1 /* really a flex ary */]; + uint32_t nvtimes; + struct idx_vtime vtimes[]; }; -DDS_EXPORT struct gcreq_queue *gcreq_queue_new (void); +DDS_EXPORT struct gcreq_queue *gcreq_queue_new (struct q_globals *gv); DDS_EXPORT void gcreq_queue_drain (struct gcreq_queue *q); DDS_EXPORT void gcreq_queue_free (struct gcreq_queue *q); diff --git a/src/core/ddsi/include/dds/ddsi/q_globals.h b/src/core/ddsi/include/dds/ddsi/q_globals.h index 857bd4c..0d0f589 100644 --- a/src/core/ddsi/include/dds/ddsi/q_globals.h +++ b/src/core/ddsi/include/dds/ddsi/q_globals.h @@ -24,7 +24,7 @@ #include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_sockwaitset.h" -#include "dds/ddsi/ddsi_iid.h" +#include "dds/ddsi/q_config.h" #ifdef DDSI_INCLUDE_ENCRYPTION #include "dds/ddsi/q_security.h" /* for q_securityDecoderSet */ @@ -64,9 +64,6 @@ enum recvips_mode { RECVIPS_MODE_SOME /* explicit list of interfaces; only one requiring recvips */ }; -#define N_LEASE_LOCKS_LG2 4 -#define N_LEASE_LOCKS ((int) (1 << N_LEASE_LOCKS_LG2)) - enum recv_thread_mode { RTM_SINGLE, RTM_MANY @@ -75,6 +72,7 @@ enum recv_thread_mode { struct recv_thread_arg { enum recv_thread_mode mode; struct nn_rbufpool *rbpool; + struct q_globals *gv; union { struct { const nn_locator_t *loc; @@ -86,14 +84,17 @@ struct recv_thread_arg { } u; }; +struct deleted_participants_admin; + struct q_globals { volatile int terminate; - volatile int exception; volatile int deaf; volatile int mute; + struct ddsrt_log_cfg logconfig; + struct config config; + struct ddsi_tkmap * m_tkmap; - struct ddsi_iid dds_iid; /* Hash tables for participants, readers, writers, proxy participants, proxy readers and proxy writers by GUID @@ -105,16 +106,14 @@ struct q_globals { /* Queue for garbage collection requests */ struct gcreq_queue *gcreq_queue; - struct ddsi_threadmon *threadmon; /* Lease junk */ ddsrt_mutex_t leaseheap_lock; - ddsrt_mutex_t lease_locks[N_LEASE_LOCKS]; ddsrt_fibheap_t leaseheap; - /* Transport factory */ - - struct ddsi_tran_factory * m_factory; + /* Transport factories & selected factory */ + struct ddsi_tran_factory *ddsi_tran_factories; + struct ddsi_tran_factory *m_factory; /* Connections for multicast discovery & data, and those that correspond to the one DDSI participant index that the DDSI2 service uses. The @@ -154,6 +153,9 @@ struct q_globals { struct participant *privileged_pp; ddsrt_mutex_t privileged_pp_lock; + /* For tracking (recently) deleted participants */ + struct deleted_participants_admin *deleted_participants; + /* GUID to be used in next call to new_participant; also protected by privileged_pp_lock */ struct nn_guid next_ppguid; @@ -199,10 +201,6 @@ struct q_globals { struct addrset *as_disc; struct addrset *as_disc_group; - /* qoslock serializes QoS changes, probably not strictly necessary, - but a lot more straightforward that way */ - ddsrt_rwlock_t qoslock; - ddsrt_mutex_t lock; /* Receive thread. (We can only has one for now, cos of the signal @@ -210,7 +208,7 @@ struct q_globals { it is only a global variable because it needs to be freed way later than the receive thread itself terminates */ #define MAX_RECV_THREADS 3 - unsigned n_recv_threads; + uint32_t n_recv_threads; struct recv_thread { const char *name; struct thread_state1 *ts; @@ -221,7 +219,7 @@ struct q_globals { struct thread_state1 *listen_ts; /* Flag cleared when stopping (receive threads). FIXME. */ - int rtps_keepgoing; + ddsrt_atomic_uint32_t rtps_keepgoing; /* Start time of the DDSI2 service, for logging relative time stamps, should I ever so desire. */ @@ -233,15 +231,16 @@ struct q_globals { packets); plus the actual QoSs needed for the builtin endpoints. */ nn_plist_t default_plist_pp; - nn_xqos_t default_xqos_rd; - nn_xqos_t default_xqos_wr; - nn_xqos_t default_xqos_wr_nad; - nn_xqos_t default_xqos_tp; - nn_xqos_t default_xqos_sub; - nn_xqos_t default_xqos_pub; - nn_xqos_t spdp_endpoint_xqos; - nn_xqos_t builtin_endpoint_xqos_rd; - nn_xqos_t builtin_endpoint_xqos_wr; + nn_plist_t default_local_plist_pp; + dds_qos_t default_xqos_rd; + dds_qos_t default_xqos_wr; + dds_qos_t default_xqos_wr_nad; + dds_qos_t default_xqos_tp; + dds_qos_t default_xqos_sub; + dds_qos_t default_xqos_pub; + dds_qos_t spdp_endpoint_xqos; + dds_qos_t builtin_endpoint_xqos_rd; + dds_qos_t builtin_endpoint_xqos_wr; /* SPDP packets get very special treatment (they're the only packets we accept from writers we don't know) and have their very own @@ -300,11 +299,11 @@ struct q_globals { FILE *pcap_fp; ddsrt_mutex_t pcap_lock; + struct ddsi_builtin_topic_interface *builtin_topic_interface; + struct nn_group_membership *mship; }; -extern struct q_globals DDS_EXPORT gv; - #if defined (__cplusplus) } #endif diff --git a/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h b/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h index d4d29ed..ca6a56f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h +++ b/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h @@ -24,15 +24,15 @@ struct hbcontrol { nn_mtime_t t_of_last_hb; nn_mtime_t t_of_last_ackhb; nn_mtime_t tsched; - unsigned hbs_since_last_write; - unsigned last_packetid; + uint32_t hbs_since_last_write; + uint32_t last_packetid; }; void writer_hbcontrol_init (struct hbcontrol *hbc); int64_t writer_hbcontrol_intv (const struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow); void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow); int writer_hbcontrol_ack_required (const struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow); -struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, unsigned packetid, int *hbansreq); +struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, uint32_t packetid, int *hbansreq); int writer_hbcontrol_must_send (const struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow); struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, int hbansreq, int issync); diff --git a/src/core/ddsi/include/dds/ddsi/q_init.h b/src/core/ddsi/include/dds/ddsi/q_init.h index a1f9cef..73f3548 100644 --- a/src/core/ddsi/include/dds/ddsi/q_init.h +++ b/src/core/ddsi/include/dds/ddsi/q_init.h @@ -16,8 +16,8 @@ extern "C" { #endif -int create_multicast_sockets(void); -int joinleave_spdp_defmcip (int dojoin); +int create_multicast_sockets (struct q_globals *gv); +int joinleave_spdp_defmcip (struct q_globals *gv, int dojoin); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_lat_estim.h b/src/core/ddsi/include/dds/ddsi/q_lat_estim.h index 9b3b41c..ebae71c 100644 --- a/src/core/ddsi/include/dds/ddsi/q_lat_estim.h +++ b/src/core/ddsi/include/dds/ddsi/q_lat_estim.h @@ -33,7 +33,7 @@ void nn_lat_estim_init (struct nn_lat_estim *le); void nn_lat_estim_fini (struct nn_lat_estim *le); void nn_lat_estim_update (struct nn_lat_estim *le, int64_t est); double nn_lat_estim_current (const struct nn_lat_estim *le); -int nn_lat_estim_log (uint32_t logcat, const char *tag, const struct nn_lat_estim *le); +int nn_lat_estim_log (uint32_t logcat, const struct ddsrt_log_cfg *logcfg, const char *tag, const struct nn_lat_estim *le); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_lease.h b/src/core/ddsi/include/dds/ddsi/q_lease.h index a139075..c9a8831 100644 --- a/src/core/ddsi/include/dds/ddsi/q_lease.h +++ b/src/core/ddsi/include/dds/ddsi/q_lease.h @@ -22,17 +22,18 @@ struct receiver_state; struct participant; struct lease; struct entity_common; +struct q_globals; /* FIXME: make a special for the lease admin */ -void lease_management_init (void); -void lease_management_term (void); +void lease_management_init (struct q_globals *gv); +void lease_management_term (struct q_globals *gv); struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e); void lease_register (struct lease *l); void lease_free (struct lease *l); void lease_renew (struct lease *l, nn_etime_t tnow); void lease_set_expiry (struct lease *l, nn_etime_t when); -int64_t check_and_handle_lease_expiration (nn_etime_t tnow); +int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow); -void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len); +void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_log.h b/src/core/ddsi/include/dds/ddsi/q_log.h index 7a0bfda..d983864 100644 --- a/src/core/ddsi/include/dds/ddsi/q_log.h +++ b/src/core/ddsi/include/dds/ddsi/q_log.h @@ -22,16 +22,36 @@ extern "C" { #endif +#define GVTRACE(...) DDS_CTRACE (&gv->logconfig, __VA_ARGS__) +#define GVLOG(cat, ...) DDS_CLOG ((cat), &gv->logconfig, __VA_ARGS__) +#define GVWARNING(...) DDS_CLOG (DDS_LC_WARNING, &gv->logconfig, __VA_ARGS__) +#define GVERROR(...) DDS_CLOG (DDS_LC_ERROR, &gv->logconfig, __VA_ARGS__) + +#define RSTTRACE(...) DDS_CTRACE (&rst->gv->logconfig, __VA_ARGS__) + +#define ETRACE(e_, ...) DDS_CTRACE (&(e_)->e.gv->logconfig, __VA_ARGS__) +#define EETRACE(e_, ...) DDS_CTRACE (&(e_)->gv->logconfig, __VA_ARGS__) +#define ELOG(cat, e_, ...) DDS_CLOG ((cat), &(e_)->e.gv->logconfig, __VA_ARGS__) +#define EELOG(cat, e_, ...) DDS_CLOG ((cat), &(e_)->gv->logconfig, __VA_ARGS__) + +/* There are quite a few places where discovery-related things are logged, so abbreviate those + a bit */ +#define GVLOGDISC(...) DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, __VA_ARGS__) +#define ELOGDISC(e_,...) DDS_CLOG (DDS_LC_DISCOVERY, &(e_)->e.gv->logconfig, __VA_ARGS__) +#define EELOGDISC(e_, ...) DDS_CLOG (DDS_LC_DISCOVERY, &(e_)->gv->logconfig, __VA_ARGS__) + /* LOG_THREAD_CPUTIME must be considered private. */ -#define LOG_THREAD_CPUTIME(guard) \ +#if DDSRT_HAVE_RUSAGE +#define LOG_THREAD_CPUTIME(logcfg, guard) \ do { \ - if (dds_get_log_mask() & DDS_LC_TIMING) { \ + if ((logcfg)->c.mask & DDS_LC_TIMING) { \ nn_mtime_t tnowlt = now_mt(); \ if (tnowlt.v >= (guard).v) { \ ddsrt_rusage_t usage; \ if (ddsrt_getrusage(DDSRT_RUSAGE_THREAD, &usage) == 0) { \ - DDS_LOG( \ + DDS_CLOG( \ DDS_LC_TIMING, \ + (logcfg), \ "thread_cputime %d.%09d\n", \ (int)(usage.stime / DDS_NSECS_IN_SEC), \ (int)(usage.stime % DDS_NSECS_IN_SEC)); \ @@ -40,6 +60,9 @@ extern "C" { } \ } \ } while (0) +#else +#define LOG_THREAD_CPUTIME(logcfg, guard) (void)(guard) +#endif /* DDSRT_HAVE_RUSAGE */ #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_nwif.h b/src/core/ddsi/include/dds/ddsi/q_nwif.h index 90777d2..e69a5a7 100644 --- a/src/core/ddsi/include/dds/ddsi/q_nwif.h +++ b/src/core/ddsi/include/dds/ddsi/q_nwif.h @@ -22,19 +22,22 @@ extern "C" { #endif +struct q_globals; + #define MAX_INTERFACES 128 struct nn_interface { nn_locator_t loc; nn_locator_t netmask; - unsigned if_index; + uint32_t if_index; unsigned mc_capable: 1; + unsigned mc_flaky: 1; unsigned point_to_point: 1; char *name; }; -int make_socket (ddsrt_socket_t *socket, unsigned short port, bool stream, bool reuse); -int find_own_ip (const char *requested_address); -unsigned locator_to_hopefully_unique_uint32 (const nn_locator_t *src); +int make_socket (ddsrt_socket_t *socket, uint16_t port, bool stream, bool reuse, const struct q_globals *gv); +int find_own_ip (struct q_globals *gv, const char *requested_address); +uint32_t locator_to_hopefully_unique_uint32 (const nn_locator_t *src); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_pcap.h b/src/core/ddsi/include/dds/ddsi/q_pcap.h index 478b038..09836c8 100644 --- a/src/core/ddsi/include/dds/ddsi/q_pcap.h +++ b/src/core/ddsi/include/dds/ddsi/q_pcap.h @@ -21,26 +21,11 @@ extern "C" { struct msghdr; -FILE * new_pcap_file (const char *name); +FILE * new_pcap_file (const struct ddsrt_log_cfg *logcfg, const char *name); -void write_pcap_received -( - FILE * fp, - nn_wctime_t tstamp, - const struct sockaddr_storage * src, - const struct sockaddr_storage * dst, - unsigned char * buf, - size_t sz -); - -void write_pcap_sent -( - FILE * fp, - nn_wctime_t tstamp, - const struct sockaddr_storage * src, - const ddsrt_msghdr_t * hdr, - size_t sz -); +void write_pcap_received (struct q_globals *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, const struct sockaddr_storage *dst, unsigned char *buf, size_t sz); +void write_pcap_sent (struct q_globals *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, + const ddsrt_msghdr_t *hdr, size_t sz); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_plist.h b/src/core/ddsi/include/dds/ddsi/q_plist.h index 6481caa..fcf54aa 100644 --- a/src/core/ddsi/include/dds/ddsi/q_plist.h +++ b/src/core/ddsi/include/dds/ddsi/q_plist.h @@ -14,7 +14,7 @@ #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_xqos.h" - +#include "dds/ddsi/ddsi_tran.h" /* FIXME: eliminate */ #if defined (__cplusplus) extern "C" { @@ -46,22 +46,16 @@ extern "C" { #define PP_STATUSINFO ((uint64_t)1 << 22) #define PP_ORIGINAL_WRITER_INFO ((uint64_t)1 << 23) #define PP_ENDPOINT_GUID ((uint64_t)1 << 24) -#define PP_PRISMTECH_WRITER_INFO ((uint64_t)1 << 25) #define PP_PRISMTECH_PARTICIPANT_VERSION_INFO ((uint64_t)1 << 26) #define PP_PRISMTECH_NODE_NAME ((uint64_t)1 << 27) #define PP_PRISMTECH_EXEC_NAME ((uint64_t)1 << 28) #define PP_PRISMTECH_PROCESS_ID ((uint64_t)1 << 29) -#define PP_PRISMTECH_SERVICE_TYPE ((uint64_t)1 << 30) -#define PP_PRISMTECH_WATCHDOG_SCHEDULING ((uint64_t)1 << 31) -#define PP_PRISMTECH_LISTENER_SCHEDULING ((uint64_t)1 << 32) #define PP_PRISMTECH_BUILTIN_ENDPOINT_SET ((uint64_t)1 << 33) #define PP_PRISMTECH_TYPE_DESCRIPTION ((uint64_t)1 << 34) #define PP_COHERENT_SET ((uint64_t)1 << 37) -#define PP_PRISMTECH_EOTINFO ((uint64_t)1 << 38) #ifdef DDSI_INCLUDE_SSM #define PP_READER_FAVOURS_SSM ((uint64_t)1 << 39) #endif -#define PP_RTI_TYPECODE ((uint64_t)1 << 40) /* Security extensions. */ #define PP_IDENTITY_TOKEN ((uint64_t)1 << 41) #define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 42) @@ -93,14 +87,14 @@ struct nn_locators_one { }; typedef struct nn_locators { - int n; + uint32_t n; struct nn_locators_one *first; struct nn_locators_one *last; } nn_locators_t; -typedef unsigned nn_ipv4address_t; +typedef uint32_t nn_ipv4address_t; -typedef unsigned nn_port_t; +typedef uint32_t nn_port_t; typedef struct nn_keyhash { unsigned char value[16]; @@ -109,15 +103,15 @@ typedef struct nn_keyhash { #ifdef DDSI_INCLUDE_SSM typedef struct nn_reader_favours_ssm { - unsigned state; /* default is false */ + uint32_t state; /* default is false */ } nn_reader_favours_ssm_t; #endif typedef struct nn_prismtech_participant_version_info { - unsigned version; - unsigned flags; - unsigned unused[3]; + uint32_t version; + uint32_t flags; + uint32_t unused[3]; char *internals; } nn_prismtech_participant_version_info_t; @@ -126,18 +120,11 @@ typedef struct nn_prismtech_eotgroup_tid { uint32_t transactionId; } nn_prismtech_eotgroup_tid_t; -typedef struct nn_prismtech_eotinfo { - uint32_t transactionId; - uint32_t n; - nn_prismtech_eotgroup_tid_t *tids; -} nn_prismtech_eotinfo_t; - typedef struct nn_plist { uint64_t present; uint64_t aliased; - int unalias_needs_bswap; - nn_xqos_t qos; + dds_qos_t qos; nn_protocol_version_t protocol_version; nn_vendorid_t vendorid; @@ -150,8 +137,8 @@ typedef struct nn_plist { unsigned char expects_inline_qos; nn_count_t participant_manual_liveliness_count; - unsigned participant_builtin_endpoints; - nn_duration_t participant_lease_duration; + uint32_t participant_builtin_endpoints; + dds_duration_t participant_lease_duration; /* nn_content_filter_property_t content_filter_property; */ nn_guid_t participant_guid; nn_guid_t endpoint_guid; @@ -160,21 +147,18 @@ typedef struct nn_plist { nn_entityid_t participant_entityid; nn_entityid_t group_entityid; #endif - unsigned builtin_endpoint_set; - unsigned prismtech_builtin_endpoint_set; + uint32_t builtin_endpoint_set; + uint32_t prismtech_builtin_endpoint_set; /* int type_max_size_serialized; */ char *entity_name; nn_keyhash_t keyhash; - unsigned statusinfo; + uint32_t statusinfo; nn_prismtech_participant_version_info_t prismtech_participant_version_info; char *node_name; char *exec_name; - unsigned char is_service; - unsigned service_type; - unsigned process_id; + uint32_t process_id; char *type_description; nn_sequence_number_t coherent_set_seqno; - nn_prismtech_eotinfo_t eotinfo; #ifdef DDSI_INCLUDE_SSM nn_reader_favours_ssm_t reader_favours_ssm; #endif @@ -183,38 +167,74 @@ typedef struct nn_plist { /***/ - typedef struct nn_plist_src { nn_protocol_version_t protocol_version; nn_vendorid_t vendorid; int encoding; const unsigned char *buf; size_t bufsz; + bool strict; + ddsi_tran_factory_t factory; /* eliminate this */ + struct ddsrt_log_cfg *logconfig; } nn_plist_src_t; +void nn_plist_init_tables (void); DDS_EXPORT void nn_plist_init_empty (nn_plist_t *dest); -DDS_EXPORT void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b); +DDS_EXPORT void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b, uint64_t pmask, uint64_t qmask); DDS_EXPORT void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src); DDS_EXPORT nn_plist_t *nn_plist_dup (const nn_plist_t *src); -DDS_EXPORT int nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const nn_plist_src_t *src); + +/** + * @brief Initialize an nn_plist_t from a PL_CDR_{LE,BE} paylaod. + * + * @param[in] pwanted + * PP_... flags indicating which non-QoS parameters are of interest, treated as + * a hint. Parameters in the input that are outside the mask may or may not be + * ignored. + * @param[in] qwanted + * QP_... flags indicating which QoS settings are of interest, and is treated as + * a hint. Parameters in the input that are outside the mask may or may not be + * ignored. + * @param[in] src + * Serialized payload to be parsed, validated and copied into dest + * - protocol_version is the version protocol version according to which the list + * should be parsed + * - vendorid is the vendor id code for the source of the parameter list (for + * handling vendor-specific parameters and compatibility workarounds) + * - encoding is PL_CDR_LE or PL_CDR_BE + * - buf is a pointer to the first parameter header + * - bufsz is the size in bytes of the input buffer + * @param[out] dest + * Filled with the recognized parameters in the input if successful, otherwise + * initialized to an empty parameter list. Where possible, pointers alias the + * input (indicated by the "aliased" bits in the plist/xqos structures), but + * some things cannot be aliased (e.g., the array of pointers to strings for a + * sequence of strings). + * Generally, nn_plist_fini should be called when done with the parameter list, + * even when nn_plist_unlias or nn_xqos_unlias hasn't been called. + * @param[out] nextafterplist + * If non-NULL, *nextafterplist is set to the first byte following the parameter + * list sentinel on successful parse, or to NULL on failure + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * All parameters valid (or ignored), dest and *nextafterplist have been set + * accordingly. + * @retval DDS_INCONSISTENT_POLICY + * All individual settings are valid, but there are inconsistencies between + * dependent settings. + * @retval DDS_RETCODE_BAD_PARAMETER + * Input contained invalid data; dest is cleared, *nextafterplist is NULL. + * @retval DDS_RETCODE_UNSUPPORTED + * Input contained an unrecognized parameter with the "incompatible-if-unknown" + * flag set; dest is cleared, *nextafterplist is NULL. + */ +DDS_EXPORT dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const nn_plist_src_t *src); DDS_EXPORT void nn_plist_fini (nn_plist_t *ps); +DDS_EXPORT void nn_plist_unalias (nn_plist_t *plist); DDS_EXPORT void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted); -DDS_EXPORT int nn_plist_init_default_participant (nn_plist_t *plist); - -DDS_EXPORT int validate_history_qospolicy (const nn_history_qospolicy_t *q); -DDS_EXPORT int validate_durability_qospolicy (const nn_durability_qospolicy_t *q); -DDS_EXPORT int validate_resource_limits_qospolicy (const nn_resource_limits_qospolicy_t *q); -DDS_EXPORT int validate_history_and_resource_limits (const nn_history_qospolicy_t *qh, const nn_resource_limits_qospolicy_t *qr); -DDS_EXPORT int validate_durability_service_qospolicy (const nn_durability_service_qospolicy_t *q); -DDS_EXPORT int validate_liveliness_qospolicy (const nn_liveliness_qospolicy_t *q); -DDS_EXPORT int validate_destination_order_qospolicy (const nn_destination_order_qospolicy_t *q); -DDS_EXPORT int validate_ownership_qospolicy (const nn_ownership_qospolicy_t *q); -DDS_EXPORT int validate_ownership_strength_qospolicy (const nn_ownership_strength_qospolicy_t *q); -DDS_EXPORT int validate_presentation_qospolicy (const nn_presentation_qospolicy_t *q); -DDS_EXPORT int validate_transport_priority_qospolicy (const nn_transport_priority_qospolicy_t *q); -DDS_EXPORT int validate_reader_data_lifecycle (const nn_reader_data_lifecycle_qospolicy_t *q); -DDS_EXPORT int validate_duration (const nn_duration_t *d); - +DDS_EXPORT void nn_plist_init_default_participant (nn_plist_t *plist); struct nn_rmsg; struct nn_rsample_info; diff --git a/src/core/ddsi/include/dds/ddsi/q_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h index d0a3de2..5a5d6e0 100644 --- a/src/core/ddsi/include/dds/ddsi/q_protocol.h +++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h @@ -32,25 +32,28 @@ typedef struct { #define NN_SEQUENCE_NUMBER_UNKNOWN_HIGH -1 #define NN_SEQUENCE_NUMBER_UNKNOWN_LOW 0 #define NN_SEQUENCE_NUMBER_UNKNOWN ((seqno_t) (((uint64_t)NN_SEQUENCE_NUMBER_UNKNOWN_HIGH << 32) | NN_SEQUENCE_NUMBER_UNKNOWN_LOW)) -typedef struct nn_sequence_number_set { +/* C99 disallows flex array in nested struct, so only put the + header in. (GCC and Clang allow it, but there are other + compilers in the world as well.) */ +typedef struct nn_sequence_number_set_header { nn_sequence_number_t bitmap_base; uint32_t numbits; - uint32_t bits[1]; -} nn_sequence_number_set_t; /* Why strict C90? zero-length/flexible array members are far nicer */ +} nn_sequence_number_set_header_t; /* SequenceNumberSet size is base (2 words) + numbits (1 word) + bitmap ((numbits+31)/32 words), and this at 4 bytes/word */ +#define NN_SEQUENCE_NUMBER_SET_MAX_BITS (256u) #define NN_SEQUENCE_NUMBER_SET_BITS_SIZE(numbits) ((unsigned) (4 * (((numbits) + 31) / 32))) -#define NN_SEQUENCE_NUMBER_SET_SIZE(numbits) (offsetof (nn_sequence_number_set_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)) +#define NN_SEQUENCE_NUMBER_SET_SIZE(numbits) (sizeof (nn_sequence_number_set_header_t) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)) typedef unsigned nn_fragment_number_t; -typedef struct nn_fragment_number_set { +typedef struct nn_fragment_number_set_header { nn_fragment_number_t bitmap_base; uint32_t numbits; - uint32_t bits[1]; -} nn_fragment_number_set_t; +} nn_fragment_number_set_header_t; /* FragmentNumberSet size is base (2 words) + numbits (1 word) + bitmap ((numbits+31)/32 words), and this at 4 bytes/word */ +#define NN_FRAGMENT_NUMBER_SET_MAX_BITS (256u) #define NN_FRAGMENT_NUMBER_SET_BITS_SIZE(numbits) ((unsigned) (4 * (((numbits) + 31) / 32))) -#define NN_FRAGMENT_NUMBER_SET_SIZE(numbits) (offsetof (nn_fragment_number_set_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits)) +#define NN_FRAGMENT_NUMBER_SET_SIZE(numbits) (sizeof (nn_fragment_number_set_header_t) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits)) typedef int32_t nn_count_t; #define DDSI_COUNT_MIN (-2147483647 - 1) #define DDSI_COUNT_MAX (2147483647) @@ -62,20 +65,6 @@ typedef struct { unsigned char address[16]; } nn_locator_t; -typedef struct nn_udpv4mcgen_address { - /* base IPv4 MC address is ipv4, host bits are bits base .. base+count-1, this machine is bit idx */ - struct in_addr ipv4; - uint8_t base; - uint8_t count; - uint8_t idx; /* must be last: then sorting will put them consecutively */ -} nn_udpv4mcgen_address_t; - - -struct cdrstring { - uint32_t length; - unsigned char contents[1]; /* C90 does not support flex. array members */ -}; - #define NN_STATUSINFO_DISPOSE 0x1u #define NN_STATUSINFO_UNREGISTER 0x2u #define NN_STATUSINFO_STANDARDIZED (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER) @@ -167,7 +156,7 @@ typedef enum SubmessageKind { typedef struct InfoTimestamp { SubmessageHeader_t smhdr; - nn_ddsi_time_t time; + ddsi_time_t time; } InfoTimestamp_t; typedef struct EntityId { @@ -196,7 +185,7 @@ typedef struct InfoSRC { #define PL_CDR_LE 0x0003u #endif -typedef unsigned short nn_parameterid_t; /* spec says short */ +typedef uint16_t nn_parameterid_t; /* spec says short */ typedef struct nn_parameter { nn_parameterid_t parameterid; uint16_t length; /* spec says signed short */ @@ -238,11 +227,12 @@ typedef struct AckNack { SubmessageHeader_t smhdr; nn_entityid_t readerId; nn_entityid_t writerId; - nn_sequence_number_set_t readerSNState; + nn_sequence_number_set_header_t readerSNState; + uint32_t bits[]; /* nn_count_t count; */ } AckNack_t; #define ACKNACK_FLAG_FINAL 0x02u -#define ACKNACK_SIZE(numbits) (offsetof (AckNack_t, readerSNState) + NN_SEQUENCE_NUMBER_SET_SIZE (numbits) + 4) +#define ACKNACK_SIZE(numbits) (offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits) + 4) #define ACKNACK_SIZE_MAX ACKNACK_SIZE (256u) typedef struct Gap { @@ -250,14 +240,15 @@ typedef struct Gap { nn_entityid_t readerId; nn_entityid_t writerId; nn_sequence_number_t gapStart; - nn_sequence_number_set_t gapList; + nn_sequence_number_set_header_t gapList; + uint32_t bits[]; } Gap_t; -#define GAP_SIZE(numbits) (offsetof (Gap_t, gapList) + NN_SEQUENCE_NUMBER_SET_SIZE (numbits)) +#define GAP_SIZE(numbits) (offsetof (Gap_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)) #define GAP_SIZE_MAX GAP_SIZE (256u) typedef struct InfoTS { SubmessageHeader_t smhdr; - nn_ddsi_time_t time; + ddsi_time_t time; } InfoTS_t; #define INFOTS_INVALIDATE_FLAG 0x2u @@ -286,10 +277,11 @@ typedef struct NackFrag { nn_entityid_t readerId; nn_entityid_t writerId; nn_sequence_number_t writerSN; - nn_fragment_number_set_t fragmentNumberState; + nn_fragment_number_set_header_t fragmentNumberState; + uint32_t bits[]; /* nn_count_t count; */ } NackFrag_t; -#define NACKFRAG_SIZE(numbits) (offsetof (NackFrag_t, fragmentNumberState) + NN_FRAGMENT_NUMBER_SET_SIZE (numbits) + 4) +#define NACKFRAG_SIZE(numbits) (offsetof (NackFrag_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits) + 4) #define NACKFRAG_SIZE_MAX NACKFRAG_SIZE (256u) typedef struct PT_InfoContainer { @@ -317,7 +309,7 @@ typedef struct ParticipantMessageData { nn_guid_prefix_t participantGuidPrefix; uint32_t kind; /* really 4 octets */ uint32_t length; - char value[1 /* length */]; + char value[]; } ParticipantMessageData_t; #define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u #define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u @@ -390,14 +382,6 @@ typedef struct ParticipantMessageData { #define PID_IDENTITY_TOKEN 0x1001u #define PID_PERMISSIONS_TOKEN 0x1002u -#define PID_RTI_TYPECODE (PID_VENDORSPECIFIC_FLAG | 0x4u) - -#ifdef DDSI_INCLUDE_SSM -/* To indicate whether a reader favours the use of SSM. Iff the - reader favours SSM, it will use SSM if available. */ -#define PID_READER_FAVOURS_SSM 0x72u -#endif - #ifdef DDSI_INCLUDE_SSM /* To indicate whether a reader favours the use of SSM. Iff the reader favours SSM, it will use SSM if available. */ diff --git a/src/core/ddsi/include/dds/ddsi/q_qosmatch.h b/src/core/ddsi/include/dds/ddsi/q_qosmatch.h index df224ed..bbf9b07 100644 --- a/src/core/ddsi/include/dds/ddsi/q_qosmatch.h +++ b/src/core/ddsi/include/dds/ddsi/q_qosmatch.h @@ -16,15 +16,19 @@ extern "C" { #endif -struct nn_xqos; +struct dds_qos; -int partition_match_based_on_wildcard_in_left_operand (const struct nn_xqos *a, const struct nn_xqos *b, const char **realname); -int partitions_match_p (const struct nn_xqos *a, const struct nn_xqos *b); -int is_wildcard_partition (const char *str); +int partitions_match_p (const struct dds_qos *a, const struct dds_qos *b); -/* Returns -1 on success, or QoS id of first mismatch (>=0) */ +/* perform reader/writer QoS (and topic name, type name, partition) matching; + mask can be used to exclude some of these (including topic name and type + name, so be careful!) -int32_t qos_match_p (const struct nn_xqos *rd, const struct nn_xqos *wr); + reason will be set to the policy id of one of the mismatching QoS, or to + DDS_INVALID_QOS_POLICY_ID if there is no mismatch or if the mismatch is + in topic or type name (those are not really QoS and don't have a policy id) */ +bool qos_match_mask_p (const dds_qos_t *rd, const dds_qos_t *wr, uint64_t mask, dds_qos_policy_id_t *reason) ddsrt_nonnull_all; +bool qos_match_p (const struct dds_qos *rd, const struct dds_qos *wr, dds_qos_policy_id_t *reason) ddsrt_nonnull ((1, 2)); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_radmin.h b/src/core/ddsi/include/dds/ddsi/q_radmin.h index 95df0a7..0d3100f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_radmin.h +++ b/src/core/ddsi/include/dds/ddsi/q_radmin.h @@ -46,16 +46,16 @@ struct nn_rmsg_chunk { /* Size is 0 after initial allocation, must be set with nn_rmsg_setsize after receiving a packet from the kernel and before processing it. */ - uint32_t size; union { - /* payload array stretched to whatever it really is */ - unsigned char payload[1]; + uint32_t size; - /* to ensure reasonable alignment of payload[] */ + /* to ensure reasonable alignment of payload */ int64_t l; double d; void *p; } u; + + /* unsigned char payload[] -- disallowed by C99 because of nesting */ }; struct nn_rmsg { @@ -93,9 +93,12 @@ struct nn_rmsg { the real packet. */ struct nn_rmsg_chunk *lastchunk; + /* whether to log */ + bool trace; + struct nn_rmsg_chunk chunk; }; -#define NN_RMSG_PAYLOAD(m) ((m)->chunk.u.payload) +#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (&(m)->chunk + 1)) #define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o)) struct receiver_state { @@ -107,6 +110,7 @@ struct receiver_state { nn_protocol_version_t protocol_version; /* 2 => 44/48 */ ddsi_tran_conn_t conn; /* Connection for request */ nn_locator_t srcloc; + struct q_globals *gv; }; struct nn_rsample_info { @@ -115,7 +119,7 @@ struct nn_rsample_info { struct proxy_writer *pwr; uint32_t size; uint32_t fragsize; - nn_ddsi_time_t timestamp; + nn_wctime_t timestamp; nn_wctime_t reception_timestamp; /* OpenSplice extension -- but we get it essentially for free, so why not? */ unsigned statusinfo: 2; /* just the two defined bits from the status info */ unsigned pt_wr_info_zoff: 16; /* PrismTech writer info offset */ @@ -194,7 +198,7 @@ typedef int32_t nn_reorder_result_t; typedef void (*nn_dqueue_callback_t) (void *arg); -struct nn_rbufpool *nn_rbufpool_new (uint32_t rbuf_size, uint32_t max_rmsg_size); +struct nn_rbufpool *nn_rbufpool_new (const struct ddsrt_log_cfg *logcfg, uint32_t rbuf_size, uint32_t max_rmsg_size); void nn_rbufpool_setowner (struct nn_rbufpool *rbp, ddsrt_thread_t tid); void nn_rbufpool_free (struct nn_rbufpool *rbp); @@ -209,23 +213,23 @@ struct nn_rdata *nn_rdata_newgap (struct nn_rmsg *rmsg); void nn_fragchain_adjust_refcount (struct nn_rdata *frag, int adjust); void nn_fragchain_unref (struct nn_rdata *frag); -struct nn_defrag *nn_defrag_new (enum nn_defrag_drop_mode drop_mode, uint32_t max_samples); +struct nn_defrag *nn_defrag_new (const struct ddsrt_log_cfg *logcfg, enum nn_defrag_drop_mode drop_mode, uint32_t max_samples); void nn_defrag_free (struct nn_defrag *defrag); struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo); void nn_defrag_notegap (struct nn_defrag *defrag, seqno_t min, seqno_t maxp1); -int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set *map, uint32_t maxsz); +int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set_header *map, uint32_t *mapbits, uint32_t maxsz); -struct nn_reorder *nn_reorder_new (enum nn_reorder_mode mode, uint32_t max_samples); +struct nn_reorder *nn_reorder_new (const struct ddsrt_log_cfg *logcfg, enum nn_reorder_mode mode, uint32_t max_samples, bool late_ack_mode); void nn_reorder_free (struct nn_reorder *r); -struct nn_rsample *nn_reorder_rsample_dup (struct nn_rmsg *rmsg, struct nn_rsample *rsampleiv); +struct nn_rsample *nn_reorder_rsample_dup_first (struct nn_rmsg *rmsg, struct nn_rsample *rsampleiv); struct nn_rdata *nn_rsample_fragchain (struct nn_rsample *rsample); nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_reorder *reorder, struct nn_rsample *rsampleiv, int *refcount_adjust, int delivery_queue_full_p); nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reorder *reorder, struct nn_rdata *rdata, seqno_t min, seqno_t maxp1, int *refcount_adjust); int nn_reorder_wantsample (struct nn_reorder *reorder, seqno_t seq); -unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set *map, uint32_t maxsz, int notail); +unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set_header *map, uint32_t *mapbits, uint32_t maxsz, int notail); seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder); -struct nn_dqueue *nn_dqueue_new (const char *name, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg); +struct nn_dqueue *nn_dqueue_new (const char *name, const struct q_globals *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg); void nn_dqueue_free (struct nn_dqueue *q); bool nn_dqueue_enqueue_deferred_wakeup (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres); void dd_dqueue_enqueue_trigger (struct nn_dqueue *q); diff --git a/src/core/ddsi/include/dds/ddsi/q_receive.h b/src/core/ddsi/include/dds/ddsi/q_receive.h index 4edaa5b..bb3555b 100644 --- a/src/core/ddsi/include/dds/ddsi/q_receive.h +++ b/src/core/ddsi/include/dds/ddsi/q_receive.h @@ -22,7 +22,7 @@ struct nn_rdata; struct ddsi_tran_listener; struct recv_thread_arg; -void trigger_recv_threads (void); +void trigger_recv_threads (const struct q_globals *gv); uint32_t recv_thread (void *vrecv_thread_arg); uint32_t listen_thread (struct ddsi_tran_listener * listener); int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg); diff --git a/src/core/ddsi/include/dds/ddsi/q_rhc.h b/src/core/ddsi/include/dds/ddsi/q_rhc.h new file mode 100644 index 0000000..5b9c5ce --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/q_rhc.h @@ -0,0 +1,86 @@ +/* + * 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 Q_RHC_H +#define Q_RHC_H + +#include +#include +#include + +#include "dds/export.h" + +/* DDS_EXPORT inline i.c.w. __attributes__((visibility...)) and some compilers: */ +#include "dds/ddsrt/attributes.h" + +#include "dds/ddsi/q_rtps.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +struct dds_qos; +struct ddsi_tkmap_instance; +struct ddsi_serdata; +struct ddsi_sertopic; +struct entity_common; + +struct proxy_writer_info +{ + nn_guid_t guid; + bool auto_dispose; + int32_t ownership_strength; + uint64_t iid; +}; + +struct rhc; + +typedef void (*rhc_free_t) (struct rhc *rhc); +typedef bool (*rhc_store_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); +typedef void (*rhc_unregister_wr_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); +typedef void (*rhc_relinquish_ownership_t) (struct rhc * __restrict rhc, const uint64_t wr_iid); +typedef void (*rhc_set_qos_t) (struct rhc *rhc, const struct dds_qos *qos); + +struct rhc_ops { + rhc_store_t store; + rhc_unregister_wr_t unregister_wr; + rhc_relinquish_ownership_t relinquish_ownership; + rhc_set_qos_t set_qos; + rhc_free_t free; +}; + +struct rhc { + const struct rhc_ops *ops; +}; + +DDS_EXPORT inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) { + return rhc->ops->store (rhc, pwr_info, sample, tk); +} +DDS_EXPORT inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) { + rhc->ops->unregister_wr (rhc, pwr_info); +} +DDS_EXPORT inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid) { + rhc->ops->relinquish_ownership (rhc, wr_iid); +} +DDS_EXPORT inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos) { + rhc->ops->set_qos (rhc, qos); +} +DDS_EXPORT inline void rhc_free (struct rhc *rhc) { + rhc->ops->free (rhc); +} + +DDS_EXPORT void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos); + +#if defined (__cplusplus) +} +#endif + +#endif /* Q_RHC_H */ diff --git a/src/core/ddsi/include/dds/ddsi/q_rtps.h b/src/core/ddsi/include/dds/ddsi/q_rtps.h index 57e3d0a..0b6ff39 100644 --- a/src/core/ddsi/include/dds/ddsi/q_rtps.h +++ b/src/core/ddsi/include/dds/ddsi/q_rtps.h @@ -74,13 +74,13 @@ typedef int64_t seqno_t; #define NN_ENTITYID_ALLOCSTEP 0x100 struct cfgst; -int rtps_config_prep (struct cfgst *cfgst); -int rtps_config_open (void); -int rtps_init (void); -int rtps_start (void); -void ddsi_plugin_init (void); -void rtps_stop (void); -void rtps_fini (void); +struct q_globals; +int rtps_config_prep (struct q_globals *config, struct cfgst *cfgst); +int rtps_config_open_trace (struct q_globals *config); +int rtps_init (struct q_globals *config); +int rtps_start (struct q_globals *config); +void rtps_stop (struct q_globals *config); +void rtps_fini (struct q_globals *config); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_thread.h b/src/core/ddsi/include/dds/ddsi/q_thread.h index 4d572d2..58439ff 100644 --- a/src/core/ddsi/include/dds/ddsi/q_thread.h +++ b/src/core/ddsi/include/dds/ddsi/q_thread.h @@ -17,7 +17,7 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" -#include "dds/ddsi/q_static_assert.h" +#include "dds/ddsrt/static_assert.h" #if defined (__cplusplus) extern "C" { @@ -54,20 +54,27 @@ enum thread_state { THREAD_STATE_ALIVE /* known to be alive - for Cyclone internal threads */ }; -struct logbuf; +struct q_globals; +struct config; +struct ddsrt_log_cfg; /* - * watchdog indicates progress for the service lease liveliness mechsanism, while vtime - * indicates progress for the Garbage collection purposes. - * vtime even : thread awake - * vtime odd : thread asleep + * vtime indicates progress for the garbage collector and the liveliness monitoring. + * + * vtime is updated without using atomic operations: only the owning thread updates + * them, and the garbage collection mechanism and the liveliness monitoring only + * observe the value + * + * gv is constant for internal threads, i.e., for threads with state = ALIVE + * gv is non-NULL for internal threads except thread liveliness monitoring */ #define THREAD_BASE \ - volatile vtime_t vtime; \ + ddsrt_atomic_uint32_t vtime; \ + ddsrt_atomic_voidp_t gv; \ + enum thread_state state; \ ddsrt_thread_t tid; \ ddsrt_thread_t extTid; \ - enum thread_state state; \ - char *name /* note: no semicolon! */ + char name[24] /* note: no semicolon! */ struct thread_state_base { THREAD_BASE; @@ -84,7 +91,7 @@ struct thread_state1 { struct thread_states { ddsrt_mutex_t lock; - unsigned nthreads; + uint32_t nthreads; struct thread_state1 *ts; /* [nthreads] */ }; @@ -97,11 +104,12 @@ DDS_EXPORT void thread_states_fini (void); DDS_EXPORT void upgrade_main_thread (void); DDS_EXPORT void downgrade_main_thread (void); -DDS_EXPORT const struct config_thread_properties_listelem *lookup_thread_properties (const char *name); -DDS_EXPORT dds_retcode_t create_thread (struct thread_state1 **ts, const char *name, uint32_t (*f) (void *arg), void *arg); +DDS_EXPORT const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name); +DDS_EXPORT dds_return_t create_thread_with_properties (struct thread_state1 **ts1, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg); +DDS_EXPORT dds_return_t create_thread (struct thread_state1 **ts, const struct q_globals *gv, const char *name, uint32_t (*f) (void *arg), void *arg); DDS_EXPORT struct thread_state1 *lookup_thread_state_real (void); -DDS_EXPORT int join_thread (struct thread_state1 *ts1); -DDS_EXPORT void log_stack_traces (void); +DDS_EXPORT dds_return_t join_thread (struct thread_state1 *ts1); +DDS_EXPORT void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct q_globals *gv); DDS_EXPORT void reset_thread_state (struct thread_state1 *ts1); DDS_EXPORT int thread_exists (const char *name); @@ -125,23 +133,27 @@ DDS_EXPORT inline bool vtime_asleep_p (vtime_t vtime) DDS_EXPORT inline bool vtime_gt (vtime_t vtime1, vtime_t vtime0) { - Q_STATIC_ASSERT_CODE (sizeof (vtime_t) == sizeof (svtime_t)); + DDSRT_STATIC_ASSERT_CODE (sizeof (vtime_t) == sizeof (svtime_t)); return (svtime_t) ((vtime1 & VTIME_TIME_MASK) - (vtime0 & VTIME_TIME_MASK)) > 0; } DDS_EXPORT inline bool thread_is_awake (void) { - return vtime_awake_p (lookup_thread_state ()->vtime); + struct thread_state1 *ts = lookup_thread_state (); + vtime_t vt = ddsrt_atomic_ld32 (&ts->vtime); + return vtime_awake_p (vt); } DDS_EXPORT inline bool thread_is_asleep (void) { - return vtime_asleep_p (lookup_thread_state ()->vtime); + struct thread_state1 *ts = lookup_thread_state (); + vtime_t vt = ddsrt_atomic_ld32 (&ts->vtime); + return vtime_asleep_p (vt); } DDS_EXPORT inline void thread_state_asleep (struct thread_state1 *ts1) { - vtime_t vt = ts1->vtime; + vtime_t vt = ddsrt_atomic_ld32 (&ts1->vtime); assert (vtime_awake_p (vt)); /* nested calls a rare and an extra fence doesn't break things */ ddsrt_atomic_fence_rel (); @@ -149,24 +161,45 @@ DDS_EXPORT inline void thread_state_asleep (struct thread_state1 *ts1) vt += (1u << VTIME_TIME_SHIFT) - 1u; else vt -= 1u; - ts1->vtime = vt; + ddsrt_atomic_st32 (&ts1->vtime, vt); } -DDS_EXPORT inline void thread_state_awake (struct thread_state1 *ts1) +DDS_EXPORT inline void thread_state_awake (struct thread_state1 *ts1, const struct q_globals *gv) { - vtime_t vt = ts1->vtime; + vtime_t vt = ddsrt_atomic_ld32 (&ts1->vtime); assert ((vt & VTIME_NEST_MASK) < VTIME_NEST_MASK); - ts1->vtime = vt + 1u; + assert (gv != NULL); + assert (ts1->state != THREAD_STATE_ALIVE || gv == ddsrt_atomic_ldvoidp (&ts1->gv)); + ddsrt_atomic_stvoidp (&ts1->gv, (struct q_globals *) gv); + ddsrt_atomic_fence_stst (); + ddsrt_atomic_st32 (&ts1->vtime, vt + 1u); /* nested calls a rare and an extra fence doesn't break things */ ddsrt_atomic_fence_acq (); } +DDS_EXPORT inline void thread_state_awake_domain_ok (struct thread_state1 *ts1) +{ + vtime_t vt = ddsrt_atomic_ld32 (&ts1->vtime); + assert ((vt & VTIME_NEST_MASK) < VTIME_NEST_MASK); + assert (ddsrt_atomic_ldvoidp (&ts1->gv) != NULL); + ddsrt_atomic_st32 (&ts1->vtime, vt + 1u); + /* nested calls a rare and an extra fence doesn't break things */ + ddsrt_atomic_fence_acq (); +} + +DDS_EXPORT inline void thread_state_awake_fixed_domain (struct thread_state1 *ts1) +{ + /* fixed domain -> must be an internal thread */ + assert (ts1->state == THREAD_STATE_ALIVE); + thread_state_awake_domain_ok (ts1); +} + DDS_EXPORT inline void thread_state_awake_to_awake_no_nest (struct thread_state1 *ts1) { - vtime_t vt = ts1->vtime; + vtime_t vt = ddsrt_atomic_ld32 (&ts1->vtime); assert ((vt & VTIME_NEST_MASK) == 1); ddsrt_atomic_fence_rel (); - ts1->vtime = vt + (1u << VTIME_TIME_SHIFT); + ddsrt_atomic_st32 (&ts1->vtime, vt + (1u << VTIME_TIME_SHIFT)); ddsrt_atomic_fence_acq (); } diff --git a/src/core/ddsi/include/dds/ddsi/q_time.h b/src/core/ddsi/include/dds/ddsi/q_time.h index 5c89cfa..7bdd5b0 100644 --- a/src/core/ddsi/include/dds/ddsi/q_time.h +++ b/src/core/ddsi/include/dds/ddsi/q_time.h @@ -26,11 +26,13 @@ extern "C" { #define T_MICROSECOND (T_MILLISECOND/1000) typedef struct { - int seconds; - unsigned fraction; -} nn_ddsi_time_t; + int32_t seconds; + uint32_t fraction; +} ddsi_time_t; +#define DDSI_TIME_INFINITE ((ddsi_time_t) { INT32_MAX, UINT32_MAX }) +#define DDSI_TIME_INVALID ((ddsi_time_t) { -1, UINT32_MAX }) -typedef nn_ddsi_time_t nn_duration_t; +typedef ddsi_time_t ddsi_duration_t; typedef struct { int64_t v; @@ -44,11 +46,9 @@ typedef struct { int64_t v; } nn_etime_t; -extern const nn_ddsi_time_t invalid_ddsi_timestamp; -extern const nn_ddsi_time_t ddsi_time_infinite; -extern const nn_duration_t duration_infinite; +#define NN_WCTIME_INVALID ((nn_wctime_t) { INT64_MIN }) -int valid_ddsi_timestamp (nn_ddsi_time_t t); +int valid_ddsi_timestamp (ddsi_time_t t); DDS_EXPORT nn_wctime_t now (void); /* wall clock time */ DDS_EXPORT nn_mtime_t now_mt (void); /* monotonic time */ @@ -61,10 +61,10 @@ DDS_EXPORT nn_mtime_t add_duration_to_mtime (nn_mtime_t t, int64_t d); DDS_EXPORT nn_wctime_t add_duration_to_wctime (nn_wctime_t t, int64_t d); DDS_EXPORT nn_etime_t add_duration_to_etime (nn_etime_t t, int64_t d); -DDS_EXPORT nn_ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t); -DDS_EXPORT nn_wctime_t nn_wctime_from_ddsi_time (nn_ddsi_time_t x); -DDS_EXPORT nn_duration_t nn_to_ddsi_duration (int64_t t); -DDS_EXPORT int64_t nn_from_ddsi_duration (nn_duration_t x); +DDS_EXPORT ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t); +DDS_EXPORT nn_wctime_t nn_wctime_from_ddsi_time (ddsi_time_t x); +DDS_EXPORT ddsi_duration_t nn_to_ddsi_duration (int64_t t); +DDS_EXPORT int64_t nn_from_ddsi_duration (ddsi_duration_t x); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_transmit.h b/src/core/ddsi/include/dds/ddsi/q_transmit.h index 19cc947..9fc3f2d 100644 --- a/src/core/ddsi/include/dds/ddsi/q_transmit.h +++ b/src/core/ddsi/include/dds/ddsi/q_transmit.h @@ -40,7 +40,7 @@ int write_sample_gc_notk (struct thread_state1 * const ts1, struct nn_xpack *xp, int write_sample_nogc_notk (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr, struct ddsi_serdata *serdata); /* When calling the following functions, wr->lock must be held */ -int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew); +dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew); int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew); void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, nn_entityid_t dst, int issync); diff --git a/src/core/ddsi/include/dds/ddsi/q_whc.h b/src/core/ddsi/include/dds/ddsi/q_whc.h index 038772b..9eb73a5 100644 --- a/src/core/ddsi/include/dds/ddsi/q_whc.h +++ b/src/core/ddsi/include/dds/ddsi/q_whc.h @@ -73,8 +73,8 @@ typedef void (*whc_free_t)(struct whc *whc); /* max_drop_seq must go soon, it's way too ugly. */ /* plist may be NULL or ddsrt_malloc'd, WHC takes ownership of plist */ typedef int (*whc_insert_t)(struct whc *whc, seqno_t max_drop_seq, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); -typedef unsigned (*whc_downgrade_to_volatile_t)(struct whc *whc, struct whc_state *st); -typedef unsigned (*whc_remove_acked_messages_t)(struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list); +typedef uint32_t (*whc_downgrade_to_volatile_t)(struct whc *whc, struct whc_state *st); +typedef uint32_t (*whc_remove_acked_messages_t)(struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list); typedef void (*whc_free_deferred_free_list_t)(struct whc *whc, struct whc_node *deferred_free_list); struct whc_ops { diff --git a/src/core/ddsi/include/dds/ddsi/q_xevent.h b/src/core/ddsi/include/dds/ddsi/q_xevent.h index ef356f4..e18b47f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xevent.h +++ b/src/core/ddsi/include/dds/ddsi/q_xevent.h @@ -42,7 +42,7 @@ struct xeventq *xeventq_new /* xeventq_free calls callback handlers with t = T_NEVER, at which point they are required to free whatever memory is claimed for the argument and call delete_xevent. */ DDS_EXPORT void xeventq_free (struct xeventq *evq); -DDS_EXPORT int xeventq_start (struct xeventq *evq, const char *name); /* <0 => error, =0 => ok */ +DDS_EXPORT dds_return_t xeventq_start (struct xeventq *evq, const char *name); /* <0 => error, =0 => ok */ DDS_EXPORT void xeventq_stop (struct xeventq *evq); DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg); @@ -59,12 +59,12 @@ DDS_EXPORT int resched_xevent_if_earlier (struct xevent *ev, nn_mtime_t tsched); DDS_EXPORT struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *wr_guid); DDS_EXPORT struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pwr_guid, const nn_guid_t *rd_guid); -DDS_EXPORT struct xevent *qxev_spdp (nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *proxypp_guid); -DDS_EXPORT struct xevent *qxev_pmd_update (nn_mtime_t tsched, const nn_guid_t *pp_guid); -DDS_EXPORT struct xevent *qxev_delete_writer (nn_mtime_t tsched, const nn_guid_t *guid); +DDS_EXPORT struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *proxypp_guid); +DDS_EXPORT struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid); +DDS_EXPORT struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *guid); /* cb will be called with now = T_NEVER if the event is still enqueued when when xeventq_free starts cleaning up */ -DDS_EXPORT struct xevent *qxev_callback (nn_mtime_t tsched, void (*cb) (struct xevent *xev, void *arg, nn_mtime_t now), void *arg); +DDS_EXPORT struct xevent *qxev_callback (struct xeventq *evq, nn_mtime_t tsched, void (*cb) (struct xevent *xev, void *arg, nn_mtime_t now), void *arg); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_xmsg.h b/src/core/ddsi/include/dds/ddsi/q_xmsg.h index ef634a9..480b72a 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xmsg.h +++ b/src/core/ddsi/include/dds/ddsi/q_xmsg.h @@ -28,8 +28,6 @@ struct proxy_reader; struct proxy_writer; struct nn_prismtech_participant_version_info; -struct nn_prismtech_writer_info; -struct nn_prismtech_eotinfo; struct nn_xmsgpool; struct nn_xmsg_data; struct nn_xmsg; @@ -64,8 +62,8 @@ void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_lo /* For sending to a particular proxy reader; this is a convenience routine that extracts a suitable address from the proxy reader's address sets and calls setdst1. */ -int nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd); -int nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr); +dds_return_t nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd); +dds_return_t nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr); /* For sending to all in the address set AS -- typically, the writer's address set to multicast to all matched readers */ @@ -94,7 +92,7 @@ void nn_xmsg_set_data_readerId (struct nn_xmsg *m, nn_entityid_t *readerId); Returns 1 if merge was successful, else 0. On failure, neither message will have been changed and both should be sent as if there had been no merging. */ -int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const struct nn_xmsg *madd); +int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct q_globals *gv, struct nn_xmsg *m, const struct nn_xmsg *madd); /* To set writer ids for updating last transmitted sequence number; wrfragid is 0 based, unlike DDSI but like other places where @@ -121,21 +119,9 @@ void nn_xmsg_submsg_setnext (struct nn_xmsg *msg, struct nn_xmsg_marker marker); void nn_xmsg_submsg_init (struct nn_xmsg *msg, struct nn_xmsg_marker marker, SubmessageKind_t smkind); void nn_xmsg_add_timestamp (struct nn_xmsg *m, nn_wctime_t t); void nn_xmsg_add_entityid (struct nn_xmsg * m); -void *nn_xmsg_addpar (struct nn_xmsg *m, unsigned pid, size_t len); -void nn_xmsg_addpar_string (struct nn_xmsg *m, unsigned pid, const char *str); -void nn_xmsg_addpar_octetseq (struct nn_xmsg *m, unsigned pid, const nn_octetseq_t *oseq); -void nn_xmsg_addpar_stringseq (struct nn_xmsg *m, unsigned pid, const nn_stringseq_t *sseq); -void nn_xmsg_addpar_guid (struct nn_xmsg *m, unsigned pid, const nn_guid_t *guid); -void nn_xmsg_addpar_BE4u (struct nn_xmsg *m, unsigned pid, unsigned x); -void nn_xmsg_addpar_4u (struct nn_xmsg *m, unsigned pid, unsigned x); +void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len); void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata); void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo); -void nn_xmsg_addpar_reliability (struct nn_xmsg *m, unsigned pid, const struct nn_reliability_qospolicy *rq); -void nn_xmsg_addpar_share (struct nn_xmsg *m, unsigned pid, const struct nn_share_qospolicy *rq); -void nn_xmsg_addpar_subscription_keys (struct nn_xmsg *m, unsigned pid, const struct nn_subscription_keys_qospolicy *rq); - -void nn_xmsg_addpar_parvinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_participant_version_info *pvi); -void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_eotinfo *txnid); void nn_xmsg_addpar_sentinel (struct nn_xmsg *m); int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m); @@ -149,10 +135,10 @@ int64_t nn_xpack_maxdelay (const struct nn_xpack *xp); unsigned nn_xpack_packetid (const struct nn_xpack *xp); /* SENDQ */ -void nn_xpack_sendq_init (void); -void nn_xpack_sendq_start (void); -void nn_xpack_sendq_stop (void); -void nn_xpack_sendq_fini (void); +void nn_xpack_sendq_init (struct q_globals *gv); +void nn_xpack_sendq_start (struct q_globals *gv); +void nn_xpack_sendq_stop (struct q_globals *gv); +void nn_xpack_sendq_fini (struct q_globals *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_xqos.h b/src/core/ddsi/include/dds/ddsi/q_xqos.h index d13207d..7ae7a02 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xqos.h +++ b/src/core/ddsi/include/dds/ddsi/q_xqos.h @@ -12,6 +12,7 @@ #ifndef NN_XQOS_H #define NN_XQOS_H +#include "dds/ddsc/dds_public_qosdefs.h" /*XXX*/ #include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_rtps.h" @@ -22,198 +23,164 @@ extern "C" { #endif -#define NN_DDS_LENGTH_UNLIMITED -1 - -typedef struct nn_octetseq { +typedef struct ddsi_octetseq { uint32_t length; unsigned char *value; -} nn_octetseq_t; +} ddsi_octetseq_t; -typedef nn_octetseq_t nn_userdata_qospolicy_t; -typedef nn_octetseq_t nn_topicdata_qospolicy_t; -typedef nn_octetseq_t nn_groupdata_qospolicy_t; +typedef ddsi_octetseq_t dds_userdata_qospolicy_t; +typedef ddsi_octetseq_t dds_topicdata_qospolicy_t; +typedef ddsi_octetseq_t dds_groupdata_qospolicy_t; -typedef enum nn_durability_kind { - NN_VOLATILE_DURABILITY_QOS, - NN_TRANSIENT_LOCAL_DURABILITY_QOS, - NN_TRANSIENT_DURABILITY_QOS, - NN_PERSISTENT_DURABILITY_QOS -} nn_durability_kind_t; +typedef struct dds_durability_qospolicy { + dds_durability_kind_t kind; +} dds_durability_qospolicy_t; -typedef struct nn_durability_qospolicy { - nn_durability_kind_t kind; -} nn_durability_qospolicy_t; - -typedef enum nn_history_kind { - NN_KEEP_LAST_HISTORY_QOS, - NN_KEEP_ALL_HISTORY_QOS -} nn_history_kind_t; - -typedef struct nn_history_qospolicy { - nn_history_kind_t kind; +typedef struct dds_history_qospolicy { + dds_history_kind_t kind; int32_t depth; -} nn_history_qospolicy_t; +} dds_history_qospolicy_t; -typedef struct nn_resource_limits_qospolicy { +typedef struct dds_resource_limits_qospolicy { int32_t max_samples; int32_t max_instances; int32_t max_samples_per_instance; -} nn_resource_limits_qospolicy_t; +} dds_resource_limits_qospolicy_t; -typedef struct nn_durability_service_qospolicy { - nn_duration_t service_cleanup_delay; - nn_history_qospolicy_t history; - nn_resource_limits_qospolicy_t resource_limits; -} nn_durability_service_qospolicy_t; +typedef struct dds_durability_service_qospolicy { + dds_duration_t service_cleanup_delay; + dds_history_qospolicy_t history; + dds_resource_limits_qospolicy_t resource_limits; +} dds_durability_service_qospolicy_t; -typedef enum nn_presentation_access_scope_kind { - NN_INSTANCE_PRESENTATION_QOS, - NN_TOPIC_PRESENTATION_QOS, - NN_GROUP_PRESENTATION_QOS -} nn_presentation_access_scope_kind_t; +typedef struct dds_external_durability_service_qospolicy { + ddsi_duration_t service_cleanup_delay; + dds_history_qospolicy_t history; + dds_resource_limits_qospolicy_t resource_limits; +} dds_external_durability_service_qospolicy_t; -typedef struct nn_presentation_qospolicy { - nn_presentation_access_scope_kind_t access_scope; +typedef struct dds_presentation_qospolicy { + dds_presentation_access_scope_kind_t access_scope; unsigned char coherent_access; unsigned char ordered_access; -} nn_presentation_qospolicy_t; +} dds_presentation_qospolicy_t; -typedef struct nn_deadline_qospolicy { - nn_duration_t deadline; -} nn_deadline_qospolicy_t; +typedef struct dds_deadline_qospolicy { + dds_duration_t deadline; +} dds_deadline_qospolicy_t; -typedef struct nn_latency_budget_qospolicy { - nn_duration_t duration; -} nn_latency_budget_qospolicy_t; +typedef struct dds_external_deadline_qospolicy { + ddsi_duration_t deadline; +} dds_external_deadline_qospolicy_t; -typedef enum nn_ownership_kind { - NN_SHARED_OWNERSHIP_QOS, - NN_EXCLUSIVE_OWNERSHIP_QOS -} nn_ownership_kind_t; +typedef struct dds_latency_budget_qospolicy { + dds_duration_t duration; +} dds_latency_budget_qospolicy_t; -typedef struct nn_ownership_qospolicy { - nn_ownership_kind_t kind; -} nn_ownership_qospolicy_t; +typedef struct dds_external_latency_budget_qospolicy { + ddsi_duration_t duration; +} dds_external_latency_budget_qospolicy_t; -typedef struct nn_ownership_strength_qospolicy { +typedef struct dds_ownership_qospolicy { + dds_ownership_kind_t kind; +} dds_ownership_qospolicy_t; + +typedef struct dds_ownership_strength_qospolicy { int32_t value; -} nn_ownership_strength_qospolicy_t; +} dds_ownership_strength_qospolicy_t; -typedef enum nn_liveliness_kind { - NN_AUTOMATIC_LIVELINESS_QOS, - NN_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS, - NN_MANUAL_BY_TOPIC_LIVELINESS_QOS -} nn_liveliness_kind_t; +typedef struct dds_liveliness_qospolicy { + dds_liveliness_kind_t kind; + dds_duration_t lease_duration; +} dds_liveliness_qospolicy_t; -typedef struct nn_liveliness_qospolicy { - nn_liveliness_kind_t kind; - nn_duration_t lease_duration; -} nn_liveliness_qospolicy_t; +typedef struct dds_external_liveliness_qospolicy { + dds_liveliness_kind_t kind; + ddsi_duration_t lease_duration; +} dds_external_liveliness_qospolicy_t; -typedef struct nn_time_based_filter_qospolicy { - nn_duration_t minimum_separation; -} nn_time_based_filter_qospolicy_t; +typedef struct dds_time_based_filter_qospolicy { + dds_duration_t minimum_separation; +} dds_time_based_filter_qospolicy_t; -typedef struct nn_stringseq { +typedef struct dds_external_time_based_filter_qospolicy { + ddsi_duration_t minimum_separation; +} dds_external_time_based_filter_qospolicy_t; + +typedef struct ddsi_stringseq { uint32_t n; char **strs; -} nn_stringseq_t; +} ddsi_stringseq_t; -typedef nn_stringseq_t nn_partition_qospolicy_t; +typedef ddsi_stringseq_t dds_partition_qospolicy_t; -typedef enum nn_reliability_kind { - NN_BEST_EFFORT_RELIABILITY_QOS, - NN_RELIABLE_RELIABILITY_QOS -} nn_reliability_kind_t; +typedef struct dds_reliability_qospolicy { + dds_reliability_kind_t kind; + dds_duration_t max_blocking_time; +} dds_reliability_qospolicy_t; -typedef struct nn_reliability_qospolicy { - nn_reliability_kind_t kind; - nn_duration_t max_blocking_time; -} nn_reliability_qospolicy_t; +typedef enum dds_external_reliability_kind { + DDS_EXTERNAL_RELIABILITY_BEST_EFFORT = 1, + DDS_EXTERNAL_RELIABILITY_RELIABLE = 2 +} dds_external_reliability_kind_t; -typedef struct nn_external_reliability_qospolicy { - uint32_t kind; - nn_duration_t max_blocking_time; -} nn_external_reliability_qospolicy_t; +typedef struct dds_external_reliability_qospolicy { + dds_external_reliability_kind_t kind; + ddsi_duration_t max_blocking_time; +} dds_external_reliability_qospolicy_t; -#define NN_PEDANTIC_BEST_EFFORT_RELIABILITY_QOS 1 -#define NN_PEDANTIC_RELIABLE_RELIABILITY_QOS 3 /* <= see DDSI 2.1, table 9.4 */ -#define NN_INTEROP_BEST_EFFORT_RELIABILITY_QOS 1 -#define NN_INTEROP_RELIABLE_RELIABILITY_QOS 2 - -typedef struct nn_transport_priority_qospolicy { +typedef struct dds_transport_priority_qospolicy { int32_t value; -} nn_transport_priority_qospolicy_t; +} dds_transport_priority_qospolicy_t; -typedef struct nn_lifespan_qospolicy { - nn_duration_t duration; -} nn_lifespan_qospolicy_t; +typedef struct dds_lifespan_qospolicy { + dds_duration_t duration; +} dds_lifespan_qospolicy_t; -typedef enum nn_destination_order_kind { - NN_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS, - NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS -} nn_destination_order_kind_t; +typedef struct dds_external_lifespan_qospolicy { + ddsi_duration_t duration; +} dds_external_lifespan_qospolicy_t; -typedef struct nn_destination_order_qospolicy { - nn_destination_order_kind_t kind; -} nn_destination_order_qospolicy_t; +typedef struct dds_destination_order_qospolicy { + dds_destination_order_kind_t kind; +} dds_destination_order_qospolicy_t; -typedef struct nn_entity_factory_qospolicy { +typedef struct dds_entity_factory_qospolicy { unsigned char autoenable_created_entities; -} nn_entity_factory_qospolicy_t; +} dds_entity_factory_qospolicy_t; -typedef struct nn_writer_data_lifecycle_qospolicy { +typedef struct dds_writer_data_lifecycle_qospolicy { unsigned char autodispose_unregistered_instances; - nn_duration_t autopurge_suspended_samples_delay; /* OpenSplice extension */ - nn_duration_t autounregister_instance_delay; /* OpenSplice extension */ -} nn_writer_data_lifecycle_qospolicy_t; +} dds_writer_data_lifecycle_qospolicy_t; -typedef enum nn_invalid_sample_visibility_kind { - NN_NO_INVALID_SAMPLE_VISIBILITY_QOS, - NN_MINIMUM_INVALID_SAMPLE_VISIBILITY_QOS, - NN_ALL_INVALID_SAMPLE_VISIBILITY_QOS -} nn_invalid_sample_visibility_kind_t; +typedef struct dds_reader_data_lifecycle_qospolicy { + dds_duration_t autopurge_nowriter_samples_delay; + dds_duration_t autopurge_disposed_samples_delay; +} dds_reader_data_lifecycle_qospolicy_t; -typedef struct nn_reader_data_lifecycle_qospolicy { - nn_duration_t autopurge_nowriter_samples_delay; - nn_duration_t autopurge_disposed_samples_delay; - unsigned char autopurge_dispose_all; /* OpenSplice extension */ - unsigned char enable_invalid_samples; /* OpenSplice extension */ - nn_invalid_sample_visibility_kind_t invalid_sample_visibility; /* OpenSplice extension */ -} nn_reader_data_lifecycle_qospolicy_t; +typedef struct dds_external_reader_data_lifecycle_qospolicy { + ddsi_duration_t autopurge_nowriter_samples_delay; + ddsi_duration_t autopurge_disposed_samples_delay; +} dds_external_reader_data_lifecycle_qospolicy_t; -typedef struct nn_synchronous_endpoint_qospolicy { - unsigned char value; -} nn_synchronous_endpoint_qospolicy_t; - -typedef struct nn_relaxed_qos_matching_qospolicy { - unsigned char value; -} nn_relaxed_qos_matching_qospolicy_t; - -typedef struct nn_subscription_keys_qospolicy { +typedef struct dds_subscription_keys_qospolicy { unsigned char use_key_list; - nn_stringseq_t key_list; -} nn_subscription_keys_qospolicy_t; + ddsi_stringseq_t key_list; +} dds_subscription_keys_qospolicy_t; -typedef struct nn_reader_lifespan_qospolicy { +typedef struct dds_reader_lifespan_qospolicy { unsigned char use_lifespan; - nn_duration_t duration; -} nn_reader_lifespan_qospolicy_t; + dds_duration_t duration; +} dds_reader_lifespan_qospolicy_t; -typedef struct nn_share_qospolicy { - unsigned char enable; - char *name; -} nn_share_qospolicy_t; +typedef struct dds_external_reader_lifespan_qospolicy { + unsigned char use_lifespan; + ddsi_duration_t duration; +} dds_external_reader_lifespan_qospolicy_t; -typedef enum nn_ignorelocal_kind { - NN_NONE_IGNORELOCAL_QOS, - NN_PARTICIPANT_IGNORELOCAL_QOS, - NN_PROCESS_IGNORELOCAL_QOS -} nn_ignorelocal_kind_t; - -typedef struct nn_ignorelocal_qospolicy { - nn_ignorelocal_kind_t value; -} nn_ignorelocal_qospolicy_t; +typedef struct dds_ignorelocal_qospolicy { + dds_ignorelocal_kind_t value; +} dds_ignorelocal_qospolicy_t; /***/ @@ -241,25 +208,22 @@ typedef struct nn_ignorelocal_qospolicy { #define QP_TIME_BASED_FILTER ((uint64_t)1 << 20) #define QP_PRISMTECH_WRITER_DATA_LIFECYCLE ((uint64_t)1 << 21) #define QP_PRISMTECH_READER_DATA_LIFECYCLE ((uint64_t)1 << 22) -#define QP_PRISMTECH_RELAXED_QOS_MATCHING ((uint64_t)1 << 23) #define QP_PRISMTECH_READER_LIFESPAN ((uint64_t)1 << 24) #define QP_PRISMTECH_SUBSCRIPTION_KEYS ((uint64_t)1 << 25) #define QP_PRISMTECH_ENTITY_FACTORY ((uint64_t)1 << 27) -#define QP_PRISMTECH_SYNCHRONOUS_ENDPOINT ((uint64_t)1 << 28) -#define QP_RTI_TYPECODE ((uint64_t)1 << 29) #define QP_CYCLONE_IGNORELOCAL ((uint64_t)1 << 30) /* Partition QoS is not RxO according to the specification (DDS 1.2, section 7.1.3), but communication will not take place unless it matches. Same for topic and type. Relaxed qos matching is a bit of a weird one, but it affects matching, so ... */ -#define QP_RXO_MASK (QP_DURABILITY | QP_PRESENTATION | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_RELAXED_QOS_MATCHING | QP_PRISMTECH_SYNCHRONOUS_ENDPOINT) +#define QP_RXO_MASK (QP_DURABILITY | QP_PRESENTATION | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_RELIABILITY | QP_DESTINATION_ORDER) #define QP_CHANGEABLE_MASK (QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP_STRENGTH | QP_TIME_BASED_FILTER | QP_PARTITION | QP_TRANSPORT_PRIORITY | QP_LIFESPAN | QP_PRISMTECH_ENTITY_FACTORY | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | QP_PRISMTECH_READER_DATA_LIFECYCLE) -#define QP_UNRECOGNIZED_INCOMPATIBLE_MASK (QP_PRISMTECH_RELAXED_QOS_MATCHING) +#define QP_UNRECOGNIZED_INCOMPATIBLE_MASK ((uint64_t) 0) /* readers & writers have an extended qos, hence why it is a separate type */ -typedef struct nn_xqos { +struct dds_qos { /* Entries present, for sparse QoS */ uint64_t present; uint64_t aliased; @@ -272,57 +236,54 @@ typedef struct nn_xqos { /* xx */char *topic_name; /* xx */char *type_name; /* PublisherQos, SubscriberQos: */ - /*xxx */nn_presentation_qospolicy_t presentation; - /*xxx */nn_partition_qospolicy_t partition; - /*xxx */nn_groupdata_qospolicy_t group_data; - /*x xX*/nn_entity_factory_qospolicy_t entity_factory; + /*xxx */dds_presentation_qospolicy_t presentation; + /*xxx */dds_partition_qospolicy_t partition; + /*xxx */dds_groupdata_qospolicy_t group_data; + /*x xX*/dds_entity_factory_qospolicy_t entity_factory; /* TopicQos: */ - /*xxx */nn_topicdata_qospolicy_t topic_data; + /*xxx */dds_topicdata_qospolicy_t topic_data; /* DataWriterQos, DataReaderQos: */ - /*xxx */nn_durability_qospolicy_t durability; - /*xxx */nn_durability_service_qospolicy_t durability_service; - /*xxx */nn_deadline_qospolicy_t deadline; - /*xxx */nn_latency_budget_qospolicy_t latency_budget; - /*xxx */nn_liveliness_qospolicy_t liveliness; - /*xxx */nn_reliability_qospolicy_t reliability; - /*xxx */nn_destination_order_qospolicy_t destination_order; - /*x x */nn_history_qospolicy_t history; - /*x x */nn_resource_limits_qospolicy_t resource_limits; - /*x x */nn_transport_priority_qospolicy_t transport_priority; - /*xxx */nn_lifespan_qospolicy_t lifespan; - /*xxx */nn_userdata_qospolicy_t user_data; - /*xxx */nn_ownership_qospolicy_t ownership; - /*xxxW*/nn_ownership_strength_qospolicy_t ownership_strength; - /*xxxR*/nn_time_based_filter_qospolicy_t time_based_filter; - /*x W*/nn_writer_data_lifecycle_qospolicy_t writer_data_lifecycle; - /*x xR*/nn_reader_data_lifecycle_qospolicy_t reader_data_lifecycle; - /*x x */nn_relaxed_qos_matching_qospolicy_t relaxed_qos_matching; - /*x xR*/nn_subscription_keys_qospolicy_t subscription_keys; - /*x xR*/nn_reader_lifespan_qospolicy_t reader_lifespan; - /*x xR*/nn_share_qospolicy_t share; - /*xxx */nn_synchronous_endpoint_qospolicy_t synchronous_endpoint; - /* x */nn_ignorelocal_qospolicy_t ignorelocal; - - /* X*/nn_octetseq_t rti_typecode; -} nn_xqos_t; + /*xxx */dds_durability_qospolicy_t durability; + /*xxx */dds_durability_service_qospolicy_t durability_service; + /*xxx */dds_deadline_qospolicy_t deadline; + /*xxx */dds_latency_budget_qospolicy_t latency_budget; + /*xxx */dds_liveliness_qospolicy_t liveliness; + /*xxx */dds_reliability_qospolicy_t reliability; + /*xxx */dds_destination_order_qospolicy_t destination_order; + /*x x */dds_history_qospolicy_t history; + /*x x */dds_resource_limits_qospolicy_t resource_limits; + /*x x */dds_transport_priority_qospolicy_t transport_priority; + /*xxx */dds_lifespan_qospolicy_t lifespan; + /*xxx */dds_userdata_qospolicy_t user_data; + /*xxx */dds_ownership_qospolicy_t ownership; + /*xxxW*/dds_ownership_strength_qospolicy_t ownership_strength; + /*xxxR*/dds_time_based_filter_qospolicy_t time_based_filter; + /*x W*/dds_writer_data_lifecycle_qospolicy_t writer_data_lifecycle; + /*x xR*/dds_reader_data_lifecycle_qospolicy_t reader_data_lifecycle; + /*x xR*/dds_subscription_keys_qospolicy_t subscription_keys; + /*x xR*/dds_reader_lifespan_qospolicy_t reader_lifespan; + /* x */dds_ignorelocal_qospolicy_t ignorelocal; +}; struct nn_xmsg; -DDS_EXPORT void nn_xqos_init_empty (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_reader (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_writer (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_writer_noautodispose (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_subscriber (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_publisher (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_init_default_topic (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_copy (nn_xqos_t *dst, const nn_xqos_t *src); -DDS_EXPORT void nn_xqos_unalias (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_fini (nn_xqos_t *xqos); -DDS_EXPORT void nn_xqos_mergein_missing (nn_xqos_t *a, const nn_xqos_t *b); -DDS_EXPORT uint64_t nn_xqos_delta (const nn_xqos_t *a, const nn_xqos_t *b, uint64_t mask); -DDS_EXPORT void nn_xqos_addtomsg (struct nn_xmsg *m, const nn_xqos_t *xqos, uint64_t wanted); -DDS_EXPORT void nn_log_xqos (uint32_t cat, const nn_xqos_t *xqos); -DDS_EXPORT nn_xqos_t *nn_xqos_dup (const nn_xqos_t *src); +DDS_EXPORT void nn_xqos_init_empty (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_reader (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_writer (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_writer_noautodispose (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_subscriber (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_publisher (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_init_default_topic (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_copy (dds_qos_t *dst, const dds_qos_t *src); +DDS_EXPORT void nn_xqos_unalias (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_fini (dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask); +DDS_EXPORT dds_return_t nn_xqos_valid (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask); +DDS_EXPORT uint64_t nn_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint64_t mask); +DDS_EXPORT void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted); +DDS_EXPORT void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); +DDS_EXPORT dds_qos_t *nn_xqos_dup (const dds_qos_t *src); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/sysdeps.h b/src/core/ddsi/include/dds/ddsi/sysdeps.h index f828c39..a3d711f 100644 --- a/src/core/ddsi/include/dds/ddsi/sysdeps.h +++ b/src/core/ddsi/include/dds/ddsi/sysdeps.h @@ -22,7 +22,7 @@ extern "C" { #define ASSERT_WRLOCK_HELD(x) ((void) 0) #define ASSERT_MUTEX_HELD(x) ((void) 0) -void log_stacktrace (const char *name, ddsrt_thread_t tid); +void log_stacktrace (const struct ddsrt_log_cfg *logcfg, const char *name, ddsrt_thread_t tid); #if defined (__cplusplus) } diff --git a/src/core/ddsi/src/ddsi_eth.c b/src/core/ddsi/src/ddsi_eth.c index 979badc..670667d 100644 --- a/src/core/ddsi/src/ddsi_eth.c +++ b/src/core/ddsi/src/ddsi_eth.c @@ -10,21 +10,20 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "ddsi_eth.h" -#include "dds/ddsi/q_config.h" -int ddsi_eth_enumerate_interfaces(ddsi_tran_factory_t fact, ddsrt_ifaddrs_t **ifs) +int ddsi_eth_enumerate_interfaces (ddsi_tran_factory_t fact, enum transport_selector transport_selector, ddsrt_ifaddrs_t **ifs) { int afs[] = { AF_INET, DDSRT_AF_TERM }; (void)fact; #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6 || - config.transport_selector == TRANS_UDP6) + if (transport_selector == TRANS_TCP6 || + transport_selector == TRANS_UDP6) { afs[0] = AF_INET6; } #endif /* DDSRT_HAVE_IPV6 */ - return -ddsrt_getifaddrs(ifs, afs); + return ddsrt_getifaddrs(ifs, afs); } diff --git a/src/core/ddsi/src/ddsi_eth.h b/src/core/ddsi/src/ddsi_eth.h index 472d3e7..0e7779b 100644 --- a/src/core/ddsi/src/ddsi_eth.h +++ b/src/core/ddsi/src/ddsi_eth.h @@ -13,12 +13,13 @@ #define DDSI_ETH_H #include "dds/ddsi/ddsi_tran.h" +#include "dds/ddsi/q_config.h" #if defined (__cplusplus) extern "C" { #endif -int ddsi_eth_enumerate_interfaces(ddsi_tran_factory_t fact, ddsrt_ifaddrs_t **ifs); +int ddsi_eth_enumerate_interfaces(ddsi_tran_factory_t fact, enum transport_selector transport_selector, ddsrt_ifaddrs_t **ifs); #if defined (__cplusplus) } diff --git a/src/core/ddsi/src/ddsi_iid.c b/src/core/ddsi/src/ddsi_iid.c index 5625973..3b9f023 100644 --- a/src/core/ddsi/src/ddsi_iid.c +++ b/src/core/ddsi/src/ddsi_iid.c @@ -11,10 +11,11 @@ */ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/process.h" +#include "dds/ddsrt/random.h" #include "dds/ddsrt/sync.h" #include "dds/ddsi/ddsi_iid.h" -#include "dds/ddsi/q_time.h" -#include "dds/ddsi/q_globals.h" + +static struct ddsi_iid dds_iid; static void dds_tea_encrypt (uint32_t v[2], const uint32_t k[4]) { @@ -49,14 +50,14 @@ uint64_t ddsi_iid_gen (void) union { uint64_t u64; uint32_t u32[2]; } tmp; #if DDSRT_ATOMIC64_SUPPORT - tmp.u64 = ddsrt_atomic_inc64_nv (&gv.dds_iid.counter); + tmp.u64 = ddsrt_atomic_inc64_nv (&dds_iid.counter); #else - ddsrt_mutex_lock (&gv.dds_iid.lock); - tmp.u64 = ++gv.dds_iid.counter; - ddsrt_mutex_unlock (&gv.dds_iid.lock); + ddsrt_mutex_lock (&dds_iid.lock); + tmp.u64 = ++dds_iid.counter; + ddsrt_mutex_unlock (&dds_iid.lock); #endif - dds_tea_encrypt (tmp.u32, gv.dds_iid.key); + dds_tea_encrypt (tmp.u32, dds_iid.key); iid = tmp.u64; return iid; } @@ -64,29 +65,26 @@ uint64_t ddsi_iid_gen (void) void ddsi_iid_init (void) { union { uint64_t u64; uint32_t u32[2]; } tmp; - nn_wctime_t tnow = now (); #if ! DDSRT_ATOMIC64_SUPPORT - ddsrt_mutex_init (&gv.dds_iid.lock); + ddsrt_mutex_init (&dds_iid.lock); #endif - gv.dds_iid.key[0] = (uint32_t) ddsrt_getpid(); - gv.dds_iid.key[1] = (uint32_t) tnow.v; - gv.dds_iid.key[2] = (uint32_t) (tnow.v >> 32); - gv.dds_iid.key[3] = 0xdeadbeef; + for (size_t i = 0; i < sizeof (dds_iid.key) / sizeof (dds_iid.key[0]); i++) + dds_iid.key[0] = ddsrt_random (); tmp.u64 = 0; - dds_tea_decrypt (tmp.u32, gv.dds_iid.key); + dds_tea_decrypt (tmp.u32, dds_iid.key); #if DDSRT_ATOMIC64_SUPPORT - ddsrt_atomic_st64 (&gv.dds_iid.counter, tmp.u64); + ddsrt_atomic_st64 (&dds_iid.counter, tmp.u64); #else - gv.dds_iid.counter = tmp.u64; + dds_iid.counter = tmp.u64; #endif } void ddsi_iid_fini (void) { #if ! DDSRT_ATOMIC64_SUPPORT - ddsrt_mutex_destroy (&gv.dds_iid.lock); + ddsrt_mutex_destroy (&dds_iid.lock); #endif } diff --git a/src/core/ddsi/src/ddsi_ipaddr.c b/src/core/ddsi/src/ddsi_ipaddr.c index 88b00c5..4b33048 100644 --- a/src/core/ddsi/src/ddsi_ipaddr.c +++ b/src/core/ddsi/src/ddsi_ipaddr.c @@ -54,7 +54,7 @@ int ddsi_ipaddr_compare (const struct sockaddr *const sa1, const struct sockaddr return eq; } -enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface interf[]) +enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) { struct sockaddr_storage tmp, iftmp, nmtmp, ownip; size_t i; @@ -64,7 +64,7 @@ enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (ddsi_tran_factory { ddsi_ipaddr_from_loc(&iftmp, &interf[i].loc); ddsi_ipaddr_from_loc(&nmtmp, &interf[i].netmask); - ddsi_ipaddr_from_loc(&ownip, &gv.ownloc); + ddsi_ipaddr_from_loc(&ownip, ownloc); if (ddsrt_sockaddr_insamesubnet ((struct sockaddr *) &tmp, (struct sockaddr *) &iftmp, (struct sockaddr *) &nmtmp)) { if (ddsi_ipaddr_compare((struct sockaddr *)&iftmp, (struct sockaddr *)&ownip) == 0) @@ -120,38 +120,43 @@ enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_ char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) { - struct sockaddr_storage src; - size_t pos; (void)tran; assert (sizeof_dst > 1); - ddsi_ipaddr_from_loc(&src, loc); - switch (src.ss_family) + if (loc->kind == NN_LOCATOR_KIND_INVALID) + snprintf (dst, sizeof_dst, "(invalid)"); + else { - case AF_INET: - ddsrt_sockaddrtostr ((const struct sockaddr *) &src, dst, sizeof_dst); - if (with_port) { - pos = strlen (dst); - assert(pos <= sizeof_dst); - snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port); - } - break; + struct sockaddr_storage src; + size_t pos; + ddsi_ipaddr_from_loc(&src, loc); + switch (src.ss_family) + { + case AF_INET: + ddsrt_sockaddrtostr ((const struct sockaddr *) &src, dst, sizeof_dst); + if (with_port) { + pos = strlen (dst); + assert(pos <= sizeof_dst); + snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port); + } + break; #if DDSRT_HAVE_IPV6 - case AF_INET6: - dst[0] = '['; - ddsrt_sockaddrtostr ((const struct sockaddr *) &src, dst + 1, sizeof_dst); - pos = strlen (dst); - if (with_port) { - assert(pos <= sizeof_dst); - snprintf (dst + pos, sizeof_dst - pos, "]:%"PRIu32, loc->port); - } else { - snprintf (dst + pos, sizeof_dst - pos, "]"); - } - break; + case AF_INET6: + dst[0] = '['; + ddsrt_sockaddrtostr ((const struct sockaddr *) &src, dst + 1, sizeof_dst); + pos = strlen (dst); + if (with_port) { + assert(pos <= sizeof_dst); + snprintf (dst + pos, sizeof_dst - pos, "]:%"PRIu32, loc->port); + } else { + snprintf (dst + pos, sizeof_dst - pos, "]"); + } + break; #endif - default: - assert(0); - dst[0] = 0; - break; + default: + assert(0); + dst[0] = 0; + break; + } } return dst; } @@ -209,11 +214,7 @@ void ddsi_ipaddr_from_loc (struct sockaddr_storage *dst, const nn_locator_t *src switch (src->kind) { case NN_LOCATOR_KIND_INVALID: -#if DDSRT_HAVE_IPV6 - dst->ss_family = (config.transport_selector == TRANS_UDP6 || config.transport_selector == TRANS_TCP6) ? AF_INET6 : AF_INET; -#else - dst->ss_family = AF_INET; -#endif + assert (0); break; case NN_LOCATOR_KIND_UDPv4: case NN_LOCATOR_KIND_TCPv4: @@ -234,7 +235,7 @@ void ddsi_ipaddr_from_loc (struct sockaddr_storage *dst, const nn_locator_t *src memcpy (&x->sin6_addr.s6_addr, src->address, 16); if (IN6_IS_ADDR_LINKLOCAL (&x->sin6_addr)) { - x->sin6_scope_id = gv.interfaceNo; + x->sin6_scope_id = 0;//FIXME: gv.interfaceNo; } break; } diff --git a/src/core/ddsi/src/ddsi_mcgroup.c b/src/core/ddsi/src/ddsi_mcgroup.c index 4fc2eb1..0728c7c 100644 --- a/src/core/ddsi/src/ddsi_mcgroup.c +++ b/src/core/ddsi/src/ddsi_mcgroup.c @@ -136,14 +136,14 @@ static char *make_joinleave_msg (char *buf, size_t bufsz, ddsi_tran_conn_t conn, int n; #ifdef DDSI_INCLUDE_SSM if (srcloc) { - ddsi_locator_to_string_no_port(srcstr, sizeof(srcstr), srcloc); + ddsi_locator_to_string_no_port(conn->m_base.gv, srcstr, sizeof(srcstr), srcloc); } #else DDSRT_UNUSED_ARG (srcloc); #endif - ddsi_locator_to_string_no_port (mcstr, sizeof(mcstr), mcloc); + ddsi_locator_to_string_no_port (conn->m_base.gv, mcstr, sizeof(mcstr), mcloc); if (interf) - ddsi_locator_to_string_no_port(interfstr, sizeof(interfstr), &interf->loc); + ddsi_locator_to_string_no_port(conn->m_base.gv, interfstr, sizeof(interfstr), &interf->loc); else (void) snprintf (interfstr, sizeof (interfstr), "(default)"); n = err ? snprintf (buf, bufsz, "error %d in ", err) : 0; @@ -156,20 +156,20 @@ static int joinleave_mcgroup (ddsi_tran_conn_t conn, int join, const nn_locator_ { char buf[256]; int err; - DDS_TRACE("%s\n", make_joinleave_msg (buf, sizeof(buf), conn, join, srcloc, mcloc, interf, 0)); + DDS_CTRACE(&conn->m_base.gv->logconfig, "%s\n", make_joinleave_msg (buf, sizeof(buf), conn, join, srcloc, mcloc, interf, 0)); if (join) err = ddsi_conn_join_mc(conn, srcloc, mcloc, interf); else err = ddsi_conn_leave_mc(conn, srcloc, mcloc, interf); if (err) - DDS_WARNING("%s\n", make_joinleave_msg (buf, sizeof(buf), conn, join, srcloc, mcloc, interf, err)); + DDS_CWARNING(&conn->m_base.gv->logconfig, "%s\n", make_joinleave_msg (buf, sizeof(buf), conn, join, srcloc, mcloc, interf, err)); return err ? -1 : 0; } -static int interface_in_recvips_p (const struct nn_interface *interf) +static int interface_in_recvips_p (const struct config_in_addr_node *recvips, const struct nn_interface *interf) { - struct config_in_addr_node *nodeaddr; - for (nodeaddr = gv.recvips; nodeaddr; nodeaddr = nodeaddr->next) + const struct config_in_addr_node *nodeaddr; + for (nodeaddr = recvips; nodeaddr; nodeaddr = nodeaddr->next) { if (locator_compare_no_port(&nodeaddr->loc, &interf->loc) == 0) return 1; @@ -177,10 +177,10 @@ static int interface_in_recvips_p (const struct nn_interface *interf) return 0; } -static int joinleave_mcgroups (ddsi_tran_conn_t conn, int join, const nn_locator_t *srcloc, const nn_locator_t *mcloc) +static int joinleave_mcgroups (const struct q_globals *gv, ddsi_tran_conn_t conn, int join, const nn_locator_t *srcloc, const nn_locator_t *mcloc) { int rc; - switch (gv.recvips_mode) + switch (gv->recvips_mode) { case RECVIPS_MODE_NONE: break; @@ -190,20 +190,20 @@ static int joinleave_mcgroups (ddsi_tran_conn_t conn, int join, const nn_locator return rc; break; case RECVIPS_MODE_PREFERRED: - if (gv.interfaces[gv.selected_interface].mc_capable) - return joinleave_mcgroup (conn, join, srcloc, mcloc, &gv.interfaces[gv.selected_interface]); + if (gv->interfaces[gv->selected_interface].mc_capable) + return joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[gv->selected_interface]); return 0; case RECVIPS_MODE_ALL: case RECVIPS_MODE_SOME: { int i, fails = 0, oks = 0; - for (i = 0; i < gv.n_interfaces; i++) + for (i = 0; i < gv->n_interfaces; i++) { - if (gv.interfaces[i].mc_capable) + if (gv->interfaces[i].mc_capable) { - if (gv.recvips_mode == RECVIPS_MODE_ALL || interface_in_recvips_p (&gv.interfaces[i])) + if (gv->recvips_mode == RECVIPS_MODE_ALL || interface_in_recvips_p (gv->recvips, &gv->interfaces[i])) { - if ((rc = joinleave_mcgroup (conn, join, srcloc, mcloc, &gv.interfaces[i])) < 0) + if ((rc = joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[i])) < 0) fails++; else oks++; @@ -213,7 +213,7 @@ static int joinleave_mcgroups (ddsi_tran_conn_t conn, int join, const nn_locator if (fails > 0) { if (oks > 0) - DDS_TRACE("multicast join failed for some but not all interfaces, proceeding\n"); + GVTRACE("multicast join failed for some but not all interfaces, proceeding\n"); else return -2; } @@ -223,43 +223,44 @@ static int joinleave_mcgroups (ddsi_tran_conn_t conn, int join, const nn_locator return 0; } -int ddsi_join_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc) +int ddsi_join_mc (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc) { + /* FIXME: gv to be reduced; perhaps mship, recvips, interfaces, ownloc should be combined into a single struct */ int ret; - ddsrt_mutex_lock (&gv.mship->lock); - if (!reg_group_membership (gv.mship, conn, srcloc, mcloc)) + ddsrt_mutex_lock (&mship->lock); + if (!reg_group_membership (mship, conn, srcloc, mcloc)) { char buf[256]; - DDS_TRACE("%s: already joined\n", make_joinleave_msg (buf, sizeof(buf), conn, 1, srcloc, mcloc, NULL, 0)); + GVTRACE("%s: already joined\n", make_joinleave_msg (buf, sizeof(buf), conn, 1, srcloc, mcloc, NULL, 0)); ret = 0; } else { - ret = joinleave_mcgroups (conn, 1, srcloc, mcloc); + ret = joinleave_mcgroups (gv, conn, 1, srcloc, mcloc); } - ddsrt_mutex_unlock (&gv.mship->lock); + ddsrt_mutex_unlock (&mship->lock); return ret; } -int ddsi_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc) +int ddsi_leave_mc (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn, const nn_locator_t *srcloc, const nn_locator_t *mcloc) { int ret; - ddsrt_mutex_lock (&gv.mship->lock); - if (!unreg_group_membership (gv.mship, conn, srcloc, mcloc)) + ddsrt_mutex_lock (&mship->lock); + if (!unreg_group_membership (mship, conn, srcloc, mcloc)) { char buf[256]; - DDS_TRACE("%s: not leaving yet\n", make_joinleave_msg (buf, sizeof(buf), conn, 0, srcloc, mcloc, NULL, 0)); + GVTRACE("%s: not leaving yet\n", make_joinleave_msg (buf, sizeof(buf), conn, 0, srcloc, mcloc, NULL, 0)); ret = 0; } else { - ret = joinleave_mcgroups (conn, 0, srcloc, mcloc); + ret = joinleave_mcgroups (gv, conn, 0, srcloc, mcloc); } - ddsrt_mutex_unlock (&gv.mship->lock); + ddsrt_mutex_unlock (&mship->lock); return ret; } -void ddsi_transfer_group_membership (ddsi_tran_conn_t conn, ddsi_tran_conn_t newconn) +void ddsi_transfer_group_membership (struct nn_group_membership *mship, ddsi_tran_conn_t conn, ddsi_tran_conn_t newconn) { struct nn_group_membership_node *n, min, max; memset(&min, 0, sizeof(min)); @@ -268,34 +269,35 @@ void ddsi_transfer_group_membership (ddsi_tran_conn_t conn, ddsi_tran_conn_t new /* ordering is on socket, then src IP, then mc IP; IP compare checks family first and AF_INET, AF_INET6 are neither 0 nor maximum representable, min and max define the range of key values that relate to oldsock */ - ddsrt_mutex_lock (&gv.mship->lock); - n = ddsrt_avl_lookup_succ_eq (&mship_td, &gv.mship->mships, &min); + ddsrt_mutex_lock (&mship->lock); + n = ddsrt_avl_lookup_succ_eq (&mship_td, &mship->mships, &min); while (n != NULL && cmp_group_membership (n, &max) <= 0) { - struct nn_group_membership_node * const nn = ddsrt_avl_find_succ (&mship_td, &gv.mship->mships, n); - ddsrt_avl_delete (&mship_td, &gv.mship->mships, n); + struct nn_group_membership_node * const nn = ddsrt_avl_find_succ (&mship_td, &mship->mships, n); + ddsrt_avl_delete (&mship_td, &mship->mships, n); n->conn = newconn; - ddsrt_avl_insert (&mship_td, &gv.mship->mships, n); + ddsrt_avl_insert (&mship_td, &mship->mships, n); n = nn; } - ddsrt_mutex_unlock (&gv.mship->lock); + ddsrt_mutex_unlock (&mship->lock); } -int ddsi_rejoin_transferred_mcgroups (ddsi_tran_conn_t conn) +int ddsi_rejoin_transferred_mcgroups (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn) { + /* FIXME: see gv should be reduced; perhaps recvips, ownloc, mship, interfaces should be a single struct */ struct nn_group_membership_node *n, min, max; ddsrt_avl_iter_t it; int ret = 0; memset(&min, 0, sizeof(min)); memset(&max, 0xff, sizeof(max)); min.conn = max.conn = conn; - ddsrt_mutex_lock (&gv.mship->lock); - for (n = ddsrt_avl_iter_succ_eq (&mship_td, &gv.mship->mships, &it, &min); n != NULL && ret >= 0 && cmp_group_membership(n, &max) <= 0; n = ddsrt_avl_iter_next (&it)) + ddsrt_mutex_lock (&mship->lock); + for (n = ddsrt_avl_iter_succ_eq (&mship_td, &mship->mships, &it, &min); n != NULL && ret >= 0 && cmp_group_membership(n, &max) <= 0; n = ddsrt_avl_iter_next (&it)) { int have_srcloc = (memcmp(&n->srcloc, &min.srcloc, sizeof(n->srcloc)) != 0); assert (n->conn == conn); - ret = joinleave_mcgroups (conn, 1, have_srcloc ? &n->srcloc : NULL, &n->mcloc); + ret = joinleave_mcgroups (gv, conn, 1, have_srcloc ? &n->srcloc : NULL, &n->mcloc); } - ddsrt_mutex_unlock (&gv.mship->lock); + ddsrt_mutex_unlock (&mship->lock); return ret; } diff --git a/src/core/ddsi/src/ddsi_raweth.c b/src/core/ddsi/src/ddsi_raweth.c index 98cb1d5..cc09ad1 100644 --- a/src/core/ddsi/src/ddsi_raweth.c +++ b/src/core/ddsi/src/ddsi_raweth.c @@ -16,7 +16,6 @@ #include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_pcap.h" #include "dds/ddsi/q_globals.h" #include "dds/ddsrt/atomics.h" @@ -24,7 +23,7 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/sockets.h" -#ifdef __linux +#if defined(__linux) && !LWIP_SOCKET #include #include #include @@ -33,25 +32,11 @@ #include #include -typedef struct ddsi_tran_factory * ddsi_raweth_factory_t; - -typedef struct ddsi_raweth_config -{ - struct nn_group_membership *mship; -} -* ddsi_raweth_config_t; - -typedef struct ddsi_raweth_conn -{ +typedef struct ddsi_raweth_conn { struct ddsi_tran_conn m_base; ddsrt_socket_t m_sock; int m_ifindex; -} -* ddsi_raweth_conn_t; - -static struct ddsi_raweth_config ddsi_raweth_config_g; -static struct ddsi_tran_factory ddsi_raweth_factory_g; -static ddsrt_atomic_uint32_t init_g = DDSRT_ATOMIC_UINT32_INIT(0); +} *ddsi_raweth_conn_t; static char *ddsi_raweth_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) { @@ -69,7 +54,7 @@ static char *ddsi_raweth_to_string (ddsi_tran_factory_t tran, char *dst, size_t static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc) { - dds_retcode_t rc; + dds_return_t rc; ssize_t ret = 0; struct msghdr msghdr; struct sockaddr_ll src; @@ -112,14 +97,14 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf snprintf(addrbuf, sizeof(addrbuf), "[%02x:%02x:%02x:%02x:%02x:%02x]:%u", src.sll_addr[0], src.sll_addr[1], src.sll_addr[2], src.sll_addr[3], src.sll_addr[4], src.sll_addr[5], ntohs(src.sll_protocol)); - DDS_WARNING("%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); + DDS_CWARNING(&conn->m_base.gv->logconfig, "%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); } } else if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_BAD_PARAMETER && rc != DDS_RETCODE_NO_CONNECTION) { - DDS_ERROR("UDP recvmsg sock %d: ret %d retcode %d\n", (int) ((ddsi_raweth_conn_t) conn)->m_sock, (int) ret, rc); + DDS_CERROR(&conn->m_base.gv->logconfig, "UDP recvmsg sock %d: ret %d retcode %d\n", (int) ((ddsi_raweth_conn_t) conn)->m_sock, (int) ret, rc); } return ret; } @@ -127,7 +112,7 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf static ssize_t ddsi_raweth_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const ddsrt_iovec_t *iov, uint32_t flags) { ddsi_raweth_conn_t uc = (ddsi_raweth_conn_t) conn; - dds_retcode_t rc; + dds_return_t rc; ssize_t ret; unsigned retry = 2; int sendflags = 0; @@ -159,7 +144,7 @@ static ssize_t ddsi_raweth_conn_write (ddsi_tran_conn_t conn, const nn_locator_t rc != DDS_RETCODE_NOT_ALLOWED && rc != DDS_RETCODE_NO_CONNECTION) { - DDS_ERROR("ddsi_raweth_conn_write failed with retcode %d", rc); + DDS_CERROR(&conn->m_base.gv->logconfig, "ddsi_raweth_conn_write failed with retcode %d", rc); } return (rc == DDS_RETCODE_OK ? ret : -1); } @@ -169,29 +154,31 @@ static ddsrt_socket_t ddsi_raweth_conn_handle (ddsi_tran_base_t base) return ((ddsi_raweth_conn_t) base)->m_sock; } -static bool ddsi_raweth_supports (int32_t kind) +static bool ddsi_raweth_supports (const struct ddsi_tran_factory *fact, int32_t kind) { + (void) fact; return (kind == NN_LOCATOR_KIND_RAWETH); } -static int ddsi_raweth_conn_locator (ddsi_tran_base_t base, nn_locator_t *loc) +static int ddsi_raweth_conn_locator (ddsi_tran_factory_t fact, ddsi_tran_base_t base, nn_locator_t *loc) { ddsi_raweth_conn_t uc = (ddsi_raweth_conn_t) base; int ret = -1; + (void) fact; if (uc->m_sock != DDSRT_INVALID_SOCKET) { loc->kind = NN_LOCATOR_KIND_RAWETH; loc->port = uc->m_base.m_base.m_port; - memcpy(loc->address, gv.extloc.address, sizeof (loc->address)); + memcpy(loc->address, uc->m_base.m_base.gv->extloc.address, sizeof (loc->address)); ret = 0; } return ret; } -static ddsi_tran_conn_t ddsi_raweth_create_conn (uint32_t port, ddsi_tran_qos_t qos) +static ddsi_tran_conn_t ddsi_raweth_create_conn (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t qos) { ddsrt_socket_t sock; - dds_retcode_t rc; + dds_return_t rc; ddsi_raweth_conn_t uc = NULL; struct sockaddr_ll addr; bool mcast = (bool) (qos ? qos->m_multicast : 0); @@ -200,27 +187,27 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (uint32_t port, ddsi_tran_qos_t if (port == 0 || port > 65535) { - DDS_ERROR("ddsi_raweth_create_conn %s port %u - using port number as ethernet type, %u won't do\n", mcast ? "multicast" : "unicast", port, port); + DDS_CERROR (&fact->gv->logconfig, "ddsi_raweth_create_conn %s port %u - using port number as ethernet type, %u won't do\n", mcast ? "multicast" : "unicast", port, port); return NULL; } rc = ddsrt_socket(&sock, PF_PACKET, SOCK_DGRAM, htons((uint16_t)port)); if (rc != DDS_RETCODE_OK) { - DDS_ERROR("ddsi_raweth_create_conn %s port %u failed ... retcode = %d\n", mcast ? "multicast" : "unicast", port, rc); + DDS_CERROR (&fact->gv->logconfig, "ddsi_raweth_create_conn %s port %u failed ... retcode = %d\n", mcast ? "multicast" : "unicast", port, rc); return NULL; } memset(&addr, 0, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_protocol = htons((uint16_t)port); - addr.sll_ifindex = (int)gv.interfaceNo; + addr.sll_ifindex = (int)fact->gv->interfaceNo; addr.sll_pkttype = PACKET_HOST | PACKET_BROADCAST | PACKET_MULTICAST; rc = ddsrt_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); if (rc != DDS_RETCODE_OK) { ddsrt_close(sock); - DDS_ERROR("ddsi_raweth_create_conn %s bind port %u failed ... retcode = %d\n", mcast ? "multicast" : "unicast", port, rc); + DDS_CERROR (&fact->gv->logconfig, "ddsi_raweth_create_conn %s bind port %u failed ... retcode = %d\n", mcast ? "multicast" : "unicast", port, rc); return NULL; } @@ -228,17 +215,17 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (uint32_t port, ddsi_tran_qos_t memset (uc, 0, sizeof (*uc)); uc->m_sock = sock; uc->m_ifindex = addr.sll_ifindex; - ddsi_factory_conn_init (&ddsi_raweth_factory_g, &uc->m_base); + ddsi_factory_conn_init (fact, &uc->m_base); uc->m_base.m_base.m_port = port; uc->m_base.m_base.m_trantype = DDSI_TRAN_CONN; uc->m_base.m_base.m_multicast = mcast; uc->m_base.m_base.m_handle_fn = ddsi_raweth_conn_handle; - uc->m_base.m_base.m_locator_fn = ddsi_raweth_conn_locator; + uc->m_base.m_locator_fn = ddsi_raweth_conn_locator; uc->m_base.m_read_fn = ddsi_raweth_conn_read; uc->m_base.m_write_fn = ddsi_raweth_conn_write; uc->m_base.m_disable_multiplexing_fn = 0; - DDS_TRACE("ddsi_raweth_create_conn %s socket %d port %u\n", mcast ? "multicast" : "unicast", uc->m_sock, uc->m_base.m_base.m_port); + DDS_CTRACE (&fact->gv->logconfig, "ddsi_raweth_create_conn %s socket %d port %u\n", mcast ? "multicast" : "unicast", uc->m_sock, uc->m_base.m_base.m_port); return uc ? &uc->m_base : NULL; } @@ -290,13 +277,11 @@ static int ddsi_raweth_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcl static void ddsi_raweth_release_conn (ddsi_tran_conn_t conn) { ddsi_raweth_conn_t uc = (ddsi_raweth_conn_t) conn; - DDS_TRACE - ( - "ddsi_raweth_release_conn %s socket %d port %d\n", - conn->m_base.m_multicast ? "multicast" : "unicast", - uc->m_sock, - uc->m_base.m_base.m_port - ); + DDS_CTRACE (&conn->m_base.gv->logconfig, + "ddsi_raweth_release_conn %s socket %d port %d\n", + conn->m_base.m_multicast ? "multicast" : "unicast", + uc->m_sock, + uc->m_base.m_base.m_port); ddsrt_close (uc->m_sock); ddsrt_free (conn); } @@ -315,10 +300,11 @@ static int ddsi_raweth_is_ssm_mcaddr (const ddsi_tran_factory_t tran, const nn_l return 0; } -static enum ddsi_nearby_address_result ddsi_raweth_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface interf[]) +static enum ddsi_nearby_address_result ddsi_raweth_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) { (void) tran; (void) loc; + (void) ownloc; (void) ninterf; (void) interf; return DNAR_LOCAL; @@ -333,8 +319,9 @@ static enum ddsi_locator_from_string_result ddsi_raweth_address_from_string (dds memset (loc->address, 0, sizeof (loc->address)); while (i < 6 && *str != 0) { - int o, p; - if (sscanf (str, "%x%n", &o, &p) != 1 || o < 0 || o > 255) + unsigned o; + int p; + if (sscanf (str, "%x%n", &o, &p) != 1 || o > 255) return AFSR_INVALID; loc->address[10 + i++] = (unsigned char) o; str += p; @@ -350,55 +337,48 @@ static enum ddsi_locator_from_string_result ddsi_raweth_address_from_string (dds return AFSR_OK; } -static void ddsi_raweth_deinit(void) +static void ddsi_raweth_deinit(ddsi_tran_factory_t fact) { - if (ddsrt_atomic_dec32_nv(&init_g) == 0) { - if (ddsi_raweth_config_g.mship) - free_group_membership(ddsi_raweth_config_g.mship); - DDS_LOG(DDS_LC_CONFIG, "raweth de-initialized\n"); - } + DDS_CLOG (DDS_LC_CONFIG, &fact->gv->logconfig, "raweth de-initialized\n"); + ddsrt_free (fact); } -static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t factory, ddsrt_ifaddrs_t **interfs) +static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t fact, enum transport_selector transport_selector, ddsrt_ifaddrs_t **ifs) { int afs[] = { AF_PACKET, DDSRT_AF_TERM }; - - (void)factory; - - return -ddsrt_getifaddrs(interfs, afs); + (void)fact; + (void)transport_selector; + return ddsrt_getifaddrs(ifs, afs); } -int ddsi_raweth_init (void) +int ddsi_raweth_init (struct q_globals *gv) { - if (ddsrt_atomic_inc32_nv(&init_g) == 1) { - memset (&ddsi_raweth_factory_g, 0, sizeof (ddsi_raweth_factory_g)); - ddsi_raweth_factory_g.m_free_fn = ddsi_raweth_deinit; - ddsi_raweth_factory_g.m_kind = NN_LOCATOR_KIND_RAWETH; - ddsi_raweth_factory_g.m_typename = "raweth"; - ddsi_raweth_factory_g.m_default_spdp_address = "raweth/ff:ff:ff:ff:ff:ff"; - ddsi_raweth_factory_g.m_connless = 1; - ddsi_raweth_factory_g.m_supports_fn = ddsi_raweth_supports; - ddsi_raweth_factory_g.m_create_conn_fn = ddsi_raweth_create_conn; - ddsi_raweth_factory_g.m_release_conn_fn = ddsi_raweth_release_conn; - ddsi_raweth_factory_g.m_join_mc_fn = ddsi_raweth_join_mc; - ddsi_raweth_factory_g.m_leave_mc_fn = ddsi_raweth_leave_mc; - ddsi_raweth_factory_g.m_is_mcaddr_fn = ddsi_raweth_is_mcaddr; - ddsi_raweth_factory_g.m_is_ssm_mcaddr_fn = ddsi_raweth_is_ssm_mcaddr; - ddsi_raweth_factory_g.m_is_nearby_address_fn = ddsi_raweth_is_nearby_address; - ddsi_raweth_factory_g.m_locator_from_string_fn = ddsi_raweth_address_from_string; - ddsi_raweth_factory_g.m_locator_to_string_fn = ddsi_raweth_to_string; - ddsi_raweth_factory_g.m_enumerate_interfaces_fn = ddsi_raweth_enumerate_interfaces; - ddsi_factory_add (&ddsi_raweth_factory_g); - - ddsi_raweth_config_g.mship = new_group_membership(); - - DDS_LOG(DDS_LC_CONFIG, "raweth initialized\n"); - } + struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact)); + memset (fact, 0, sizeof (*fact)); + fact->gv = gv; + fact->m_free_fn = ddsi_raweth_deinit; + fact->m_kind = NN_LOCATOR_KIND_RAWETH; + fact->m_typename = "raweth"; + fact->m_default_spdp_address = "raweth/ff:ff:ff:ff:ff:ff"; + fact->m_connless = 1; + fact->m_supports_fn = ddsi_raweth_supports; + fact->m_create_conn_fn = ddsi_raweth_create_conn; + fact->m_release_conn_fn = ddsi_raweth_release_conn; + fact->m_join_mc_fn = ddsi_raweth_join_mc; + fact->m_leave_mc_fn = ddsi_raweth_leave_mc; + fact->m_is_mcaddr_fn = ddsi_raweth_is_mcaddr; + fact->m_is_ssm_mcaddr_fn = ddsi_raweth_is_ssm_mcaddr; + fact->m_is_nearby_address_fn = ddsi_raweth_is_nearby_address; + fact->m_locator_from_string_fn = ddsi_raweth_address_from_string; + fact->m_locator_to_string_fn = ddsi_raweth_to_string; + fact->m_enumerate_interfaces_fn = ddsi_raweth_enumerate_interfaces; + ddsi_factory_add (gv, fact); + GVLOG (DDS_LC_CONFIG, "raweth initialized\n"); return 0; } #else -int ddsi_raweth_init (void) { return 0; } +int ddsi_raweth_init (struct q_globals *gv) { (void) gv; return 0; } #endif /* defined __linux */ diff --git a/src/core/ddsi/src/ddsi_serdata_default.c b/src/core/ddsi/src/ddsi_serdata_default.c index 167cc8b..4aa0699 100644 --- a/src/core/ddsi/src/ddsi_serdata_default.c +++ b/src/core/ddsi/src/ddsi_serdata_default.c @@ -20,20 +20,30 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" -#include "dds__key.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__stream.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_globals.h" #include "dds/ddsi/ddsi_serdata_default.h" +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN +#define NATIVE_ENCODING CDR_LE +#define NATIVE_ENCODING_PL PL_CDR_LE +#elif DDSRT_ENDIAN == DDSRT_BIG_ENDIAN +#define NATIVE_ENCODING CDR_BE +#define NATIVE_ENCODING_PL PL_CDR_BE +#else +#error "DDSRT_ENDIAN neither LITTLE nor BIG" +#endif + /* 8k entries in the freelist seems to be roughly the amount needed to send minimum-size (well, 4 bytes) samples as fast as possible over loopback while using large messages -- actually, it stands to reason that this would be the same as the WHC node pool size */ #define MAX_POOL_SIZE 8192 #define MAX_SIZE_FOR_POOL 256 -#define CLEAR_PADDING 0 +#define DEFAULT_NEW_SIZE 128 +#define CHUNK_SIZE 128 #ifndef NDEBUG static int ispowerof2_size (size_t x) @@ -63,7 +73,6 @@ static void serdata_free_wrap (void *elem) void ddsi_serdatapool_free (struct serdatapool * pool) { - DDS_TRACE("ddsi_serdatapool_free(%p)\n", (void *) pool); nn_freelist_fini (&pool->freelist, serdata_free_wrap); ddsrt_free (pool); } @@ -80,7 +89,7 @@ static void *serdata_default_append (struct ddsi_serdata_default **d, size_t n) char *p; if ((*d)->pos + n > (*d)->size) { - size_t size1 = alignup_size ((*d)->pos + n, 128); + size_t size1 = alignup_size ((*d)->pos + n, CHUNK_SIZE); *d = ddsrt_realloc (*d, offsetof (struct ddsi_serdata_default, data) + size1); (*d)->size = (uint32_t)size1; } @@ -92,17 +101,13 @@ static void *serdata_default_append (struct ddsi_serdata_default **d, size_t n) static void *serdata_default_append_aligned (struct ddsi_serdata_default **d, size_t n, size_t a) { -#if CLEAR_PADDING - size_t pos0 = st->pos; -#endif + size_t pos0 = (*d)->pos; char *p; assert (ispowerof2_size (a)); (*d)->pos = (uint32_t) alignup_size ((*d)->pos, a); p = serdata_default_append (d, n); -#if CLEAR_PADDING - if (p && (*d)->pos > pos0) - memset ((*d)->data + pos0, 0, (*d)->pos - pos0); -#endif + while (pos0 < (*d)->pos) + (*d)->data[pos0++] = 0; return p; } @@ -210,7 +215,7 @@ static void serdata_default_free(struct ddsi_serdata *dcmn) { struct ddsi_serdata_default *d = (struct ddsi_serdata_default *)dcmn; assert(ddsrt_atomic_ld32(&d->c.refc) == 0); - if (d->size > MAX_SIZE_FOR_POOL || !nn_freelist_push (&gv.serpool->freelist, d)) + if (d->size > MAX_SIZE_FOR_POOL || !nn_freelist_push (&d->serpool->freelist, d)) dds_free (d); } @@ -228,36 +233,49 @@ static void serdata_default_init(struct ddsi_serdata_default *d, const struct dd d->keyhash.m_iskey = 0; } -static struct ddsi_serdata_default *serdata_default_allocnew(struct serdatapool *pool) +static struct ddsi_serdata_default *serdata_default_allocnew (struct serdatapool *serpool, uint32_t init_size) { - const uint32_t init_size = 128; - struct ddsi_serdata_default *d = ddsrt_malloc(offsetof (struct ddsi_serdata_default, data) + init_size); + struct ddsi_serdata_default *d = ddsrt_malloc (offsetof (struct ddsi_serdata_default, data) + init_size); d->size = init_size; - d->pool = pool; + d->serpool = serpool; return d; } -static struct ddsi_serdata_default *serdata_default_new(const struct ddsi_sertopic_default *tp, enum ddsi_serdata_kind kind) +static struct ddsi_serdata_default *serdata_default_new_size (const struct ddsi_sertopic_default *tp, enum ddsi_serdata_kind kind, uint32_t size) { struct ddsi_serdata_default *d; - if ((d = nn_freelist_pop (&gv.serpool->freelist)) == NULL) - d = serdata_default_allocnew(gv.serpool); - else - ddsrt_atomic_st32(&d->c.refc, 1); - serdata_default_init(d, tp, kind); + if (size <= MAX_SIZE_FOR_POOL && (d = nn_freelist_pop (&tp->serpool->freelist)) != NULL) + ddsrt_atomic_st32 (&d->c.refc, 1); + else if ((d = serdata_default_allocnew (tp->serpool, size)) == NULL) + return NULL; + serdata_default_init (d, tp, kind); return d; } +static struct ddsi_serdata_default *serdata_default_new (const struct ddsi_sertopic_default *tp, enum ddsi_serdata_kind kind) +{ + return serdata_default_new_size (tp, kind, DEFAULT_NEW_SIZE); +} + /* Construct a serdata from a fragchain received over the network */ static struct ddsi_serdata_default *serdata_default_from_ser_common (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; - struct ddsi_serdata_default *d = serdata_default_new(tp, kind); + + /* FIXME: check whether this really is the correct maximum: offsets are relative + to the CDR header, but there are also some places that use a serdata as-if it + were a stream, and those use offsets (m_index) relative to the start of the + serdata */ + if (size > UINT32_MAX - offsetof (struct ddsi_serdata_default, hdr)) + return NULL; + struct ddsi_serdata_default *d = serdata_default_new_size (tp, kind, (uint32_t) size); + if (d == NULL) + return NULL; + uint32_t off = 4; /* must skip the CDR header */ assert (fragchain->min == 0); assert (fragchain->maxp1 >= off); /* CDR header must be in first fragment */ - (void)size; memcpy (&d->hdr, NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)), sizeof (d->hdr)); assert (d->hdr.identifier == CDR_LE || d->hdr.identifier == CDR_BE); @@ -276,23 +294,45 @@ static struct ddsi_serdata_default *serdata_default_from_ser_common (const struc fragchain = fragchain->nextfrag; } - dds_stream_t is; - dds_stream_from_serdata_default (&is, d); - dds_stream_read_keyhash (&is, &d->keyhash, (const dds_topic_descriptor_t *)tp->type, kind == SDK_KEY); - return d; + const bool needs_bswap = (d->hdr.identifier != NATIVE_ENCODING); + d->hdr.identifier = NATIVE_ENCODING; + const uint32_t pad = fromBE2u (d->hdr.options) & 2; + if (d->pos < pad) + { + ddsi_serdata_unref (&d->c); + return NULL; + } + else if (!dds_stream_normalize (d->data, d->pos - pad, needs_bswap, tp, kind == SDK_KEY)) + { + ddsi_serdata_unref (&d->c); + return NULL; + } + else + { + dds_istream_t is; + dds_istream_from_serdata_default (&is, d); + dds_stream_extract_keyhash (&is, &d->keyhash, tp, kind == SDK_KEY); + return d; + } } static struct ddsi_serdata *serdata_default_from_ser (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size) { - return fix_serdata_default (serdata_default_from_ser_common (tpcmn, kind, fragchain, size), tpcmn->serdata_basehash); + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_ser_common (tpcmn, kind, fragchain, size)) == NULL) + return NULL; + return fix_serdata_default (d, tpcmn->serdata_basehash); } static struct ddsi_serdata *serdata_default_from_ser_nokey (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size) { - return fix_serdata_default_nokey (serdata_default_from_ser_common (tpcmn, kind, fragchain, size), tpcmn->serdata_basehash); + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_ser_common (tpcmn, kind, fragchain, size)) == NULL) + return NULL; + return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); } -struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) { /* FIXME: not quite sure this is correct, though a check against a specially hacked OpenSplice suggests it is */ const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; @@ -304,8 +344,14 @@ struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic * else { struct ddsi_serdata_default *d = serdata_default_new(tp, SDK_KEY); - d->hdr.identifier = CDR_BE; + if (d == NULL) + return NULL; serdata_default_append_blob (&d, 1, sizeof (keyhash->value), keyhash->value); + if (!dds_stream_normalize (d->data, d->pos, (NATIVE_ENCODING != CDR_BE), tp, true)) + { + ddsi_serdata_unref (&d->c); + return NULL; + } memcpy (d->keyhash.m_hash, keyhash->value, sizeof (d->keyhash.m_hash)); d->keyhash.m_set = 1; d->keyhash.m_iskey = 1; @@ -313,23 +359,56 @@ struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic * } } -struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; struct ddsi_serdata_default *d = serdata_default_new(tp, SDK_KEY); + if (d == NULL) + return NULL; (void)keyhash; d->keyhash.m_set = 1; d->keyhash.m_iskey = 1; return fix_serdata_default_nokey(d, tp->c.serdata_basehash); } +static void gen_keyhash_from_sample (const struct ddsi_sertopic_default *topic, dds_keyhash_t *kh, const char *sample) +{ + const struct dds_topic_descriptor *desc = (const struct dds_topic_descriptor *) topic->type; + kh->m_set = 1; + if (desc->m_nkeys == 0) + kh->m_iskey = 1; + else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) + { + dds_ostreamBE_t os; + kh->m_iskey = 1; + dds_ostreamBE_init (&os, 0); + os.x.m_buffer = kh->m_hash; + os.x.m_size = 16; + dds_stream_write_keyBE (&os, sample, topic); + } + else + { + dds_ostreamBE_t os; + ddsrt_md5_state_t md5st; + kh->m_iskey = 0; + dds_ostreamBE_init (&os, 64); + dds_stream_write_keyBE (&os, sample, topic); + ddsrt_md5_init (&md5st); + ddsrt_md5_append (&md5st, os.x.m_buffer, os.x.m_index); + ddsrt_md5_finish (&md5st, kh->m_hash); + dds_ostreamBE_fini (&os); + } +} + static struct ddsi_serdata_default *serdata_default_from_sample_cdr_common (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; struct ddsi_serdata_default *d = serdata_default_new(tp, kind); - dds_stream_t os; - dds_key_gen ((const dds_topic_descriptor_t *)tp->type, &d->keyhash, (char*)sample); - dds_stream_from_serdata_default (&os, d); + if (d == NULL) + return NULL; + dds_ostream_t os; + gen_keyhash_from_sample (tp, &d->keyhash, sample); + dds_ostream_from_serdata_default (&os, d); switch (kind) { case SDK_EMPTY: @@ -341,18 +420,24 @@ static struct ddsi_serdata_default *serdata_default_from_sample_cdr_common (cons dds_stream_write_sample (&os, sample, tp); break; } - dds_stream_add_to_serdata_default (&os, &d); + dds_ostream_add_to_serdata_default (&os, &d); return d; } static struct ddsi_serdata *serdata_default_from_sample_cdr (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) { - return fix_serdata_default (serdata_default_from_sample_cdr_common (tpcmn, kind, sample), tpcmn->serdata_basehash); + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_sample_cdr_common (tpcmn, kind, sample)) == NULL) + return NULL; + return fix_serdata_default (d, tpcmn->serdata_basehash); } static struct ddsi_serdata *serdata_default_from_sample_cdr_nokey (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) { - return fix_serdata_default_nokey (serdata_default_from_sample_cdr_common (tpcmn, kind, sample), tpcmn->serdata_basehash); + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_sample_cdr_common (tpcmn, kind, sample)) == NULL) + return NULL; + return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); } static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *vsample) @@ -361,6 +446,8 @@ static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; const struct ddsi_plist_sample *sample = vsample; struct ddsi_serdata_default *d = serdata_default_new(tp, kind); + if (d == NULL) + return NULL; serdata_default_append_blob (&d, 1, sample->size, sample->blob); const unsigned char *rawkey = nn_plist_findparam_native_unchecked (sample->blob, sample->keyparam); #ifndef NDEBUG @@ -416,8 +503,11 @@ static struct ddsi_serdata *serdata_default_from_sample_rawcdr (const struct dds const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; const struct ddsi_rawcdr_sample *sample = vsample; struct ddsi_serdata_default *d = serdata_default_new(tp, kind); + if (d == NULL) + return NULL; assert (sample->keysize <= 16); serdata_default_append_blob (&d, 1, sample->size, sample->blob); + serdata_default_append_aligned (&d, 0, 4); d->keyhash.m_set = 1; d->keyhash.m_iskey = 1; if (sample->keysize == 0) @@ -433,7 +523,10 @@ static struct ddsi_serdata *serdata_default_to_topicless (const struct ddsi_serd { const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)d->c.topic; + assert (d->hdr.identifier == NATIVE_ENCODING || d->hdr.identifier == NATIVE_ENCODING_PL); struct ddsi_serdata_default *d_tl = serdata_default_new(tp, SDK_KEY); + if (d_tl == NULL) + return NULL; d_tl->c.topic = NULL; d_tl->c.hash = d->c.hash; d_tl->c.timestamp.v = INT64_MIN; @@ -443,31 +536,31 @@ static struct ddsi_serdata *serdata_default_to_topicless (const struct ddsi_serd the payload is of interest. */ if (d->c.ops == &ddsi_serdata_ops_cdr) { + assert (d->hdr.identifier == NATIVE_ENCODING); if (d->c.kind == SDK_KEY) - { - d_tl->hdr.identifier = d->hdr.identifier; serdata_default_append_blob (&d_tl, 1, d->pos, d->data); - } else if (d->keyhash.m_iskey) { - d_tl->hdr.identifier = CDR_BE; serdata_default_append_blob (&d_tl, 1, sizeof (d->keyhash.m_hash), d->keyhash.m_hash); +#if NATIVE_ENCODING != CDR_BE + bool ok = dds_stream_normalize (d_tl->data, d_tl->pos, true, tp, true); + assert (ok); + (void) ok; +#endif } else { - const struct dds_topic_descriptor *desc = tp->type; - dds_stream_t is, os; - uint32_t nbytes; - dds_stream_from_serdata_default (&is, d); - dds_stream_from_serdata_default (&os, d_tl); - nbytes = dds_stream_extract_key (&is, &os, desc->m_ops, false); - os.m_index += nbytes; + dds_istream_t is; + dds_ostream_t os; + dds_istream_from_serdata_default (&is, d); + dds_ostream_from_serdata_default (&os, d_tl); + dds_stream_extract_key_from_data (&is, &os, tp); if (os.m_index < os.m_size) { - os.m_buffer.p8 = dds_realloc (os.m_buffer.p8, os.m_index); + os.m_buffer = dds_realloc (os.m_buffer, os.m_index); os.m_size = os.m_index; } - dds_stream_add_to_serdata_default (&os, &d_tl); + dds_ostream_add_to_serdata_default (&os, &d_tl); } } return (struct ddsi_serdata *)d_tl; @@ -501,26 +594,30 @@ static void serdata_default_to_ser_unref (struct ddsi_serdata *serdata_common, c static bool serdata_default_to_sample_cdr (const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) { const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; - dds_stream_t is; + const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *) d->c.topic; + dds_istream_t is; if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ - dds_stream_from_serdata_default(&is, d); + assert (d->hdr.identifier == NATIVE_ENCODING); + dds_istream_from_serdata_default(&is, d); if (d->c.kind == SDK_KEY) - dds_stream_read_key (&is, sample, (const dds_topic_descriptor_t*) ((struct ddsi_sertopic_default *)d->c.topic)->type); + dds_stream_read_key (&is, sample, tp); else - dds_stream_read_sample (&is, sample, (const struct ddsi_sertopic_default *)d->c.topic); + dds_stream_read_sample (&is, sample, tp); return true; /* FIXME: can't conversion to sample fail? */ } static bool serdata_default_topicless_to_sample_cdr (const struct ddsi_sertopic *topic, const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) { const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; - dds_stream_t is; + const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *) topic; + dds_istream_t is; assert (d->c.topic == NULL); assert (d->c.kind == SDK_KEY); assert (d->c.ops == topic->serdata_ops); + assert (d->hdr.identifier == NATIVE_ENCODING); if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ - dds_stream_from_serdata_default(&is, d); - dds_stream_read_key (&is, sample, (const dds_topic_descriptor_t*) ((struct ddsi_sertopic_default *)topic)->type); + dds_istream_from_serdata_default(&is, d); + dds_stream_read_key (&is, sample, tp); return true; /* FIXME: can't conversion to sample fail? */ } diff --git a/src/core/ddsi/src/ddsi_sertopic.c b/src/core/ddsi/src/ddsi_sertopic.c index 3ce5ef1..968a1de 100644 --- a/src/core/ddsi/src/ddsi_sertopic.c +++ b/src/core/ddsi/src/ddsi_sertopic.c @@ -16,9 +16,11 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/md5.h" +#include "dds/ddsrt/string.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_serdata.h" @@ -41,6 +43,41 @@ void ddsi_sertopic_unref (struct ddsi_sertopic *sertopic) } } +void ddsi_sertopic_init (struct ddsi_sertopic *tp, const char *name, const char *type_name, const struct ddsi_sertopic_ops *sertopic_ops, const struct ddsi_serdata_ops *serdata_ops, bool topickind_no_key) +{ + ddsrt_atomic_st32 (&tp->refc, 1); + tp->iid = ddsi_iid_gen (); + tp->name = ddsrt_strdup (name); + tp->type_name = ddsrt_strdup (type_name); + size_t ntn_sz = strlen (tp->name) + 1 + strlen (tp->type_name) + 1; + tp->name_type_name = ddsrt_malloc (ntn_sz); + (void) snprintf (tp->name_type_name, ntn_sz, "%s/%s", tp->name, tp->type_name); + tp->ops = sertopic_ops; + tp->serdata_ops = serdata_ops; + tp->serdata_basehash = ddsi_sertopic_compute_serdata_basehash (tp->serdata_ops); + tp->topickind_no_key = topickind_no_key; +} + +void ddsi_sertopic_init_anon (struct ddsi_sertopic *tp, const struct ddsi_sertopic_ops *sertopic_ops, const struct ddsi_serdata_ops *serdata_ops, bool topickind_no_key) +{ + ddsrt_atomic_st32 (&tp->refc, 1); + tp->iid = ddsi_iid_gen (); + tp->name = NULL; + tp->type_name = NULL; + tp->name_type_name = NULL; + tp->ops = sertopic_ops; + tp->serdata_ops = serdata_ops; + tp->serdata_basehash = ddsi_sertopic_compute_serdata_basehash (tp->serdata_ops); + tp->topickind_no_key = topickind_no_key; +} + +void ddsi_sertopic_fini (struct ddsi_sertopic *tp) +{ + ddsrt_free (tp->name); + ddsrt_free (tp->type_name); + ddsrt_free (tp->name_type_name); +} + uint32_t ddsi_sertopic_compute_serdata_basehash (const struct ddsi_serdata_ops *ops) { ddsrt_md5_state_t md5st; diff --git a/src/core/ddsi/src/ddsi_sertopic_default.c b/src/core/ddsi/src/ddsi_sertopic_default.c index 81a40c7..0fbfec6 100644 --- a/src/core/ddsi/src/ddsi_sertopic_default.c +++ b/src/core/ddsi/src/ddsi_sertopic_default.c @@ -22,13 +22,9 @@ #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_serdata_default.h" -/* FIXME: sertopic /= ddstopic so a lot of stuff needs to be moved here from dds_topic.c and the free function needs to be implemented properly */ - static void sertopic_default_free (struct ddsi_sertopic *tp) { - ddsrt_free (tp->name_type_name); - ddsrt_free (tp->name); - ddsrt_free (tp->type_name); + ddsi_sertopic_fini (tp); ddsrt_free (tp); } @@ -42,7 +38,7 @@ static void sertopic_default_realloc_samples (void **ptrs, const struct ddsi_ser { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; const size_t size = tp->type->m_size; - char *new = dds_realloc (old, size * count); + char *new = (oldcount == count) ? old : dds_realloc (old, size * count); if (new && count > oldcount) memset (new + size * oldcount, 0, size * (count - oldcount)); for (size_t i = 0; i < count; i++) diff --git a/src/core/ddsi/src/ddsi_ssl.c b/src/core/ddsi/src/ddsi_ssl.c index 2d85f0e..e8abd98 100644 --- a/src/core/ddsi/src/ddsi_ssl.c +++ b/src/core/ddsi/src/ddsi_ssl.c @@ -28,19 +28,21 @@ #include "dds/ddsrt/sockets.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" +#include "dds/ddsi/q_globals.h" static SSL_CTX *ddsi_ssl_ctx = NULL; +static bool ddsi_ssl_allow_self_signed_hack = false; static SSL *ddsi_ssl_new (void) { return SSL_new (ddsi_ssl_ctx); } -static void ddsi_ssl_error (SSL *ssl, const char *str, int err) +static void ddsi_ssl_error (const struct q_globals *gv, SSL *ssl, const char *str, int err) { char buff[128]; ERR_error_string ((unsigned) SSL_get_error (ssl, err), buff); - DDS_ERROR ("tcp/ssl %s %s %d\n", str, buff, err); + GVERROR ("tcp/ssl %s %s %d\n", str, buff, err); } static int ddsi_ssl_verify (int ok, X509_STORE_CTX *store) @@ -52,7 +54,7 @@ static int ddsi_ssl_verify (int ok, X509_STORE_CTX *store) int err = X509_STORE_CTX_get_error (store); /* Check if allowing self-signed certificates */ - if (config.ssl_self_signed && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))) + if (ddsi_ssl_allow_self_signed_hack && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN))) ok = 1; else { @@ -63,7 +65,7 @@ static int ddsi_ssl_verify (int ok, X509_STORE_CTX *store) return ok; } -static ssize_t ddsi_ssl_read (SSL *ssl, void *buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_ssl_read (SSL *ssl, void *buf, size_t len, dds_return_t *rc) { assert (len <= INT32_MAX); if (SSL_get_shutdown (ssl) != 0) @@ -95,7 +97,7 @@ static ssize_t ddsi_ssl_read (SSL *ssl, void *buf, size_t len, dds_retcode_t *rc return rcvd; } -static ssize_t ddsi_ssl_write (SSL *ssl, const void *buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_ssl_write (SSL *ssl, const void *buf, size_t len, dds_return_t *rc) { assert(len <= INT32_MAX); @@ -176,76 +178,80 @@ static void ddsi_ssl_dynlock_destroy (CRYPTO_dynlock_value *lock, const char *fi static int ddsi_ssl_password (char *buf, int num, int rwflag, void *udata) { + struct q_globals *gv = udata; (void) rwflag; - (void) udata; - if (num < 0 || (size_t) num < strlen (config.ssl_key_pass) + 1) + if (num < 0 || (size_t) num < strlen (gv->config.ssl_key_pass) + 1) return 0; DDSRT_WARNING_MSVC_OFF(4996); - strcpy (buf, config.ssl_key_pass); + strcpy (buf, gv->config.ssl_key_pass); DDSRT_WARNING_MSVC_ON(4996); - return (int) strlen (config.ssl_key_pass); + return (int) strlen (gv->config.ssl_key_pass); } -static SSL_CTX *ddsi_ssl_ctx_init (void) +static SSL_CTX *ddsi_ssl_ctx_init (struct q_globals *gv) { SSL_CTX *ctx = SSL_CTX_new (SSLv23_method ()); unsigned disallow_TLSv1_2; /* Load certificates */ - if (! SSL_CTX_use_certificate_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM)) + if (! SSL_CTX_use_certificate_file (ctx, gv->config.ssl_keystore, SSL_FILETYPE_PEM)) { - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load certificate from file: %s\n", config.ssl_keystore); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load certificate from file: %s\n", gv->config.ssl_keystore); goto fail; } /* Set password and callback */ SSL_CTX_set_default_passwd_cb (ctx, ddsi_ssl_password); + SSL_CTX_set_default_passwd_cb_userdata (ctx, gv); /* Get private key */ - if (! SSL_CTX_use_PrivateKey_file (ctx, config.ssl_keystore, SSL_FILETYPE_PEM)) + if (! SSL_CTX_use_PrivateKey_file (ctx, gv->config.ssl_keystore, SSL_FILETYPE_PEM)) { - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load private key from file: %s\n", config.ssl_keystore); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load private key from file: %s\n", gv->config.ssl_keystore); goto fail; } /* Load CAs */ - if (! SSL_CTX_load_verify_locations (ctx, config.ssl_keystore, 0)) + if (! SSL_CTX_load_verify_locations (ctx, gv->config.ssl_keystore, 0)) { - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load CA from file: %s\n", config.ssl_keystore); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load CA from file: %s\n", gv->config.ssl_keystore); goto fail; } /* Set ciphers */ - if (! SSL_CTX_set_cipher_list (ctx, config.ssl_ciphers)) + if (! SSL_CTX_set_cipher_list (ctx, gv->config.ssl_ciphers)) { - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to set ciphers: %s\n", config.ssl_ciphers); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to set ciphers: %s\n", gv->config.ssl_ciphers); goto fail; } /* Load randomness from file (optional) */ - if (config.ssl_rand_file[0] != '\0') + if (gv->config.ssl_rand_file[0] != '\0') { - if (! RAND_load_file (config.ssl_rand_file, 4096)) + if (! RAND_load_file (gv->config.ssl_rand_file, 4096)) { - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load random seed from file: %s\n", config.ssl_rand_file); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl failed to load random seed from file: %s\n", gv->config.ssl_rand_file); goto fail; } } /* Set certificate verification policy from configuration */ - if (!config.ssl_verify) + if (!gv->config.ssl_verify) SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, NULL); else { int i = SSL_VERIFY_PEER; - if (config.ssl_verify_client) + if (gv->config.ssl_verify_client) i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + /* FIXME: whether or not self-signed is allowed is per-config, SSL_set_ex_data can fix that (or hashing ctx) */ + if (gv->config.ssl_self_signed) + ddsi_ssl_allow_self_signed_hack = true; SSL_CTX_set_verify (ctx, i, ddsi_ssl_verify); } - switch (config.ssl_min_version.major) + switch (gv->config.ssl_min_version.major) { case 1: - switch (config.ssl_min_version.minor) + switch (gv->config.ssl_min_version.minor) { case 2: disallow_TLSv1_2 = 0; @@ -254,17 +260,17 @@ static SSL_CTX *ddsi_ssl_ctx_init (void) #ifdef SSL_OP_NO_TLSv1_2 disallow_TLSv1_2 = SSL_OP_NO_TLSv1_2; #else - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: openssl version does not support disabling TLSv1.2 as required by config\n"); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: openssl version does not support disabling TLSv1.2 as required by gv->config\n"); goto fail; #endif break; default: - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", config.ssl_min_version.major, config.ssl_min_version.minor); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", gv->config.ssl_min_version.major, gv->config.ssl_min_version.minor); goto fail; } break; default: - DDS_LOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", config.ssl_min_version.major, config.ssl_min_version.minor); + GVLOG (DDS_LC_ERROR | DDS_LC_CONFIG, "tcp/ssl: can't set minimum requested TLS version to %d.%d\n", gv->config.ssl_min_version.major, gv->config.ssl_min_version.minor); goto fail; } SSL_CTX_set_options (ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | disallow_TLSv1_2); @@ -275,18 +281,18 @@ fail: return NULL; } -static void dds_report_tls_version (const SSL *ssl, const char *oper) +static void dds_report_tls_version (const struct q_globals *gv, const SSL *ssl, const char *oper) { if (ssl) { char issuer[256], subject[256]; X509_NAME_oneline (X509_get_issuer_name (SSL_get_peer_certificate (ssl)), issuer, sizeof (issuer)); X509_NAME_oneline (X509_get_subject_name (SSL_get_peer_certificate (ssl)), subject, sizeof (subject)); - DDS_TRACE("tcp/ssl %s %s issued by %s [%s]\n", oper, subject, issuer, SSL_get_version (ssl)); + GVTRACE ("tcp/ssl %s %s issued by %s [%s]\n", oper, subject, issuer, SSL_get_version (ssl)); } } -static SSL *ddsi_ssl_connect (ddsrt_socket_t sock) +static SSL *ddsi_ssl_connect (const struct q_globals *gv, ddsrt_socket_t sock) { SSL *ssl; int err; @@ -302,11 +308,11 @@ static SSL *ddsi_ssl_connect (ddsrt_socket_t sock) err = SSL_connect (ssl); if (err != 1) { - ddsi_ssl_error (ssl, "connect failed", err); + ddsi_ssl_error (gv, ssl, "connect failed", err); SSL_free (ssl); ssl = NULL; } - dds_report_tls_version (ssl, "connected to"); + dds_report_tls_version (gv, ssl, "connected to"); return ssl; } @@ -320,7 +326,7 @@ static BIO *ddsi_ssl_listen (ddsrt_socket_t sock) return bio; } -static SSL *ddsi_ssl_accept (BIO *bio, ddsrt_socket_t *sock) +static SSL *ddsi_ssl_accept (const struct q_globals *gv, BIO *bio, ddsrt_socket_t *sock) { SSL *ssl = NULL; BIO *nbio; @@ -340,12 +346,13 @@ static SSL *ddsi_ssl_accept (BIO *bio, ddsrt_socket_t *sock) ssl = NULL; } } - dds_report_tls_version (ssl, "accepted from"); + dds_report_tls_version (gv, ssl, "accepted from"); return ssl; } -static bool ddsi_ssl_init (void) +static bool ddsi_ssl_init (struct q_globals *gv) { + /* FIXME: allocate this stuff ... don't copy gv into a global variable ... */ ERR_load_BIO_strings (); SSL_load_error_strings (); SSL_library_init (); @@ -368,7 +375,7 @@ static bool ddsi_ssl_init (void) CRYPTO_set_dynlock_create_callback (ddsi_ssl_dynlock_create); CRYPTO_set_dynlock_lock_callback (ddsi_ssl_dynlock_lock); CRYPTO_set_dynlock_destroy_callback (ddsi_ssl_dynlock_destroy); - ddsi_ssl_ctx = ddsi_ssl_ctx_init (); + ddsi_ssl_ctx = ddsi_ssl_ctx_init (gv); return (ddsi_ssl_ctx != NULL); } diff --git a/src/core/ddsi/src/ddsi_tcp.c b/src/core/ddsi/src/ddsi_tcp.c index 8d7ec2b..9c7fb41 100644 --- a/src/core/ddsi/src/ddsi_tcp.c +++ b/src/core/ddsi/src/ddsi_tcp.c @@ -29,15 +29,6 @@ #define INVALID_PORT (~0u) -typedef struct ddsi_tran_factory * ddsi_tcp_factory_g_t; -static ddsrt_atomic_uint32_t ddsi_tcp_init_g = DDSRT_ATOMIC_UINT32_INIT(0); - -#ifdef DDSI_INCLUDE_SSL -static struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin; -#endif - -static const char * ddsi_name = "tcp"; - /* ddsi_tcp_conn: TCP connection for reading and writing. Mutex prevents concurrent writes to socket. Is reference counted. Peer port is actually contained in peer @@ -49,8 +40,7 @@ static const char * ddsi_name = "tcp"; wait set that manages their lifecycle. */ -typedef struct ddsi_tcp_conn -{ +typedef struct ddsi_tcp_conn { struct ddsi_tran_conn m_base; struct sockaddr_storage m_peer_addr; uint32_t m_peer_port; @@ -59,22 +49,25 @@ typedef struct ddsi_tcp_conn #ifdef DDSI_INCLUDE_SSL SSL * m_ssl; #endif -} -* ddsi_tcp_conn_t; +} *ddsi_tcp_conn_t; -typedef struct ddsi_tcp_listener -{ +typedef struct ddsi_tcp_listener { struct ddsi_tran_listener m_base; ddsrt_socket_t m_sock; #ifdef DDSI_INCLUDE_SSL BIO * m_bio; #endif -} -* ddsi_tcp_listener_t; +} *ddsi_tcp_listener_t; -/* Stateless singleton instance handed out as client connection */ - -static struct ddsi_tcp_conn ddsi_tcp_conn_client; +struct ddsi_tran_factory_tcp { + struct ddsi_tran_factory fact; + ddsrt_mutex_t ddsi_tcp_cache_lock_g; + ddsrt_avl_tree_t ddsi_tcp_cache_g; + struct ddsi_tcp_conn ddsi_tcp_conn_client; +#ifdef DDSI_INCLUDE_SSL + struct ddsi_ssl_plugins ddsi_tcp_ssl_plugin; +#endif +}; static int ddsi_tcp_cmp_conn (const struct ddsi_tcp_conn *c1, const struct ddsi_tcp_conn *c2) { @@ -92,12 +85,10 @@ static int ddsi_tcp_cmp_conn_wrap (const void *a, const void *b) return ddsi_tcp_cmp_conn (a, b); } -typedef struct ddsi_tcp_node -{ +typedef struct ddsi_tcp_node { ddsrt_avl_node_t m_avlnode; ddsi_tcp_conn_t m_conn; -} -* ddsi_tcp_node_t; +} * ddsi_tcp_node_t; static const ddsrt_avl_treedef_t ddsi_tcp_treedef = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY ( @@ -107,17 +98,13 @@ static const ddsrt_avl_treedef_t ddsi_tcp_treedef = DDSRT_AVL_TREEDEF_INITIALIZE 0 ); -static ddsrt_mutex_t ddsi_tcp_cache_lock_g; -static ddsrt_avl_tree_t ddsi_tcp_cache_g; -static struct ddsi_tran_factory ddsi_tcp_factory_g; +static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, ddsrt_socket_t, bool, struct sockaddr *); -static ddsi_tcp_conn_t ddsi_tcp_new_conn (ddsrt_socket_t, bool, struct sockaddr *); - -static char *sockaddr_to_string_with_port (char *dst, size_t sizeof_dst, const struct sockaddr *src) +static char *sockaddr_to_string_with_port (const struct q_globals *gv, char *dst, size_t sizeof_dst, const struct sockaddr *src) { nn_locator_t loc; ddsi_ipaddr_to_loc(&loc, src, src->sa_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); - ddsi_locator_to_string(dst, sizeof_dst, &loc); + ddsi_locator_to_string(gv, dst, sizeof_dst, &loc); return dst; } @@ -146,15 +133,15 @@ static void ddsi_tcp_cache_dump (void) } */ -static unsigned short get_socket_port (ddsrt_socket_t socket) +static unsigned short get_socket_port (struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket) { struct sockaddr_storage addr; socklen_t addrlen = sizeof (addr); - dds_retcode_t ret; + dds_return_t ret; ret = ddsrt_getsockname(socket, (struct sockaddr *)&addr, &addrlen); if (ret != DDS_RETCODE_OK) { - DDS_ERROR("ddsi_tcp_get_socket_port: ddsrt_getsockname retcode %"PRId32"\n", ret); + DDS_CERROR (logcfg, "ddsi_tcp_get_socket_port: ddsrt_getsockname retcode %"PRId32"\n", ret); return 0; } return ddsrt_sockaddr_get_port((struct sockaddr *)&addr); @@ -163,24 +150,24 @@ static unsigned short get_socket_port (ddsrt_socket_t socket) static void ddsi_tcp_conn_set_socket (ddsi_tcp_conn_t conn, ddsrt_socket_t sock) { conn->m_sock = sock; - conn->m_base.m_base.m_port = (sock == DDSRT_INVALID_SOCKET) ? INVALID_PORT : get_socket_port (sock); + conn->m_base.m_base.m_port = (sock == DDSRT_INVALID_SOCKET) ? INVALID_PORT : get_socket_port (&conn->m_base.m_base.gv->logconfig, sock); } -static void ddsi_tcp_sock_free (ddsrt_socket_t sock, const char * msg) +static void ddsi_tcp_sock_free (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock, const char *msg) { if (sock != DDSRT_INVALID_SOCKET) { if (msg) { - DDS_LOG(DDS_LC_TCP, "%s %s free socket %"PRIdSOCK"\n", ddsi_name, msg, sock); + DDS_CLOG (DDS_LC_TCP, logcfg, "tcp %s free socket %"PRIdSOCK"\n", msg, sock); } ddsrt_close (sock); } } -static void ddsi_tcp_sock_new (ddsrt_socket_t * sock, unsigned short port) +static void ddsi_tcp_sock_new (ddsrt_socket_t *sock, unsigned short port, const struct q_globals *gv) { - if (make_socket (sock, port, true, true) != 0) + if (make_socket (sock, port, true, true, gv) != 0) { *sock = DDSRT_INVALID_SOCKET; } @@ -195,11 +182,14 @@ static void ddsi_tcp_node_free (void * ptr) static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t * msg) { +#ifdef DDSI_INCLUDE_SSL + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) conn->m_base.m_factory; +#endif char buff[DDSI_LOCSTRLEN]; ddsrt_socket_t sock; - dds_retcode_t ret; + dds_return_t ret; - ddsi_tcp_sock_new (&sock, 0); + ddsi_tcp_sock_new (&sock, 0, conn->m_base.m_base.gv); if (sock != DDSRT_INVALID_SOCKET) { /* Attempt to connect, expected that may fail */ @@ -212,15 +202,15 @@ static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t * if (ret != DDS_RETCODE_OK) { - ddsi_tcp_sock_free (sock, NULL); + ddsi_tcp_sock_free (&conn->m_base.m_base.gv->logconfig, sock, NULL); return; } ddsi_tcp_conn_set_socket (conn, sock); #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.connect) + if (fact->ddsi_tcp_ssl_plugin.connect) { - conn->m_ssl = (ddsi_tcp_ssl_plugin.connect) (sock); + conn->m_ssl = (fact->ddsi_tcp_ssl_plugin.connect) (conn->m_base.m_base.gv, sock); if (conn->m_ssl == NULL) { ddsi_tcp_conn_set_socket (conn, DDSRT_INVALID_SOCKET); @@ -229,21 +219,21 @@ static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t * } #endif - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *) msg->msg_name); - DDS_LOG(DDS_LC_TCP, "%s connect socket %"PRIdSOCK" port %u to %s\n", ddsi_name, sock, get_socket_port (sock), buff); + sockaddr_to_string_with_port(conn->m_base.m_base.gv, buff, sizeof(buff), (struct sockaddr *) msg->msg_name); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp connect socket %"PRIdSOCK" port %u to %s\n", sock, get_socket_port (&conn->m_base.m_base.gv->logconfig, sock), buff); /* Also may need to receive on connection so add to waitset */ (void)ddsrt_setsocknonblocking(conn->m_sock, true); - assert (gv.n_recv_threads > 0); - assert (gv.recv_threads[0].arg.mode == RTM_MANY); - os_sockWaitsetAdd (gv.recv_threads[0].arg.u.many.ws, &conn->m_base); - os_sockWaitsetTrigger (gv.recv_threads[0].arg.u.many.ws); + assert (conn->m_base.m_base.gv->n_recv_threads > 0); + assert (conn->m_base.m_base.gv->recv_threads[0].arg.mode == RTM_MANY); + os_sockWaitsetAdd (conn->m_base.m_base.gv->recv_threads[0].arg.u.many.ws, &conn->m_base); + os_sockWaitsetTrigger (conn->m_base.m_base.gv->recv_threads[0].arg.u.many.ws); } } -static void ddsi_tcp_cache_add (ddsi_tcp_conn_t conn, ddsrt_avl_ipath_t * path) +static void ddsi_tcp_cache_add (struct ddsi_tran_factory_tcp *fact, ddsi_tcp_conn_t conn, ddsrt_avl_ipath_t * path) { const char * action = "added"; ddsi_tcp_node_t node; @@ -256,11 +246,11 @@ static void ddsi_tcp_cache_add (ddsi_tcp_conn_t conn, ddsrt_avl_ipath_t * path) { node = ddsrt_malloc (sizeof (*node)); node->m_conn = conn; - ddsrt_avl_insert_ipath (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, node, path); + ddsrt_avl_insert_ipath (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, node, path); } else { - node = ddsrt_avl_lookup (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, conn); + node = ddsrt_avl_lookup (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, conn); if (node) { /* Replace connection in cache */ @@ -273,30 +263,31 @@ static void ddsi_tcp_cache_add (ddsi_tcp_conn_t conn, ddsrt_avl_ipath_t * path) { node = ddsrt_malloc (sizeof (*node)); node->m_conn = conn; - ddsrt_avl_insert (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, node); + ddsrt_avl_insert (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, node); } } - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); - DDS_LOG(DDS_LC_TCP, "%s cache %s %s socket %"PRIdSOCK" to %s\n", ddsi_name, action, conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); + sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + DDS_CLOG (DDS_LC_TCP, &fact->fact.gv->logconfig, "tcp cache %s %s socket %"PRIdSOCK" to %s\n", action, conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); } static void ddsi_tcp_cache_remove (ddsi_tcp_conn_t conn) { + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) conn->m_base.m_factory; char buff[DDSI_LOCSTRLEN]; ddsi_tcp_node_t node; ddsrt_avl_dpath_t path; - ddsrt_mutex_lock (&ddsi_tcp_cache_lock_g); - node = ddsrt_avl_lookup_dpath (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, conn, &path); + ddsrt_mutex_lock (&fact->ddsi_tcp_cache_lock_g); + node = ddsrt_avl_lookup_dpath (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, conn, &path); if (node) { - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); - DDS_LOG(DDS_LC_TCP, "%s cache removed socket %"PRIdSOCK" to %s\n", ddsi_name, conn->m_sock, buff); - ddsrt_avl_delete_dpath (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, node, &path); + sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp cache removed socket %"PRIdSOCK" to %s\n", conn->m_sock, buff); + ddsrt_avl_delete_dpath (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, node, &path); ddsi_tcp_node_free (node); } - ddsrt_mutex_unlock (&ddsi_tcp_cache_lock_g); + ddsrt_mutex_unlock (&fact->ddsi_tcp_cache_lock_g); } /* @@ -304,7 +295,7 @@ static void ddsi_tcp_cache_remove (ddsi_tcp_conn_t conn) create new connection. */ -static ddsi_tcp_conn_t ddsi_tcp_cache_find (const ddsrt_msghdr_t * msg) +static ddsi_tcp_conn_t ddsi_tcp_cache_find (struct ddsi_tran_factory_tcp *fact, const ddsrt_msghdr_t * msg) { ddsrt_avl_ipath_t path; ddsi_tcp_node_t node; @@ -317,13 +308,13 @@ static ddsi_tcp_conn_t ddsi_tcp_cache_find (const ddsrt_msghdr_t * msg) /* Check cache for existing connection to target */ - ddsrt_mutex_lock (&ddsi_tcp_cache_lock_g); - node = ddsrt_avl_lookup_ipath (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, &key, &path); + ddsrt_mutex_lock (&fact->ddsi_tcp_cache_lock_g); + node = ddsrt_avl_lookup_ipath (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, &key, &path); if (node) { if (node->m_conn->m_base.m_closed) { - ddsrt_avl_delete (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, node); + ddsrt_avl_delete (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, node); ddsi_tcp_node_free (node); } else @@ -333,15 +324,15 @@ static ddsi_tcp_conn_t ddsi_tcp_cache_find (const ddsrt_msghdr_t * msg) } if (ret == NULL) { - ret = ddsi_tcp_new_conn (DDSRT_INVALID_SOCKET, false, (struct sockaddr *)&key.m_peer_addr); - ddsi_tcp_cache_add (ret, &path); + ret = ddsi_tcp_new_conn (fact, DDSRT_INVALID_SOCKET, false, (struct sockaddr *)&key.m_peer_addr); + ddsi_tcp_cache_add (fact, ret, &path); } - ddsrt_mutex_unlock (&ddsi_tcp_cache_lock_g); + ddsrt_mutex_unlock (&fact->ddsi_tcp_cache_lock_g); return ret; } -static ssize_t ddsi_tcp_conn_read_plain (ddsi_tcp_conn_t tcp, void * buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_tcp_conn_read_plain (ddsi_tcp_conn_t tcp, void * buf, size_t len, dds_return_t *rc) { ssize_t rcvd = -1; @@ -352,51 +343,57 @@ static ssize_t ddsi_tcp_conn_read_plain (ddsi_tcp_conn_t tcp, void * buf, size_t } #ifdef DDSI_INCLUDE_SSL -static ssize_t ddsi_tcp_conn_read_ssl (ddsi_tcp_conn_t tcp, void * buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_tcp_conn_read_ssl (ddsi_tcp_conn_t tcp, void * buf, size_t len, dds_return_t *rc) { - return (ddsi_tcp_ssl_plugin.read) (tcp->m_ssl, buf, len, rc); + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) tcp->m_base.m_factory; + return (fact->ddsi_tcp_ssl_plugin.read) (tcp->m_ssl, buf, len, rc); } #endif -static bool ddsi_tcp_select (ddsrt_socket_t sock, bool read, size_t pos) +static bool ddsi_tcp_select (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock, bool read, size_t pos, int64_t timeout) { - dds_retcode_t rc; + dds_return_t rc; fd_set fds; - fd_set * rdset = read ? &fds : NULL; - fd_set * wrset = read ? NULL : &fds; - int64_t tval = read ? config.tcp_read_timeout : config.tcp_write_timeout; + fd_set *rdset = read ? &fds : NULL; + fd_set *wrset = read ? NULL : &fds; + int64_t tval = timeout; 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); + DDS_CLOG (DDS_LC_TCP, logcfg, "tcp blocked %s: sock %d\n", read ? "read" : "write", (int) sock); do { rc = ddsrt_select (sock + 1, rdset, wrset, NULL, tval, &ready); } while (rc == DDS_RETCODE_INTERRUPTED); if (rc != DDS_RETCODE_OK) { - DDS_WARNING - ( - "%s abandoning %s on blocking socket %d after %"PRIuSIZE" bytes\n", - ddsi_name, read ? "read" : "write", (int) sock, pos - ); + DDS_CWARNING (logcfg, "tcp abandoning %s on blocking socket %d after %"PRIuSIZE" bytes\n", read ? "read" : "write", (int) sock, pos); } return (ready > 0); } -static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc) +static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char *buf, size_t len, bool allow_spurious, nn_locator_t *srcloc) { - dds_retcode_t rc; +#ifdef DDSI_INCLUDE_SSL + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) conn->m_factory; +#endif + dds_return_t rc; ddsi_tcp_conn_t tcp = (ddsi_tcp_conn_t) conn; - ssize_t (*rd) (ddsi_tcp_conn_t, void *, size_t, dds_retcode_t * err) = ddsi_tcp_conn_read_plain; + ssize_t (*rd) (ddsi_tcp_conn_t, void *, size_t, dds_return_t * err) = ddsi_tcp_conn_read_plain; size_t pos = 0; ssize_t n; #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.read) + if (fact->ddsi_tcp_ssl_plugin.read) { rd = ddsi_tcp_conn_read_ssl; } @@ -419,7 +416,7 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s } else if (n == 0) { - DDS_LOG(DDS_LC_TCP, "%s read: sock %"PRIdSOCK" closed-by-peer\n", ddsi_name, tcp->m_sock); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.gv->logconfig, "tcp read: sock %"PRIdSOCK" closed-by-peer\n", tcp->m_sock); break; } else @@ -430,12 +427,13 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s { if (allow_spurious && pos == 0) return 0; - else if (ddsi_tcp_select (tcp->m_sock, true, pos) == false) + const int64_t timeout = conn->m_base.gv->config.tcp_read_timeout; + if (ddsi_tcp_select (&conn->m_base.gv->logconfig, tcp->m_sock, true, pos, timeout) == false) break; } else { - DDS_LOG(DDS_LC_TCP, "%s read: sock %"PRIdSOCK" error %"PRId32"\n", ddsi_name, tcp->m_sock, rc); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.gv->logconfig, "tcp read: sock %"PRIdSOCK" error %"PRId32"\n", tcp->m_sock, rc); break; } } @@ -446,7 +444,7 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s return -1; } -static ssize_t ddsi_tcp_conn_write_plain (ddsi_tcp_conn_t conn, const void * buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_tcp_conn_write_plain (ddsi_tcp_conn_t conn, const void * buf, size_t len, dds_return_t *rc) { ssize_t sent = -1; int sendflags = 0; @@ -460,23 +458,18 @@ static ssize_t ddsi_tcp_conn_write_plain (ddsi_tcp_conn_t conn, const void * buf } #ifdef DDSI_INCLUDE_SSL -static ssize_t ddsi_tcp_conn_write_ssl (ddsi_tcp_conn_t conn, const void * buf, size_t len, dds_retcode_t *rc) +static ssize_t ddsi_tcp_conn_write_ssl (ddsi_tcp_conn_t conn, const void * buf, size_t len, dds_return_t *rc) { - return (ddsi_tcp_ssl_plugin.write) (conn->m_ssl, buf, len, rc); + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) conn->m_base.m_factory; + return (fact->ddsi_tcp_ssl_plugin.write) (conn->m_ssl, buf, len, rc); } #endif -static ssize_t ddsi_tcp_block_write -( - ssize_t (*wr) (ddsi_tcp_conn_t, const void *, size_t, dds_retcode_t *), - ddsi_tcp_conn_t conn, - const void * buf, - size_t sz -) +static ssize_t ddsi_tcp_block_write (ssize_t (*wr) (ddsi_tcp_conn_t, const void *, size_t, dds_return_t *), ddsi_tcp_conn_t conn, const void * buf, size_t sz) { /* Write all bytes of buf even in the presence of signals, partial writes and blocking (typically write buffer full) */ - dds_retcode_t rc; + dds_return_t rc; size_t pos = 0; ssize_t n = -1; @@ -493,14 +486,15 @@ static ssize_t ddsi_tcp_block_write { if (rc == DDS_RETCODE_TRY_AGAIN) { - if (ddsi_tcp_select (conn->m_sock, false, pos) == false) + const int64_t timeout = conn->m_base.m_base.gv->config.tcp_write_timeout; + if (ddsi_tcp_select (&conn->m_base.m_base.gv->logconfig, conn->m_sock, false, pos, timeout) == false) { break; } } else { - DDS_LOG(DDS_LC_TCP, "%s write: sock %"PRIdSOCK" error %"PRId32"\n", ddsi_name, conn->m_sock, rc); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp write: sock %"PRIdSOCK" error %"PRId32"\n", conn->m_sock, rc); break; } } @@ -513,9 +507,8 @@ static ssize_t ddsi_tcp_block_write static size_t iovlen_sum (size_t niov, const ddsrt_iovec_t *iov) { size_t tot = 0; - while (niov--) { + while (niov--) tot += iov++->iov_len; - } return tot; } @@ -527,6 +520,7 @@ static void set_msghdr_iov (ddsrt_msghdr_t *mhdr, ddsrt_iovec_t *iov, size_t iov static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *dst, size_t niov, const ddsrt_iovec_t *iov, uint32_t flags) { + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) base->m_factory; #ifdef DDSI_INCLUDE_SSL char msgbuf[4096]; /* stack buffer for merging smallish writes without requiring allocations */ ddsrt_iovec_t iovec; /* iovec used for msgbuf */ @@ -550,7 +544,7 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d len = iovlen_sum (niov, iov); (void) base; - conn = ddsi_tcp_cache_find (&msg); + conn = ddsi_tcp_cache_find (fact, &msg); if (conn == NULL) { return -1; @@ -575,13 +569,13 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d if (!connect && ((flags & DDSI_TRAN_ON_CONNECT) != 0)) { - DDS_LOG(DDS_LC_TCP, "%s write: sock %"PRIdSOCK" message filtered\n", ddsi_name, conn->m_sock); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp write: sock %"PRIdSOCK" message filtered\n", conn->m_sock); ddsrt_mutex_unlock (&conn->m_mutex); return (ssize_t) len; } #ifdef DDSI_INCLUDE_SSL - if (config.ssl_enable) + if (base->m_base.gv->config.ssl_enable) { /* SSL doesn't have sendmsg, ret = 0 so writing starts at first byte. Rumor is that it is much better to merge small writes, which do here @@ -609,7 +603,7 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d #endif { int sendflags = 0; - dds_retcode_t rc; + dds_return_t rc; #ifdef MSG_NOSIGNAL sendflags |= MSG_NOSIGNAL; #endif @@ -634,11 +628,11 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d { case DDS_RETCODE_NO_CONNECTION: case DDS_RETCODE_ILLEGAL_OPERATION: - DDS_LOG(DDS_LC_TCP, "%s write: sock %"PRIdSOCK" DDS_RETCODE_NO_CONNECTION\n", ddsi_name, conn->m_sock); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp write: sock %"PRIdSOCK" DDS_RETCODE_NO_CONNECTION\n", conn->m_sock); break; default: if (! conn->m_base.m_closed && (conn->m_sock != DDSRT_INVALID_SOCKET)) - DDS_WARNING("%s write failed on socket %"PRIdSOCK" with errno %"PRId32"\n", ddsi_name, conn->m_sock, rc); + DDS_CWARNING (&conn->m_base.m_base.gv->logconfig, "tcp write failed on socket %"PRIdSOCK" with errno %"PRId32"\n", conn->m_sock, rc); break; } } @@ -647,7 +641,7 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d { if (ret == 0) { - DDS_LOG(DDS_LC_TCP, "%s write: sock %"PRIdSOCK" eof\n", ddsi_name, conn->m_sock); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp write: sock %"PRIdSOCK" eof\n", conn->m_sock); } piecewise = (ret > 0 && (size_t) ret < len); } @@ -655,10 +649,10 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d if (piecewise) { - ssize_t (*wr) (ddsi_tcp_conn_t, const void *, size_t, dds_retcode_t *) = ddsi_tcp_conn_write_plain; + ssize_t (*wr) (ddsi_tcp_conn_t, const void *, size_t, dds_return_t *) = ddsi_tcp_conn_write_plain; int i = 0; #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.write) + if (fact->ddsi_tcp_ssl_plugin.write) { wr = ddsi_tcp_conn_write_ssl; } @@ -700,35 +694,40 @@ static ddsrt_socket_t ddsi_tcp_conn_handle (ddsi_tran_base_t base) return ((ddsi_tcp_conn_t) base)->m_sock; } -static bool ddsi_tcp_supports (int32_t kind) +ddsrt_attribute_no_sanitize (("thread")) +static bool ddsi_tcp_supports (const struct ddsi_tran_factory *fact_cmn, int32_t kind) { - return kind == ddsi_tcp_factory_g.m_kind; + return kind == fact_cmn->m_kind; } -static int ddsi_tcp_locator (ddsi_tran_base_t base, nn_locator_t *loc) +static int ddsi_tcp_locator (struct ddsi_tran_factory *fact_cmn, ddsi_tran_base_t base, nn_locator_t *loc) { - loc->kind = ddsi_tcp_factory_g.m_kind; - memcpy(loc->address, gv.extloc.address, sizeof(loc->address)); + loc->kind = fact_cmn->m_kind; + memcpy(loc->address, base->gv->extloc.address, sizeof(loc->address)); loc->port = base->m_port; return 0; } -static ddsi_tran_conn_t ddsi_tcp_create_conn (uint32_t port, ddsi_tran_qos_t qos) +static ddsi_tran_conn_t ddsi_tcp_create_conn (struct ddsi_tran_factory *fact_cmn, uint32_t port, ddsi_tran_qos_t qos) { + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) fact_cmn; (void) qos; (void) port; - return &ddsi_tcp_conn_client.m_base; + return &fact->ddsi_tcp_conn_client.m_base; } static int ddsi_tcp_listen (ddsi_tran_listener_t listener) { +#ifdef DDSI_INCLUDE_SSL + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory; +#endif ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener; int ret = listen (tl->m_sock, 4); #ifdef DDSI_INCLUDE_SSL - if ((ret == 0) && ddsi_tcp_ssl_plugin.listen) + if ((ret == 0) && fact->ddsi_tcp_ssl_plugin.listen) { - tl->m_bio = (ddsi_tcp_ssl_plugin.listen) (tl->m_sock); + tl->m_bio = (fact->ddsi_tcp_ssl_plugin.listen) (tl->m_sock); } #endif @@ -737,13 +736,14 @@ static int ddsi_tcp_listen (ddsi_tran_listener_t listener) static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) { + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory; ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener; ddsi_tcp_conn_t tcp = NULL; ddsrt_socket_t sock = DDSRT_INVALID_SOCKET; struct sockaddr_storage addr; socklen_t addrlen = sizeof (addr); char buff[DDSI_LOCSTRLEN]; - dds_retcode_t rc = DDS_RETCODE_OK; + dds_return_t rc = DDS_RETCODE_OK; #ifdef DDSI_INCLUDE_SSL SSL * ssl = NULL; #endif @@ -751,9 +751,9 @@ static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) memset (&addr, 0, addrlen); do { #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.accept) + if (fact->ddsi_tcp_ssl_plugin.accept) { - ssl = (ddsi_tcp_ssl_plugin.accept) (tl->m_bio, &sock); + ssl = (fact->ddsi_tcp_ssl_plugin.accept) (listener->m_base.gv, tl->m_bio, &sock); if (ssl == NULL) { assert(sock == DDSRT_INVALID_SOCKET); rc = DDS_RETCODE_ERROR; @@ -764,9 +764,9 @@ static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) { rc = ddsrt_accept(tl->m_sock, NULL, NULL, &sock); } - if (! gv.rtps_keepgoing) + if (!ddsrt_atomic_ld32(&listener->m_base.gv->rtps_keepgoing)) { - ddsi_tcp_sock_free (sock, NULL); + ddsi_tcp_sock_free (&listener->m_base.gv->logconfig, sock, NULL); return NULL; } } while (rc == DDS_RETCODE_INTERRUPTED || rc == DDS_RETCODE_TRY_AGAIN); @@ -774,21 +774,21 @@ static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) if (sock == DDSRT_INVALID_SOCKET) { (void)ddsrt_getsockname (tl->m_sock, (struct sockaddr *) &addr, &addrlen); - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&addr); - DDS_LOG((rc == DDS_RETCODE_OK) ? DDS_LC_ERROR : DDS_LC_FATAL, "%s accept failed on socket %"PRIdSOCK" at %s retcode %"PRId32"\n", ddsi_name, tl->m_sock, buff, rc); + sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + DDS_CLOG ((rc == DDS_RETCODE_OK) ? DDS_LC_ERROR : DDS_LC_FATAL, &listener->m_base.gv->logconfig, "tcp accept failed on socket %"PRIdSOCK" at %s retcode %"PRId32"\n", tl->m_sock, buff, rc); } else if (getpeername (sock, (struct sockaddr *) &addr, &addrlen) == -1) { - DDS_WARNING("%s accepted new socket %"PRIdSOCK" on socket %"PRIdSOCK" but no peer address, errno %"PRId32"\n", ddsi_name, sock, tl->m_sock, rc); + DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp accepted new socket %"PRIdSOCK" on socket %"PRIdSOCK" but no peer address, errno %"PRId32"\n", sock, tl->m_sock, rc); ddsrt_close (sock); } else { - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&addr); - DDS_LOG(DDS_LC_TCP, "%s accept new socket %"PRIdSOCK" on socket %"PRIdSOCK" from %s\n", ddsi_name, sock, tl->m_sock, buff); + sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + DDS_CLOG (DDS_LC_TCP, &listener->m_base.gv->logconfig, "tcp accept new socket %"PRIdSOCK" on socket %"PRIdSOCK" from %s\n", sock, tl->m_sock, buff); (void)ddsrt_setsocknonblocking (sock, true); - tcp = ddsi_tcp_new_conn (sock, true, (struct sockaddr *)&addr); + tcp = ddsi_tcp_new_conn (fact, sock, true, (struct sockaddr *)&addr); #ifdef DDSI_INCLUDE_SSL tcp->m_ssl = ssl; #endif @@ -798,9 +798,9 @@ static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) /* Add connection to cache for bi-dir */ - ddsrt_mutex_lock (&ddsi_tcp_cache_lock_g); - ddsi_tcp_cache_add (tcp, NULL); - ddsrt_mutex_unlock (&ddsi_tcp_cache_lock_g); + ddsrt_mutex_lock (&fact->ddsi_tcp_cache_lock_g); + ddsi_tcp_cache_add (fact, tcp, NULL); + ddsrt_mutex_unlock (&fact->ddsi_tcp_cache_lock_g); } return tcp ? &tcp->m_base : NULL; } @@ -822,28 +822,28 @@ static void ddsi_tcp_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * lo ddsi_tcp_conn_t tc = (ddsi_tcp_conn_t) conn; assert (tc->m_sock != DDSRT_INVALID_SOCKET); ddsi_ipaddr_to_loc (loc, (struct sockaddr *)&tc->m_peer_addr, tc->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); - ddsi_locator_to_string(buff, sizeof(buff), loc); - DDS_LOG(DDS_LC_TCP, "(%s EP:%s)", ddsi_name, buff); + ddsi_locator_to_string(conn->m_base.gv, buff, sizeof(buff), loc); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.gv->logconfig, "(tcp EP:%s)", buff); } -static void ddsi_tcp_base_init (struct ddsi_tran_conn * base) +static void ddsi_tcp_base_init (const struct ddsi_tran_factory_tcp *fact, struct ddsi_tran_conn *base) { - ddsi_factory_conn_init (&ddsi_tcp_factory_g, base); + ddsi_factory_conn_init (&fact->fact, base); base->m_base.m_trantype = DDSI_TRAN_CONN; base->m_base.m_handle_fn = ddsi_tcp_conn_handle; - base->m_base.m_locator_fn = ddsi_tcp_locator; base->m_read_fn = ddsi_tcp_conn_read; base->m_write_fn = ddsi_tcp_conn_write; base->m_peer_locator_fn = ddsi_tcp_conn_peer_locator; base->m_disable_multiplexing_fn = 0; + base->m_locator_fn = ddsi_tcp_locator; } -static ddsi_tcp_conn_t ddsi_tcp_new_conn (ddsrt_socket_t sock, bool server, struct sockaddr * peer) +static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, ddsrt_socket_t sock, bool server, struct sockaddr * peer) { ddsi_tcp_conn_t conn = (ddsi_tcp_conn_t) ddsrt_malloc (sizeof (*conn)); memset (conn, 0, sizeof (*conn)); - ddsi_tcp_base_init (&conn->m_base); + ddsi_tcp_base_init (fact, &conn->m_base); ddsrt_mutex_init (&conn->m_mutex); conn->m_sock = DDSRT_INVALID_SOCKET; (void)memcpy(&conn->m_peer_addr, peer, ddsrt_sockaddr_get_size(peer)); @@ -855,7 +855,7 @@ static ddsi_tcp_conn_t ddsi_tcp_new_conn (ddsrt_socket_t sock, bool server, stru return conn; } -static ddsi_tran_listener_t ddsi_tcp_create_listener (int port, ddsi_tran_qos_t qos) +static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t qos) { char buff[DDSI_LOCSTRLEN]; ddsrt_socket_t sock; @@ -865,35 +865,36 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (int port, ddsi_tran_qos_t (void) qos; - ddsi_tcp_sock_new (&sock, (unsigned short) port); + ddsi_tcp_sock_new (&sock, (unsigned short) port, fact->gv); if (sock != DDSRT_INVALID_SOCKET) { - dds_retcode_t ret; + dds_return_t ret; tl = (ddsi_tcp_listener_t) ddsrt_malloc (sizeof (*tl)); memset (tl, 0, sizeof (*tl)); tl->m_sock = sock; + tl->m_base.m_base.gv = fact->gv; tl->m_base.m_listen_fn = ddsi_tcp_listen; tl->m_base.m_accept_fn = ddsi_tcp_accept; - tl->m_base.m_factory = &ddsi_tcp_factory_g; + tl->m_base.m_factory = fact; - tl->m_base.m_base.m_port = get_socket_port (sock); + tl->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock); tl->m_base.m_base.m_trantype = DDSI_TRAN_LISTENER; tl->m_base.m_base.m_handle_fn = ddsi_tcp_listener_handle; - tl->m_base.m_base.m_locator_fn = ddsi_tcp_locator; + tl->m_base.m_locator_fn = ddsi_tcp_locator; ret = ddsrt_getsockname(sock, (struct sockaddr *)&addr, &addrlen); if (ret != DDS_RETCODE_OK) { - DDS_ERROR("ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret); - ddsi_tcp_sock_free(sock, NULL); + DDS_CERROR (&fact->gv->logconfig, "ddsi_tcp_create_listener: ddsrt_getsockname returned %"PRId32"\n", ret); + ddsi_tcp_sock_free(&fact->gv->logconfig, sock, NULL); ddsrt_free(tl); return NULL; } - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&addr); - DDS_LOG(DDS_LC_TCP, "%s create listener socket %"PRIdSOCK" on %s\n", ddsi_name, sock, buff); + sockaddr_to_string_with_port(fact->gv, buff, sizeof(buff), (struct sockaddr *)&addr); + DDS_CLOG (DDS_LC_TCP, &fact->gv->logconfig, "tcp create listener socket %"PRIdSOCK" on %s\n", sock, buff); } return tl ? &tl->m_base : NULL; @@ -901,19 +902,22 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (int port, ddsi_tran_qos_t static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn) { +#ifdef DDSI_INCLUDE_SSL + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) conn->m_base.m_factory; +#endif char buff[DDSI_LOCSTRLEN]; - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); - DDS_LOG(DDS_LC_TCP, "%s free %s connnection on socket %"PRIdSOCK" to %s\n", ddsi_name, conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); + sockaddr_to_string_with_port(conn->m_base.m_base.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + DDS_CLOG (DDS_LC_TCP, &conn->m_base.m_base.gv->logconfig, "tcp free %s connnection on socket %"PRIdSOCK" to %s\n", conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.ssl_free) + if (fact->ddsi_tcp_ssl_plugin.ssl_free) { - (ddsi_tcp_ssl_plugin.ssl_free) (conn->m_ssl); + (fact->ddsi_tcp_ssl_plugin.ssl_free) (conn->m_ssl); } else #endif { - ddsi_tcp_sock_free (conn->m_sock, "connection"); + ddsi_tcp_sock_free (&conn->m_base.m_base.gv->logconfig, conn->m_sock, "connection"); } ddsrt_mutex_destroy (&conn->m_mutex); ddsrt_free (conn); @@ -921,23 +925,25 @@ static void ddsi_tcp_conn_delete (ddsi_tcp_conn_t conn) static void ddsi_tcp_close_conn (ddsi_tran_conn_t tc) { - if (tc != &ddsi_tcp_conn_client.m_base) + struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) tc->m_factory; + if (tc != &fact_tcp->ddsi_tcp_conn_client.m_base) { char buff[DDSI_LOCSTRLEN]; nn_locator_t loc; ddsi_tcp_conn_t conn = (ddsi_tcp_conn_t) tc; - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); - DDS_LOG(DDS_LC_TCP, "%s close %s connnection on socket %"PRIdSOCK" to %s\n", ddsi_name, conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); + sockaddr_to_string_with_port(tc->m_base.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + DDS_CLOG (DDS_LC_TCP, &tc->m_base.gv->logconfig, "tcp close %s connnection on socket %"PRIdSOCK" to %s\n", conn->m_base.m_server ? "server" : "client", conn->m_sock, buff); (void) shutdown (conn->m_sock, 2); ddsi_ipaddr_to_loc(&loc, (struct sockaddr *)&conn->m_peer_addr, conn->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); loc.port = conn->m_peer_port; - purge_proxy_participants (&loc, conn->m_base.m_server); + purge_proxy_participants (conn->m_base.m_base.gv, &loc, conn->m_base.m_server); } } static void ddsi_tcp_release_conn (ddsi_tran_conn_t conn) { - if (conn != &ddsi_tcp_conn_client.m_base) + struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) conn->m_factory; + if (conn != &fact_tcp->ddsi_tcp_conn_client.m_base) { ddsi_tcp_conn_delete ((ddsi_tcp_conn_t) conn); } @@ -947,10 +953,10 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener) { ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener; ddsrt_socket_t sock; - dds_retcode_t ret; + dds_return_t ret; /* Connect to own listener socket to wake listener from blocking 'accept()' */ - ddsi_tcp_sock_new (&sock, 0); + ddsi_tcp_sock_new (&sock, 0, listener->m_base.gv); if (sock != DDSRT_INVALID_SOCKET) { struct sockaddr_storage addr; @@ -958,7 +964,7 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener) ret = ddsrt_getsockname(tl->m_sock, (struct sockaddr *)&addr, &addrlen); if (ret != DDS_RETCODE_OK) { - DDS_WARNING("%s failed to get listener address error %"PRId32"\n", ddsi_name, ret); + DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp failed to get listener address error %"PRId32"\n", ret); } else { switch (addr.ss_family) { case AF_INET: @@ -987,11 +993,11 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener) if (ret != DDS_RETCODE_OK) { char buff[DDSI_LOCSTRLEN]; - sockaddr_to_string_with_port(buff, sizeof(buff), (struct sockaddr *)&addr); - DDS_WARNING("%s failed to connect to own listener (%s) error %"PRId32"\n", ddsi_name, buff, ret); + sockaddr_to_string_with_port(listener->m_base.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + DDS_CWARNING (&listener->m_base.gv->logconfig, "tcp failed to connect to own listener (%s) error %"PRId32"\n", buff, ret); } } - ddsi_tcp_sock_free (sock, NULL); + ddsi_tcp_sock_free (&listener->m_base.gv->logconfig, sock, NULL); } } @@ -999,33 +1005,34 @@ static void ddsi_tcp_release_listener (ddsi_tran_listener_t listener) { ddsi_tcp_listener_t tl = (ddsi_tcp_listener_t) listener; #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.bio_vfree) + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory; + if (fact->ddsi_tcp_ssl_plugin.bio_vfree) { - (ddsi_tcp_ssl_plugin.bio_vfree) (tl->m_bio); + (fact->ddsi_tcp_ssl_plugin.bio_vfree) (tl->m_bio); } #endif - ddsi_tcp_sock_free (tl->m_sock, "listener"); + ddsi_tcp_sock_free (&listener->m_base.gv->logconfig, tl->m_sock, "listener"); ddsrt_free (tl); } -static void ddsi_tcp_release_factory (void) +static void ddsi_tcp_release_factory (struct ddsi_tran_factory *fact_cmn) { - if (ddsrt_atomic_dec32_nv (&ddsi_tcp_init_g) == 0) { - ddsrt_avl_free (&ddsi_tcp_treedef, &ddsi_tcp_cache_g, ddsi_tcp_node_free); - ddsrt_mutex_destroy (&ddsi_tcp_cache_lock_g); + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) fact_cmn; + ddsrt_avl_free (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, ddsi_tcp_node_free); + ddsrt_mutex_destroy (&fact->ddsi_tcp_cache_lock_g); #ifdef DDSI_INCLUDE_SSL - if (ddsi_tcp_ssl_plugin.fini) - { - (ddsi_tcp_ssl_plugin.fini) (); - } -#endif - DDS_LOG(DDS_LC_CONFIG, "tcp de-initialized\n"); + if (fact->ddsi_tcp_ssl_plugin.fini) + { + (fact->ddsi_tcp_ssl_plugin.fini) (); } +#endif + DDS_CLOG (DDS_LC_CONFIG, &fact_cmn->gv->logconfig, "tcp de-initialized\n"); + ddsrt_free (fact); } -static enum ddsi_locator_from_string_result ddsi_tcp_address_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str) +static enum ddsi_locator_from_string_result ddsi_tcp_address_from_string (ddsi_tran_factory_t fact, nn_locator_t *loc, const char *str) { - return ddsi_ipaddr_from_string(tran, loc, str, ddsi_tcp_factory_g.m_kind); + return ddsi_ipaddr_from_string(fact, loc, str, fact->m_kind); } static int ddsi_tcp_is_mcaddr (const ddsi_tran_factory_t tran, const nn_locator_t *loc) @@ -1042,64 +1049,63 @@ static int ddsi_tcp_is_ssm_mcaddr (const ddsi_tran_factory_t tran, const nn_loca return 0; } -static enum ddsi_nearby_address_result ddsi_tcp_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, size_t ninterf, const struct nn_interface interf[]) +static enum ddsi_nearby_address_result ddsi_tcp_is_nearby_address (ddsi_tran_factory_t tran, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) { - return ddsi_ipaddr_is_nearby_address(tran, loc, ninterf, interf); + return ddsi_ipaddr_is_nearby_address(tran, loc, ownloc, ninterf, interf); } -int ddsi_tcp_init (void) +int ddsi_tcp_init (struct q_globals *gv) { - if (ddsrt_atomic_inc32_nv (&ddsi_tcp_init_g) == 1) - { - memset (&ddsi_tcp_factory_g, 0, sizeof (ddsi_tcp_factory_g)); - ddsi_tcp_factory_g.m_kind = NN_LOCATOR_KIND_TCPv4; - ddsi_tcp_factory_g.m_typename = "tcp"; - ddsi_tcp_factory_g.m_stream = true; - ddsi_tcp_factory_g.m_connless = false; - ddsi_tcp_factory_g.m_supports_fn = ddsi_tcp_supports; - ddsi_tcp_factory_g.m_create_listener_fn = ddsi_tcp_create_listener; - ddsi_tcp_factory_g.m_create_conn_fn = ddsi_tcp_create_conn; - ddsi_tcp_factory_g.m_release_conn_fn = ddsi_tcp_release_conn; - ddsi_tcp_factory_g.m_close_conn_fn = ddsi_tcp_close_conn; - ddsi_tcp_factory_g.m_unblock_listener_fn = ddsi_tcp_unblock_listener; - ddsi_tcp_factory_g.m_release_listener_fn = ddsi_tcp_release_listener; - ddsi_tcp_factory_g.m_free_fn = ddsi_tcp_release_factory; - ddsi_tcp_factory_g.m_locator_from_string_fn = ddsi_tcp_address_from_string; - ddsi_tcp_factory_g.m_locator_to_string_fn = ddsi_ipaddr_to_string; - ddsi_tcp_factory_g.m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces; - ddsi_tcp_factory_g.m_is_mcaddr_fn = ddsi_tcp_is_mcaddr; - ddsi_tcp_factory_g.m_is_ssm_mcaddr_fn = ddsi_tcp_is_ssm_mcaddr; - ddsi_tcp_factory_g.m_is_nearby_address_fn = ddsi_tcp_is_nearby_address; - ddsi_factory_add (&ddsi_tcp_factory_g); + struct ddsi_tran_factory_tcp *fact = ddsrt_malloc (sizeof (*fact)); + + memset (fact, 0, sizeof (*fact)); + fact->fact.gv = gv; + fact->fact.m_kind = NN_LOCATOR_KIND_TCPv4; + fact->fact.m_typename = "tcp"; + fact->fact.m_stream = true; + fact->fact.m_connless = false; + fact->fact.m_supports_fn = ddsi_tcp_supports; + fact->fact.m_create_listener_fn = ddsi_tcp_create_listener; + fact->fact.m_create_conn_fn = ddsi_tcp_create_conn; + fact->fact.m_release_conn_fn = ddsi_tcp_release_conn; + fact->fact.m_close_conn_fn = ddsi_tcp_close_conn; + fact->fact.m_unblock_listener_fn = ddsi_tcp_unblock_listener; + fact->fact.m_release_listener_fn = ddsi_tcp_release_listener; + fact->fact.m_free_fn = ddsi_tcp_release_factory; + fact->fact.m_locator_from_string_fn = ddsi_tcp_address_from_string; + fact->fact.m_locator_to_string_fn = ddsi_ipaddr_to_string; + fact->fact.m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces; + fact->fact.m_is_mcaddr_fn = ddsi_tcp_is_mcaddr; + fact->fact.m_is_ssm_mcaddr_fn = ddsi_tcp_is_ssm_mcaddr; + fact->fact.m_is_nearby_address_fn = ddsi_tcp_is_nearby_address; + ddsi_factory_add (gv, &fact->fact); #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6) - { - ddsi_tcp_factory_g.m_kind = NN_LOCATOR_KIND_TCPv6; - ddsi_tcp_factory_g.m_typename = "tcp6"; - } + if (gv->config.transport_selector == TRANS_TCP6) + { + fact->fact.m_kind = NN_LOCATOR_KIND_TCPv6; + fact->fact.m_typename = "tcp6"; + } #endif - memset (&ddsi_tcp_conn_client, 0, sizeof (ddsi_tcp_conn_client)); - ddsi_tcp_base_init (&ddsi_tcp_conn_client.m_base); + memset (&fact->ddsi_tcp_conn_client, 0, sizeof (fact->ddsi_tcp_conn_client)); + ddsi_tcp_base_init (fact, &fact->ddsi_tcp_conn_client.m_base); #ifdef DDSI_INCLUDE_SSL - if (config.ssl_enable) + if (gv->config.ssl_enable) + { + ddsi_ssl_config_plugin (&fact->ddsi_tcp_ssl_plugin); + if (! fact->ddsi_tcp_ssl_plugin.init (gv)) { - ddsi_name = "tcp/ssl"; - ddsi_ssl_config_plugin (&ddsi_tcp_ssl_plugin); - if (! ddsi_tcp_ssl_plugin.init ()) - { - DDS_ERROR("Failed to initialize OpenSSL\n"); - return -1; - } + GVERROR ("Failed to initialize OpenSSL\n"); + return -1; } + } #endif - ddsrt_avl_init (&ddsi_tcp_treedef, &ddsi_tcp_cache_g); - ddsrt_mutex_init (&ddsi_tcp_cache_lock_g); + ddsrt_avl_init (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g); + ddsrt_mutex_init (&fact->ddsi_tcp_cache_lock_g); - DDS_LOG(DDS_LC_CONFIG, "%s initialized\n", ddsi_name); - } + GVLOG (DDS_LC_CONFIG, "tcp initialized\n"); return 0; } diff --git a/src/core/ddsi/src/ddsi_threadmon.c b/src/core/ddsi/src/ddsi_threadmon.c index 6098d71..346b0b9 100644 --- a/src/core/ddsi/src/ddsi_threadmon.c +++ b/src/core/ddsi/src/ddsi_threadmon.c @@ -14,6 +14,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" +#include "dds/ddsrt/hopscotch.h" #include "dds/ddsi/ddsi_threadmon.h" #include "dds/ddsi/q_config.h" @@ -21,7 +22,6 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_globals.h" /* for mattr, cattr */ #include "dds/ddsi/q_receive.h" @@ -30,126 +30,183 @@ struct alive_vt { vtime_t vt; }; +struct threadmon_domain { + const struct q_globals *gv; + unsigned n_not_alive; + size_t msgpos; + char msg[2048]; +}; + struct ddsi_threadmon { int keepgoing; struct alive_vt *av_ary; void (*renew_cb) (void *arg); void *renew_arg; + int64_t liveliness_monitoring_interval; + bool noprogress_log_stacktraces; ddsrt_mutex_t lock; ddsrt_cond_t cond; struct thread_state1 *ts; + struct ddsrt_hh *domains; }; +static struct threadmon_domain *find_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) +{ + struct threadmon_domain dummy; + dummy.gv = gv; + return ddsrt_hh_lookup (sl->domains, &dummy); +} + static uint32_t threadmon_thread (struct ddsi_threadmon *sl) { /* Do not check more often than once every 100ms (no particular reason why it has to be 100ms), regardless of the lease settings. Note: can't trust sl->self, may have been scheduled before the assignment. */ - nn_mtime_t next_thread_cputime = { 0 }; nn_mtime_t tlast = { 0 }; bool was_alive = true; - unsigned i; - for (i = 0; i < thread_states.nthreads; i++) + for (uint32_t i = 0; i < thread_states.nthreads; i++) { sl->av_ary[i].alive = true; + sl->av_ary[i].vt = 0; } ddsrt_mutex_lock (&sl->lock); while (sl->keepgoing) { /* Guard against spurious wakeups by checking only when cond_waitfor signals a timeout */ - if (ddsrt_cond_waitfor (&sl->cond, &sl->lock, config.liveliness_monitoring_interval)) + if (ddsrt_cond_waitfor (&sl->cond, &sl->lock, sl->liveliness_monitoring_interval)) continue; - - unsigned n_alive = 0, n_unused = 0; - nn_mtime_t tnow = now_mt (); - - LOG_THREAD_CPUTIME (next_thread_cputime); - - DDS_TRACE("threadmon: tnow %"PRId64":", tnow.v); - /* Check progress only if enough time has passed: there is no guarantee that os_cond_timedwait wont ever return early, and we do want to avoid spurious warnings. */ + nn_mtime_t tnow = now_mt (); if (tnow.v < tlast.v) + continue; + + /* Scan threads to classify them as alive (sleeping or making progress) or dead (stuck in the same + "awake" state), ignoring those used in domains that do not have a liveliness monitoring enabled + (in which case find_domain returns a null pointer). + + A non-awake thread is not really bound to a domain, but it is mostly ignored because it is + considered "alive". An awake one may be switching to another domain immediately after loading + the domain here, but in that case it is making progress -- and so also mostly ignored. (This + is a similar argument to that used for the GC). */ + unsigned n_not_alive = 0; + tlast = tnow; + for (uint32_t i = 0; i < thread_states.nthreads; i++) { - n_alive = thread_states.nthreads; - } - else - { - tlast = tnow; - for (i = 0; i < thread_states.nthreads; i++) + if (thread_states.ts[i].state == THREAD_STATE_ZERO) + continue; + + vtime_t vt = ddsrt_atomic_ld32 (&thread_states.ts[i].vtime); + ddsrt_atomic_fence_ldld (); + struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&thread_states.ts[i].gv); + struct threadmon_domain *tmdom = find_domain (sl, gv); + if (tmdom == NULL) + continue; + + bool alive = vtime_asleep_p (vt) || vtime_asleep_p (sl->av_ary[i].vt) || vtime_gt (vt, sl->av_ary[i].vt); + n_not_alive += (unsigned) !alive; + tmdom->n_not_alive += (unsigned) !alive; + + /* Construct a detailed trace line for domains that have tracing enabled, domains that don't + only get "failed to make progress"/"once again made progress" messages */ + if (tmdom->msgpos < sizeof (tmdom->msg) && (gv->logconfig.c.mask & DDS_LC_TRACE)) { - if (thread_states.ts[i].state == THREAD_STATE_ZERO) - n_unused++; + tmdom->msgpos += + (size_t) snprintf (tmdom->msg + tmdom->msgpos, sizeof (tmdom->msg) - tmdom->msgpos, + " %u(%s):%c:%"PRIx32"->%"PRIx32, i, thread_states.ts[i].name, alive ? 'a' : 'd', sl->av_ary[i].vt, vt); + } + + sl->av_ary[i].vt = vt; + if (sl->av_ary[i].alive != alive) + { + const char *name = thread_states.ts[i].name; + const char *msg; + if (!alive) + msg = "failed to make progress"; else + msg = "once again made progress"; + DDS_CLOG (alive ? DDS_LC_INFO : DDS_LC_WARNING, &gv->logconfig, "thread %s %s\n", name ? name : "(anon)", msg); + sl->av_ary[i].alive = alive; + } + } + + /* Scan all domains: there is only a single log buffer for the thread and we need the newline + to flush the messages if we want to avoid mixing up domains; and we'd still like to dump + stack traces only once if there are stuck threads, even though a deadlock typically involves + multiple threads. */ + struct ddsrt_hh_iter it; + for (struct threadmon_domain *tmdom = ddsrt_hh_iter_first (sl->domains, &it); tmdom != NULL; tmdom = ddsrt_hh_iter_next (&it)) + { + if (tmdom->n_not_alive == 0) + DDS_CTRACE (&tmdom->gv->logconfig, "%s: OK\n", tmdom->msg); + else + { + DDS_CTRACE (&tmdom->gv->logconfig, "%s: FAIL (%u)\n", tmdom->msg, tmdom->n_not_alive); + if (was_alive && tmdom->gv->logconfig.c.mask != 0) { - vtime_t vt = thread_states.ts[i].vtime; - bool alive = vtime_asleep_p (vt) || vtime_asleep_p (sl->av_ary[i].vt) || vtime_gt (vt, sl->av_ary[i].vt); - n_alive += (unsigned) alive; - DDS_TRACE(" %u(%s):%c:%"PRIx32"->%"PRIx32, i, thread_states.ts[i].name, alive ? 'a' : 'd', sl->av_ary[i].vt, vt); - sl->av_ary[i].vt = vt; - if (sl->av_ary[i].alive != alive) - { - const char *name = thread_states.ts[i].name; - const char *msg; - if (!alive) - msg = "failed to make progress"; - else - msg = "once again made progress"; - DDS_INFO("thread %s %s\n", name ? name : "(anon)", msg); - sl->av_ary[i].alive = alive; - } + if (!sl->noprogress_log_stacktraces) + DDS_CLOG (~DDS_LC_FATAL, &tmdom->gv->logconfig, "-- stack traces requested, but traces disabled --\n"); + else + log_stack_traces (&tmdom->gv->logconfig, tmdom->gv); + } + was_alive = false; + } + tmdom->n_not_alive = 0; + tmdom->msgpos = 0; + tmdom->msg[0] = 0; + +#if DDSRT_HAVE_RUSAGE + if (tmdom->gv->logconfig.c.mask & DDS_LC_TIMING) + { + ddsrt_rusage_t u; + if (ddsrt_getrusage (DDSRT_RUSAGE_SELF, &u) == DDS_RETCODE_OK) + { + DDS_CLOG (DDS_LC_TIMING, &tmdom->gv->logconfig, + "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), + (int) (u.stime % DDS_NSECS_IN_SEC), + u.maxrss, u.idrss, u.nvcsw, u.nivcsw); } } +#endif /* DDSRT_HAVE_RUSAGE */ } - if (n_alive + n_unused == thread_states.nthreads) - { - DDS_TRACE(": [%u] OK\n", n_alive); - was_alive = true; - } - else - { - DDS_TRACE(": [%u] FAIL\n", n_alive); - if (was_alive) - log_stack_traces (); - was_alive = false; - } - - 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", - (int) (u.utime / DDS_NSECS_IN_SEC), - (int) (u.utime % DDS_NSECS_IN_SEC), - (int) (u.stime / DDS_NSECS_IN_SEC), - (int) (u.stime % DDS_NSECS_IN_SEC), - u.maxrss, u.idrss, u.nvcsw, u.nivcsw); - } - } - - /* While deaf, we need to make sure the receive thread wakes up - every now and then to try recreating sockets & rejoining multicast - groups */ - if (gv.deaf) - trigger_recv_threads (); + was_alive = (n_not_alive == 0); } ddsrt_mutex_unlock (&sl->lock); return 0; } -struct ddsi_threadmon *ddsi_threadmon_new (void) +static uint32_t threadmon_domain_hash (const void *va) +{ + const struct threadmon_domain *a = va; + const uint32_t u = (uint16_t) ((uintptr_t) a->gv >> 3); + const uint32_t v = u * 0xb4817365; + return v >> 16; +} + +static int threadmon_domain_eq (const void *va, const void *vb) +{ + const struct threadmon_domain *a = va; + const struct threadmon_domain *b = vb; + return a->gv == b->gv; +} + +struct ddsi_threadmon *ddsi_threadmon_new (int64_t liveliness_monitoring_interval, bool noprogress_log_stacktraces) { struct ddsi_threadmon *sl; sl = ddsrt_malloc (sizeof (*sl)); sl->keepgoing = -1; sl->ts = NULL; + sl->liveliness_monitoring_interval = liveliness_monitoring_interval; + sl->noprogress_log_stacktraces = noprogress_log_stacktraces; + sl->domains = ddsrt_hh_new (1, threadmon_domain_hash, threadmon_domain_eq); if ((sl->av_ary = ddsrt_malloc (thread_states.nthreads * sizeof (*sl->av_ary))) == NULL) goto fail_vtimes; @@ -164,26 +221,54 @@ struct ddsi_threadmon *ddsi_threadmon_new (void) return NULL; } -int ddsi_threadmon_start (struct ddsi_threadmon *sl) +dds_return_t ddsi_threadmon_start (struct ddsi_threadmon *sl, const char *name) { ddsrt_mutex_lock (&sl->lock); assert (sl->keepgoing == -1); sl->keepgoing = 1; ddsrt_mutex_unlock (&sl->lock); - if (create_thread (&sl->ts, "lease", (uint32_t (*) (void *)) threadmon_thread, sl) != DDS_RETCODE_OK) + /* FIXME: thread properties */ + if (create_thread_with_properties (&sl->ts, NULL, name, (uint32_t (*) (void *)) threadmon_thread, sl) != DDS_RETCODE_OK) goto fail_thread; return 0; fail_thread: sl->keepgoing = -1; - return Q_ERR_UNSPECIFIED; + return DDS_RETCODE_ERROR; } -void ddsi_threadmon_statechange_barrier (struct ddsi_threadmon *sl) +void ddsi_threadmon_register_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) { - ddsrt_mutex_lock (&sl->lock); - ddsrt_mutex_unlock (&sl->lock); + if (gv->config.liveliness_monitoring) + { + struct threadmon_domain *tmdom = ddsrt_malloc (sizeof (*tmdom)); + tmdom->gv = gv; + tmdom->n_not_alive = 0; + tmdom->msgpos = 0; + tmdom->msg[0] = 0; + + ddsrt_mutex_lock (&sl->lock); + int x = ddsrt_hh_add (sl->domains, tmdom); + assert (x); + (void) x; + ddsrt_mutex_unlock (&sl->lock); + } +} + +void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) +{ + if (gv->config.liveliness_monitoring) + { + ddsrt_mutex_lock (&sl->lock); + struct threadmon_domain dummy; + dummy.gv = gv; + struct threadmon_domain *tmdom = ddsrt_hh_lookup (sl->domains, &dummy); + assert (tmdom); + ddsrt_hh_remove (sl->domains, tmdom); + ddsrt_mutex_unlock (&sl->lock); + ddsrt_free (tmdom); + } } void ddsi_threadmon_stop (struct ddsi_threadmon *sl) @@ -200,9 +285,13 @@ void ddsi_threadmon_stop (struct ddsi_threadmon *sl) void ddsi_threadmon_free (struct ddsi_threadmon *sl) { +#ifndef NDEBUG + struct ddsrt_hh_iter it; + assert (ddsrt_hh_iter_first (sl->domains, &it) == NULL); +#endif ddsrt_cond_destroy (&sl->cond); ddsrt_mutex_destroy (&sl->lock); + ddsrt_hh_free (sl->domains); ddsrt_free (sl->av_ary); ddsrt_free (sl); } - diff --git a/src/core/ddsi/src/ddsi_tkmap.c b/src/core/ddsi/src/ddsi_tkmap.c index 132fd5d..c00d4aa 100644 --- a/src/core/ddsi/src/ddsi_tkmap.c +++ b/src/core/ddsi/src/ddsi_tkmap.c @@ -31,7 +31,8 @@ struct ddsi_tkmap { - struct ddsrt_chh * m_hh; + struct ddsrt_chh *m_hh; + struct q_globals *gv; ddsrt_mutex_t m_lock; ddsrt_cond_t m_cond; }; @@ -42,9 +43,10 @@ static void gc_buckets_impl (struct gcreq *gcreq) gcreq_free (gcreq); } -static void gc_buckets (void *a) +static void gc_buckets (void *a, void *arg) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_buckets_impl); + const struct ddsi_tkmap *tkmap = arg; + struct gcreq *gcreq = gcreq_new (tkmap->gv->gcreq_queue, gc_buckets_impl); gcreq->arg = a; gcreq_enqueue (gcreq); } @@ -57,19 +59,19 @@ static void gc_tkmap_instance_impl (struct gcreq *gcreq) gcreq_free (gcreq); } -static void gc_tkmap_instance (struct ddsi_tkmap_instance *tk) +static void gc_tkmap_instance (struct ddsi_tkmap_instance *tk, struct gcreq_queue *gcreq_queue) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_tkmap_instance_impl); + struct gcreq *gcreq = gcreq_new (gcreq_queue, gc_tkmap_instance_impl); gcreq->arg = tk; gcreq_enqueue (gcreq); } -static uint32_t dds_tk_hash (const struct ddsi_tkmap_instance * inst) +static uint32_t dds_tk_hash (const struct ddsi_tkmap_instance *inst) { return inst->m_sample->hash; } -static uint32_t dds_tk_hash_void (const void * inst) +static uint32_t dds_tk_hash_void (const void *inst) { return dds_tk_hash (inst); } @@ -84,10 +86,11 @@ static int dds_tk_equals_void (const void *a, const void *b) return dds_tk_equals (a, b); } -struct ddsi_tkmap *ddsi_tkmap_new (void) +struct ddsi_tkmap *ddsi_tkmap_new (struct q_globals *gv) { struct ddsi_tkmap *tkmap = dds_alloc (sizeof (*tkmap)); - tkmap->m_hh = ddsrt_chh_new (1, dds_tk_hash_void, dds_tk_equals_void, gc_buckets); + tkmap->m_hh = ddsrt_chh_new (1, dds_tk_hash_void, dds_tk_equals_void, gc_buckets, tkmap); + tkmap->gv = gv; ddsrt_mutex_init (&tkmap->m_lock); ddsrt_cond_init (&tkmap->m_cond); return tkmap; @@ -137,7 +140,7 @@ struct ddsi_tkmap_instance *ddsi_tkmap_find_by_id (struct ddsi_tkmap *map, uint6 return tk; else /* Let key value lookup handle the possible CAS loop and the complicated cases */ - return ddsi_tkmap_find (tk->m_sample, false, false); + return ddsi_tkmap_find (map, tk->m_sample, false); } /* Debug keyhash generation for debug and coverage builds */ @@ -152,15 +155,10 @@ struct ddsi_tkmap_instance *ddsi_tkmap_find_by_id (struct ddsi_tkmap *map, uint6 #define DDS_DEBUG_KEYHASH 1 #endif -struct ddsi_tkmap_instance * -ddsi_tkmap_find( - struct ddsi_serdata * sd, - const bool rd, - const bool create) +struct ddsi_tkmap_instance *ddsi_tkmap_find (struct ddsi_tkmap *map, struct ddsi_serdata *sd, const bool create) { struct ddsi_tkmap_instance dummy; - struct ddsi_tkmap_instance * tk; - struct ddsi_tkmap * map = gv.m_tkmap; + struct ddsi_tkmap_instance *tk; assert (thread_is_awake ()); dummy.m_sample = sd; @@ -200,17 +198,12 @@ retry: goto retry; } } - - if (tk && rd) - { - DDS_TRACE("tk=%p iid=%"PRIx64" ", (void *) tk, tk->m_iid); - } return tk; } -struct ddsi_tkmap_instance * ddsi_tkmap_lookup_instance_ref (struct ddsi_serdata * sd) +struct ddsi_tkmap_instance *ddsi_tkmap_lookup_instance_ref (struct ddsi_tkmap *map, struct ddsi_serdata *sd) { - return ddsi_tkmap_find (sd, true, true); + return ddsi_tkmap_find (map, sd, true); } void ddsi_tkmap_instance_ref (struct ddsi_tkmap_instance *tk) @@ -218,7 +211,7 @@ void ddsi_tkmap_instance_ref (struct ddsi_tkmap_instance *tk) ddsrt_atomic_inc32 (&tk->m_refc); } -void ddsi_tkmap_instance_unref (struct ddsi_tkmap_instance * tk) +void ddsi_tkmap_instance_unref (struct ddsi_tkmap *map, struct ddsi_tkmap_instance *tk) { uint32_t old, new; assert (thread_is_awake ()); @@ -234,8 +227,6 @@ void ddsi_tkmap_instance_unref (struct ddsi_tkmap_instance * tk) } while (!ddsrt_atomic_cas32(&tk->m_refc, old, new)); if (new == REFC_DELETE) { - struct ddsi_tkmap *map = gv.m_tkmap; - /* Remove from hash table */ int removed = ddsrt_chh_remove(map->m_hh, tk); assert (removed); @@ -248,6 +239,6 @@ void ddsi_tkmap_instance_unref (struct ddsi_tkmap_instance * tk) /* Schedule freeing of memory until after all those who may have found a pointer have progressed to where they no longer hold that pointer */ - gc_tkmap_instance(tk); + gc_tkmap_instance(tk, map->gv->gcreq_queue); } } diff --git a/src/core/ddsi/src/ddsi_tran.c b/src/core/ddsi/src/ddsi_tran.c index c1ef648..3094d29 100644 --- a/src/core/ddsi/src/ddsi_tran.c +++ b/src/core/ddsi/src/ddsi_tran.c @@ -21,33 +21,30 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_globals.h" -static ddsi_tran_factory_t ddsi_tran_factories = NULL; - extern inline uint32_t ddsi_conn_type (ddsi_tran_conn_t conn); extern inline uint32_t ddsi_conn_port (ddsi_tran_conn_t conn); extern inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos); -extern inline bool ddsi_factory_supports (ddsi_tran_factory_t factory, int32_t kind); +extern inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind); extern inline ddsrt_socket_t ddsi_conn_handle (ddsi_tran_conn_t conn); extern inline int ddsi_conn_locator (ddsi_tran_conn_t conn, nn_locator_t * loc); extern inline ddsrt_socket_t ddsi_tran_handle (ddsi_tran_base_t base); extern inline ddsi_tran_conn_t ddsi_factory_create_conn (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos); -extern inline int ddsi_tran_locator (ddsi_tran_base_t base, nn_locator_t * loc); extern inline int ddsi_listener_locator (ddsi_tran_listener_t listener, nn_locator_t * loc); extern inline int ddsi_listener_listen (ddsi_tran_listener_t listener); extern inline ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listener); extern inline ssize_t ddsi_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc); extern inline ssize_t ddsi_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const ddsrt_iovec_t *iov, uint32_t flags); -void ddsi_factory_add (ddsi_tran_factory_t factory) +void ddsi_factory_add (struct q_globals *gv, ddsi_tran_factory_t factory) { - factory->m_factory = ddsi_tran_factories; - ddsi_tran_factories = factory; + factory->m_factory = gv->ddsi_tran_factories; + gv->ddsi_tran_factories = factory; } -ddsi_tran_factory_t ddsi_factory_find (const char * type) +ddsi_tran_factory_t ddsi_factory_find (const struct q_globals *gv, const char *type) { /* FIXME: should speed up */ - ddsi_tran_factory_t factory = ddsi_tran_factories; + ddsi_tran_factory_t factory = gv->ddsi_tran_factories; while (factory) { @@ -61,23 +58,23 @@ ddsi_tran_factory_t ddsi_factory_find (const char * type) return factory; } -void ddsi_tran_factories_fini (void) +void ddsi_tran_factories_fini (struct q_globals *gv) { ddsi_tran_factory_t factory; - while ((factory = ddsi_tran_factories) != NULL) + while ((factory = gv->ddsi_tran_factories) != NULL) { /* Keep the factory in the list for the duration of "factory_free" so that conversion of locator kind to factory remains possible. */ ddsi_tran_factory_t next = factory->m_factory; ddsi_factory_free (factory); - ddsi_tran_factories = next; + gv->ddsi_tran_factories = next; } } -static ddsi_tran_factory_t ddsi_factory_find_with_len (const char * type, size_t len) +static ddsi_tran_factory_t ddsi_factory_find_with_len (const struct q_globals *gv, const char *type, size_t len) { /* FIXME: should speed up */ - ddsi_tran_factory_t factory = ddsi_tran_factories; + ddsi_tran_factory_t factory = gv->ddsi_tran_factories; while (factory) { @@ -91,12 +88,13 @@ static ddsi_tran_factory_t ddsi_factory_find_with_len (const char * type, size_t return factory; } -ddsi_tran_factory_t ddsi_factory_find_supported_kind (int32_t kind) +ddsrt_attribute_no_sanitize (("thread")) +ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct q_globals *gv, int32_t kind) { /* FIXME: MUST speed up */ ddsi_tran_factory_t factory; - for (factory = ddsi_tran_factories; factory; factory = factory->m_factory) { - if (factory->m_supports_fn(kind)) { + for (factory = gv->ddsi_tran_factories; factory; factory = factory->m_factory) { + if (factory->m_supports_fn(factory, kind)) { return factory; } } @@ -107,7 +105,7 @@ void ddsi_factory_free (ddsi_tran_factory_t factory) { if (factory && factory->m_free_fn) { - (factory->m_free_fn) (); + (factory->m_free_fn) (factory); } } @@ -121,20 +119,19 @@ void ddsi_conn_free (ddsi_tran_conn_t conn) /* FIXME: rethink the socket waitset & the deleting of entries; the biggest issue is TCP handling that can open & close sockets at will and yet expects the waitset to wake up at the apprioriate times. (This pretty much works with the select-based version, but not the kqueue-based one.) TCP code can also have connections without a socket ... Calling sockWaitsetRemove here (where there shouldn't be any knowledge of it) at least ensures that it is removed in time and that there can't be aliasing of connections and sockets. */ if (ddsi_conn_handle (conn) != DDSRT_INVALID_SOCKET) { - unsigned i; - for (i = 0; i < gv.n_recv_threads; i++) + for (uint32_t i = 0; i < conn->m_base.gv->n_recv_threads; i++) { - if (!gv.recv_threads[i].ts) - assert (!gv.rtps_keepgoing); + if (!conn->m_base.gv->recv_threads[i].ts) + assert (!ddsrt_atomic_ld32 (&conn->m_base.gv->rtps_keepgoing)); else { - switch (gv.recv_threads[i].arg.mode) + switch (conn->m_base.gv->recv_threads[i].arg.mode) { case RTM_MANY: - os_sockWaitsetRemove (gv.recv_threads[i].arg.u.many.ws, conn); + os_sockWaitsetRemove (conn->m_base.gv->recv_threads[i].arg.u.many.ws, conn); break; case RTM_SINGLE: - if (gv.recv_threads[i].arg.u.single.conn == conn) + if (conn->m_base.gv->recv_threads[i].arg.u.single.conn == conn) abort(); break; } @@ -158,19 +155,19 @@ void ddsi_conn_add_ref (ddsi_tran_conn_t conn) ddsrt_atomic_inc32 (&conn->m_count); } -void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn) +void ddsi_factory_conn_init (const struct ddsi_tran_factory *factory, ddsi_tran_conn_t conn) { ddsrt_atomic_st32 (&conn->m_count, 1); conn->m_connless = factory->m_connless; conn->m_stream = factory->m_stream; - conn->m_factory = factory; + conn->m_factory = (struct ddsi_tran_factory *) factory; + conn->m_base.gv = factory->gv; } void ddsi_conn_disable_multiplexing (ddsi_tran_conn_t conn) { - if (conn->m_disable_multiplexing_fn) { + if (conn->m_disable_multiplexing_fn) (conn->m_disable_multiplexing_fn) (conn); - } } bool ddsi_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * loc) @@ -238,27 +235,27 @@ void ddsi_listener_free (ddsi_tran_listener_t listener) } } -int ddsi_is_mcaddr (const nn_locator_t *loc) +int ddsi_is_mcaddr (const struct q_globals *gv, const nn_locator_t *loc) { - ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind (loc->kind); + ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind (gv, loc->kind); return tran ? tran->m_is_mcaddr_fn (tran, loc) : 0; } -int ddsi_is_ssm_mcaddr (const nn_locator_t *loc) +int ddsi_is_ssm_mcaddr (const struct q_globals *gv, const nn_locator_t *loc) { - ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(loc->kind); + ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(gv, loc->kind); if (tran && tran->m_is_ssm_mcaddr_fn != 0) return tran->m_is_ssm_mcaddr_fn (tran, loc); return 0; } -enum ddsi_nearby_address_result ddsi_is_nearby_address (const nn_locator_t *loc, size_t ninterf, const struct nn_interface interf[]) +enum ddsi_nearby_address_result ddsi_is_nearby_address (const struct q_globals *gv, const nn_locator_t *loc, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) { - ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(loc->kind); - return tran ? tran->m_is_nearby_address_fn (tran, loc, ninterf, interf) : DNAR_DISTANT; + ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(gv, loc->kind); + return tran ? tran->m_is_nearby_address_fn (tran, loc, ownloc, ninterf, interf) : DNAR_DISTANT; } -enum ddsi_locator_from_string_result ddsi_locator_from_string (nn_locator_t *loc, const char *str) +enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct q_globals *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory) { const char *sep = strchr(str, '/'); ddsi_tran_factory_t tran; @@ -269,21 +266,21 @@ enum ddsi_locator_from_string_result ddsi_locator_from_string (nn_locator_t *loc while (cur-- > str) if (!isalnum((unsigned char)*cur) && *cur != '_') return AFSR_INVALID; - tran = ddsi_factory_find_with_len(str, (size_t)(sep - str)); + tran = ddsi_factory_find_with_len(gv, str, (size_t)(sep - str)); if (tran == NULL) return AFSR_UNKNOWN; } else { /* FIXME: am I happy with defaulting it like this? */ - tran = gv.m_factory; + tran = default_factory; } return tran->m_locator_from_string_fn (tran, loc, sep ? sep + 1 : str); } -char *ddsi_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc) +char *ddsi_locator_to_string (const struct q_globals *gv, char *dst, size_t sizeof_dst, const nn_locator_t *loc) { /* FIXME: should add a "factory" for INVALID locators */ if (loc->kind != NN_LOCATOR_KIND_INVALID) { - ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(loc->kind); + ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(gv, loc->kind); int pos = snprintf (dst, sizeof_dst, "%s/", tran->m_typename); if (0 < pos && (size_t)pos < sizeof_dst) (void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 1); @@ -293,10 +290,10 @@ char *ddsi_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t * return dst; } -char *ddsi_locator_to_string_no_port (char *dst, size_t sizeof_dst, const nn_locator_t *loc) +char *ddsi_locator_to_string_no_port (const struct q_globals *gv, char *dst, size_t sizeof_dst, const nn_locator_t *loc) { if (loc->kind != NN_LOCATOR_KIND_INVALID) { - ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(loc->kind); + ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(gv, loc->kind); int pos = snprintf (dst, sizeof_dst, "%s/", tran->m_typename); if (0 < pos && (size_t)pos < sizeof_dst) (void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 0); @@ -306,7 +303,7 @@ char *ddsi_locator_to_string_no_port (char *dst, size_t sizeof_dst, const nn_loc return dst; } -int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, ddsrt_ifaddrs_t **interfs) +int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, enum transport_selector transport_selector, ddsrt_ifaddrs_t **interfs) { - return factory->m_enumerate_interfaces_fn (factory, interfs); + return factory->m_enumerate_interfaces_fn (factory, transport_selector, interfs); } diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 53135f1..3d0a93d 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -27,34 +27,18 @@ #include "dds/ddsi/q_pcap.h" #include "dds/ddsi/q_globals.h" -extern void ddsi_factory_conn_init (ddsi_tran_factory_t factory, ddsi_tran_conn_t conn); - -typedef struct ddsi_tran_factory * ddsi_udp_factory_t; - -typedef struct ddsi_udp_config -{ - struct nn_group_membership *mship; -} -* ddsi_udp_config_t; - -typedef struct ddsi_udp_conn -{ +typedef struct ddsi_udp_conn { struct ddsi_tran_conn m_base; ddsrt_socket_t m_sock; #if defined _WIN32 WSAEVENT m_sockEvent; #endif int m_diffserv; -} -* ddsi_udp_conn_t; - -static struct ddsi_udp_config ddsi_udp_config_g; -static struct ddsi_tran_factory ddsi_udp_factory_g; -static ddsrt_atomic_uint32_t ddsi_udp_init_g = DDSRT_ATOMIC_UINT32_INIT(0); +} *ddsi_udp_conn_t; static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, size_t len, bool allow_spurious, nn_locator_t *srcloc) { - dds_retcode_t rc; + dds_return_t rc; ssize_t ret = 0; ddsrt_msghdr_t msghdr; struct sockaddr_storage src; @@ -86,6 +70,15 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s if (srcloc) ddsi_ipaddr_to_loc(srcloc, (struct sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6); + if(conn->m_base.gv->pcap_fp) + { + struct sockaddr_storage dest; + socklen_t dest_len = sizeof (dest); + if (ddsrt_getsockname (((ddsi_udp_conn_t) conn)->m_sock, (struct sockaddr *) &dest, &dest_len) != DDS_RETCODE_OK) + memset(&dest, 0, sizeof(dest)); + write_pcap_received(conn->m_base.gv, now(), &src, &dest, buf, (size_t) ret); + } + /* Check for udp packet truncation */ if ((((size_t) ret) > len) #if DDSRT_MSGHDR_FLAGS @@ -96,14 +89,14 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s char addrbuf[DDSI_LOCSTRLEN]; nn_locator_t tmp; ddsi_ipaddr_to_loc(&tmp, (struct sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6); - ddsi_locator_to_string(addrbuf, sizeof(addrbuf), &tmp); - DDS_WARNING("%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); + ddsi_locator_to_string(conn->m_base.gv, addrbuf, sizeof(addrbuf), &tmp); + DDS_CWARNING(&conn->m_base.gv->logconfig, "%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); } } else if (rc != DDS_RETCODE_BAD_PARAMETER && rc != DDS_RETCODE_NO_CONNECTION) { - DDS_ERROR("UDP recvmsg sock %d: ret %d retcode %"PRId32"\n", (int) ((ddsi_udp_conn_t) conn)->m_sock, (int) ret, rc); + DDS_CERROR(&conn->m_base.gv->logconfig, "UDP recvmsg sock %d: ret %d retcode %"PRId32"\n", (int) ((ddsi_udp_conn_t) conn)->m_sock, (int) ret, rc); ret = -1; } return ret; @@ -117,7 +110,7 @@ static void set_msghdr_iov (ddsrt_msghdr_t *mhdr, ddsrt_iovec_t *iov, size_t iov static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, const ddsrt_iovec_t *iov, uint32_t flags) { - dds_retcode_t rc; + dds_return_t rc; ssize_t ret = -1; unsigned retry = 2; int sendflags = 0; @@ -140,7 +133,7 @@ static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *d #else DDSRT_UNUSED_ARG(flags); #endif -#ifdef MSG_NOSIGNAL +#if MSG_NOSIGNAL && !LWIP_SOCKET sendflags |= MSG_NOSIGNAL; #endif do { @@ -156,19 +149,19 @@ static ssize_t ddsi_udp_conn_write (ddsi_tran_conn_t conn, const nn_locator_t *d } while ((rc == DDS_RETCODE_INTERRUPTED) || (rc == DDS_RETCODE_TRY_AGAIN) || (rc == DDS_RETCODE_NOT_ALLOWED && retry-- > 0)); - if (ret > 0 && gv.pcap_fp) + if (ret > 0 && conn->m_base.gv->pcap_fp) { struct sockaddr_storage sa; socklen_t alen = sizeof (sa); if (ddsrt_getsockname (((ddsi_udp_conn_t) conn)->m_sock, (struct sockaddr *) &sa, &alen) != DDS_RETCODE_OK) memset(&sa, 0, sizeof(sa)); - write_pcap_sent (gv.pcap_fp, now (), &sa, &msg, (size_t) ret); + write_pcap_sent (conn->m_base.gv, now (), &sa, &msg, (size_t) ret); } else if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_NOT_ALLOWED && rc != DDS_RETCODE_NO_CONNECTION) { - DDS_ERROR("ddsi_udp_conn_write failed with retcode %"PRId32"\n", rc); + DDS_CERROR(&conn->m_base.gv->logconfig, "ddsi_udp_conn_write failed with retcode %"PRId32"\n", rc); } return (rc == DDS_RETCODE_OK ? ret : -1); } @@ -190,48 +183,42 @@ static ddsrt_socket_t ddsi_udp_conn_handle (ddsi_tran_base_t base) return ((ddsi_udp_conn_t) base)->m_sock; } -static bool ddsi_udp_supports (int32_t kind) +static bool ddsi_udp_supports (const struct ddsi_tran_factory *fact, int32_t kind) { - return - kind == ddsi_udp_factory_g.m_kind || - (kind == NN_LOCATOR_KIND_UDPv4MCGEN && ddsi_udp_factory_g.m_kind == NN_LOCATOR_KIND_UDPv4); + return kind == fact->m_kind || (kind == NN_LOCATOR_KIND_UDPv4MCGEN && fact->m_kind == NN_LOCATOR_KIND_UDPv4); } -static int ddsi_udp_conn_locator (ddsi_tran_base_t base, nn_locator_t *loc) +static int ddsi_udp_conn_locator (ddsi_tran_factory_t fact, ddsi_tran_base_t base, nn_locator_t *loc) { int ret = -1; ddsi_udp_conn_t uc = (ddsi_udp_conn_t) base; if (uc->m_sock != DDSRT_INVALID_SOCKET) { - loc->kind = ddsi_udp_factory_g.m_kind; + loc->kind = fact->m_kind; loc->port = uc->m_base.m_base.m_port; - memcpy(loc->address, gv.extloc.address, sizeof (loc->address)); + memcpy(loc->address, uc->m_base.m_base.gv->extloc.address, sizeof (loc->address)); ret = 0; } return ret; } -static unsigned short get_socket_port (ddsrt_socket_t socket) +static unsigned short get_socket_port (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket) { - dds_retcode_t ret; + dds_return_t ret; struct sockaddr_storage addr; socklen_t addrlen = sizeof (addr); ret = ddsrt_getsockname (socket, (struct sockaddr *)&addr, &addrlen); if (ret != DDS_RETCODE_OK) { - DDS_ERROR("ddsi_udp_get_socket_port: getsockname returned %"PRId32"\n", ret); + DDS_CERROR (logcfg, "ddsi_udp_get_socket_port: getsockname returned %"PRId32"\n", ret); return 0; } return ddsrt_sockaddr_get_port((struct sockaddr *)&addr); } -static ddsi_tran_conn_t ddsi_udp_create_conn -( - uint32_t port, - ddsi_tran_qos_t qos -) +static ddsi_tran_conn_t ddsi_udp_create_conn (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t qos) { int ret; ddsrt_socket_t sock; @@ -240,13 +227,7 @@ static ddsi_tran_conn_t ddsi_udp_create_conn /* If port is zero, need to create dynamic port */ - ret = make_socket - ( - &sock, - (unsigned short) port, - false, - mcast - ); + ret = make_socket (&sock, (unsigned short) port, false, mcast, fact->gv); if (ret == 0) { @@ -260,44 +241,37 @@ static ddsi_tran_conn_t ddsi_udp_create_conn WSAEventSelect(uc->m_sock, uc->m_sockEvent, FD_WRITE); #endif - ddsi_factory_conn_init (&ddsi_udp_factory_g, &uc->m_base); - uc->m_base.m_base.m_port = get_socket_port (sock); + ddsi_factory_conn_init (fact, &uc->m_base); + uc->m_base.m_base.m_port = get_socket_port (&fact->gv->logconfig, sock); uc->m_base.m_base.m_trantype = DDSI_TRAN_CONN; uc->m_base.m_base.m_multicast = mcast; uc->m_base.m_base.m_handle_fn = ddsi_udp_conn_handle; - uc->m_base.m_base.m_locator_fn = ddsi_udp_conn_locator; uc->m_base.m_read_fn = ddsi_udp_conn_read; uc->m_base.m_write_fn = ddsi_udp_conn_write; uc->m_base.m_disable_multiplexing_fn = ddsi_udp_disable_multiplexing; + uc->m_base.m_locator_fn = ddsi_udp_conn_locator; - DDS_TRACE - ( - "ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", - mcast ? "multicast" : "unicast", - uc->m_sock, - uc->m_base.m_base.m_port - ); + DDS_CTRACE (&fact->gv->logconfig, + "ddsi_udp_create_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", + mcast ? "multicast" : "unicast", + uc->m_sock, + uc->m_base.m_base.m_port); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - if ((uc->m_diffserv != 0) && (ddsi_udp_factory_g.m_kind == NN_LOCATOR_KIND_UDPv4)) + if ((uc->m_diffserv != 0) && (fact->m_kind == NN_LOCATOR_KIND_UDPv4)) { - dds_retcode_t rc; + dds_return_t rc; rc = ddsrt_setsockopt(sock, IPPROTO_IP, IP_TOS, (char *)&uc->m_diffserv, sizeof(uc->m_diffserv)); if (rc != DDS_RETCODE_OK) - DDS_ERROR("ddsi_udp_create_conn: set diffserv retcode %"PRId32"\n", rc); + DDS_CERROR (fact->gv->logconfig, "ddsi_udp_create_conn: set diffserv retcode %"PRId32"\n", rc); } #endif } else { - if (config.participantIndex != PARTICIPANT_INDEX_AUTO) + if (fact->gv->config.participantIndex != PARTICIPANT_INDEX_AUTO) { - DDS_ERROR - ( - "UDP make_socket failed for %s port %"PRIu32"\n", - mcast ? "multicast" : "unicast", - port - ); + DDS_CERROR (&fact->gv->logconfig, "UDP make_socket failed for %s port %"PRIu32"\n", mcast ? "multicast" : "unicast", port); } } @@ -306,11 +280,11 @@ static ddsi_tran_conn_t ddsi_udp_create_conn static int joinleave_asm_mcgroup (ddsrt_socket_t socket, int join, const nn_locator_t *mcloc, const struct nn_interface *interf) { - dds_retcode_t rc; + dds_return_t rc; struct sockaddr_storage mcip; ddsi_ipaddr_from_loc(&mcip, mcloc); #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_UDP6) + if (mcloc->kind == NN_LOCATOR_KIND_UDPv6) { struct ipv6_mreq ipv6mreq; memset (&ipv6mreq, 0, sizeof (ipv6mreq)); @@ -335,12 +309,12 @@ static int joinleave_asm_mcgroup (ddsrt_socket_t socket, int join, const nn_loca #ifdef DDSI_INCLUDE_SSM static int joinleave_ssm_mcgroup (ddsrt_socket_t socket, int join, const nn_locator_t *srcloc, const nn_locator_t *mcloc, const struct nn_interface *interf) { - dds_retcode_t rc; + dds_return_t rc; struct sockaddr_storage mcip, srcip; ddsi_ipaddr_from_loc(&mcip, mcloc); ddsi_ipaddr_from_loc(&srcip, srcloc); #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_UDP6) + if (mcloc->kind == NN_LOCATOR_KIND_UDPv6) { struct group_source_req gsr; memset (&gsr, 0, sizeof (gsr)); @@ -393,13 +367,11 @@ static int ddsi_udp_leave_mc (ddsi_tran_conn_t conn, const nn_locator_t *srcloc, static void ddsi_udp_release_conn (ddsi_tran_conn_t conn) { ddsi_udp_conn_t uc = (ddsi_udp_conn_t) conn; - DDS_TRACE - ( - "ddsi_udp_release_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", - conn->m_base.m_multicast ? "multicast" : "unicast", - uc->m_sock, - uc->m_base.m_base.m_port - ); + DDS_CTRACE (&conn->m_base.gv->logconfig, + "ddsi_udp_release_conn %s socket %"PRIdSOCK" port %"PRIu32"\n", + conn->m_base.m_multicast ? "multicast" : "unicast", + uc->m_sock, + uc->m_base.m_base.m_port); ddsrt_close (uc->m_sock); #if defined _WIN32 && !defined WINCE WSACloseEvent(uc->m_sockEvent); @@ -407,15 +379,6 @@ static void ddsi_udp_release_conn (ddsi_tran_conn_t conn) ddsrt_free (conn); } -void ddsi_udp_fini (void) -{ - if(ddsrt_atomic_dec32_nv (&ddsi_udp_init_g) == 0) { - free_group_membership(ddsi_udp_config_g.mship); - memset (&ddsi_udp_factory_g, 0, sizeof (ddsi_udp_factory_g)); - DDS_LOG(DDS_LC_CONFIG, "udp finalized\n"); - } -} - static int ddsi_udp_is_mcaddr (const ddsi_tran_factory_t tran, const nn_locator_t *loc) { (void) tran; @@ -466,7 +429,7 @@ static int ddsi_udp_is_ssm_mcaddr (const ddsi_tran_factory_t tran, const nn_loca static enum ddsi_locator_from_string_result ddsi_udp_address_from_string (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str) { - return ddsi_ipaddr_from_string(tran, loc, str, ddsi_udp_factory_g.m_kind); + return ddsi_ipaddr_from_string (tran, loc, str, tran->m_kind); } static char *ddsi_udp_locator_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) @@ -497,57 +460,45 @@ static char *ddsi_udp_locator_to_string (ddsi_tran_factory_t tran, char *dst, si } } -static void ddsi_udp_deinit(void) +static void ddsi_udp_fini (ddsi_tran_factory_t fact) { - if (ddsrt_atomic_dec32_nv(&ddsi_udp_init_g) == 0) { - if (ddsi_udp_config_g.mship) - free_group_membership(ddsi_udp_config_g.mship); - DDS_LOG(DDS_LC_CONFIG, "udp de-initialized\n"); - } + DDS_CLOG (DDS_LC_CONFIG, &fact->gv->logconfig, "udp finalized\n"); + ddsrt_free (fact); } -int ddsi_udp_init (void) +int ddsi_udp_init (struct q_globals *gv) { - /* TODO: proper init_once. Either the call doesn't need it, in which case - * this can be removed. Or the call does, in which case it should be done right. - * The lack of locking suggests it isn't needed. - */ - if (ddsrt_atomic_inc32_nv (&ddsi_udp_init_g) == 1) - { - memset (&ddsi_udp_factory_g, 0, sizeof (ddsi_udp_factory_g)); - ddsi_udp_factory_g.m_free_fn = ddsi_udp_deinit; - ddsi_udp_factory_g.m_kind = NN_LOCATOR_KIND_UDPv4; - ddsi_udp_factory_g.m_typename = "udp"; - ddsi_udp_factory_g.m_default_spdp_address = "udp/239.255.0.1"; - ddsi_udp_factory_g.m_connless = true; - ddsi_udp_factory_g.m_supports_fn = ddsi_udp_supports; - ddsi_udp_factory_g.m_create_conn_fn = ddsi_udp_create_conn; - ddsi_udp_factory_g.m_release_conn_fn = ddsi_udp_release_conn; - ddsi_udp_factory_g.m_free_fn = ddsi_udp_fini; - ddsi_udp_factory_g.m_join_mc_fn = ddsi_udp_join_mc; - ddsi_udp_factory_g.m_leave_mc_fn = ddsi_udp_leave_mc; - ddsi_udp_factory_g.m_is_mcaddr_fn = ddsi_udp_is_mcaddr; + struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact)); + memset (fact, 0, sizeof (*fact)); + fact->gv = gv; + fact->m_free_fn = ddsi_udp_fini; + fact->m_kind = NN_LOCATOR_KIND_UDPv4; + fact->m_typename = "udp"; + fact->m_default_spdp_address = "udp/239.255.0.1"; + fact->m_connless = true; + fact->m_supports_fn = ddsi_udp_supports; + fact->m_create_conn_fn = ddsi_udp_create_conn; + fact->m_release_conn_fn = ddsi_udp_release_conn; + fact->m_join_mc_fn = ddsi_udp_join_mc; + fact->m_leave_mc_fn = ddsi_udp_leave_mc; + fact->m_is_mcaddr_fn = ddsi_udp_is_mcaddr; #ifdef DDSI_INCLUDE_SSM - ddsi_udp_factory_g.m_is_ssm_mcaddr_fn = ddsi_udp_is_ssm_mcaddr; + fact->m_is_ssm_mcaddr_fn = ddsi_udp_is_ssm_mcaddr; #endif - ddsi_udp_factory_g.m_is_nearby_address_fn = ddsi_ipaddr_is_nearby_address; - ddsi_udp_factory_g.m_locator_from_string_fn = ddsi_udp_address_from_string; - ddsi_udp_factory_g.m_locator_to_string_fn = ddsi_udp_locator_to_string; - ddsi_udp_factory_g.m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces; + fact->m_is_nearby_address_fn = ddsi_ipaddr_is_nearby_address; + fact->m_locator_from_string_fn = ddsi_udp_address_from_string; + fact->m_locator_to_string_fn = ddsi_udp_locator_to_string; + fact->m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces; #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_UDP6) - { - ddsi_udp_factory_g.m_kind = NN_LOCATOR_KIND_UDPv6; - ddsi_udp_factory_g.m_typename = "udp6"; - ddsi_udp_factory_g.m_default_spdp_address = "udp6/ff02::ffff:239.255.0.1"; - } + if (gv->config.transport_selector == TRANS_UDP6) + { + fact->m_kind = NN_LOCATOR_KIND_UDPv6; + fact->m_typename = "udp6"; + fact->m_default_spdp_address = "udp6/ff02::ffff:239.255.0.1"; + } #endif - ddsi_udp_config_g.mship = new_group_membership(); - - ddsi_factory_add (&ddsi_udp_factory_g); - - DDS_LOG(DDS_LC_CONFIG, "udp initialized\n"); - } + ddsi_factory_add (gv, fact); + GVLOG (DDS_LC_CONFIG, "udp initialized\n"); return 0; } diff --git a/src/core/ddsi/src/ddsi_vendor.c b/src/core/ddsi/src/ddsi_vendor.c index 2fea95b..6d1dfaf 100644 --- a/src/core/ddsi/src/ddsi_vendor.c +++ b/src/core/ddsi/src/ddsi_vendor.c @@ -16,6 +16,7 @@ extern inline bool vendor_equals (nn_vendorid_t a, nn_vendorid_t b); extern inline bool vendor_is_rti (nn_vendorid_t vendor); extern inline bool vendor_is_twinoaks (nn_vendorid_t vendor); +extern inline bool vendor_is_eprosima (nn_vendorid_t vendor); extern inline bool vendor_is_prismtech (nn_vendorid_t vendor); extern inline bool vendor_is_opensplice (nn_vendorid_t vendor); extern inline bool vendor_is_cloud (nn_vendorid_t vendor); diff --git a/src/core/ddsi/src/q_addrset.c b/src/core/ddsi/src/q_addrset.c index f8694d8..b04f064 100644 --- a/src/core/ddsi/src/q_addrset.c +++ b/src/core/ddsi/src/q_addrset.c @@ -18,11 +18,13 @@ #include "dds/ddsrt/string.h" #include "dds/ddsrt/misc.h" #include "dds/ddsrt/avl.h" +#include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_globals.h" /* gv.mattr */ +#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */ /* So what does one do with const & mutexes? I need to take lock in a pure function just in case some other thread is trying to change @@ -42,35 +44,35 @@ static int compare_locators_vwrap (const void *va, const void *vb); static const ddsrt_avl_ctreedef_t addrset_treedef = DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct addrset_node, avlnode), offsetof (struct addrset_node, loc), compare_locators_vwrap, 0); -static int add_addresses_to_addrset_1 (struct addrset *as, const char *ip, int port_mode, const char *msgtag, int req_mc, int mcgen_base, int mcgen_count, int mcgen_idx) +static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrset *as, const char *ip, int port_mode, const char *msgtag, int req_mc, int mcgen_base, int mcgen_count, int mcgen_idx) { char buf[DDSI_LOCSTRLEN]; nn_locator_t loc; - switch (ddsi_locator_from_string(&loc, ip)) + switch (ddsi_locator_from_string(gv, &loc, ip, gv->m_factory)) { case AFSR_OK: break; case AFSR_INVALID: - DDS_ERROR("%s: %s: not a valid address\n", msgtag, ip); + GVERROR ("%s: %s: not a valid address\n", msgtag, ip); return -1; case AFSR_UNKNOWN: - DDS_ERROR("%s: %s: unknown address\n", msgtag, ip); + GVERROR ("%s: %s: unknown address\n", msgtag, ip); return -1; case AFSR_MISMATCH: - DDS_ERROR("%s: %s: address family mismatch\n", msgtag, ip); + GVERROR ("%s: %s: address family mismatch\n", msgtag, ip); return -1; } - if (req_mc && !ddsi_is_mcaddr (&loc)) + if (req_mc && !ddsi_is_mcaddr (gv, &loc)) { - DDS_ERROR ("%s: %s: not a multicast address\n", msgtag, ip); + GVERROR ("%s: %s: not a multicast address\n", msgtag, ip); return -1; } if (mcgen_base == -1 && mcgen_count == -1 && mcgen_idx == -1) ; - else if (loc.kind == NN_LOCATOR_KIND_UDPv4 && ddsi_is_mcaddr(&loc) && mcgen_base >= 0 && mcgen_count > 0 && mcgen_base + mcgen_count < 28 && mcgen_idx >= 0 && mcgen_idx < mcgen_count) + else if (loc.kind == NN_LOCATOR_KIND_UDPv4 && ddsi_is_mcaddr(gv, &loc) && mcgen_base >= 0 && mcgen_count > 0 && mcgen_base + mcgen_count < 28 && mcgen_idx >= 0 && mcgen_idx < mcgen_count) { nn_udpv4mcgen_address_t x; memset(&x, 0, sizeof(x)); @@ -84,55 +86,57 @@ static int add_addresses_to_addrset_1 (struct addrset *as, const char *ip, int p } else { - DDS_ERROR("%s: %s,%d,%d,%d: IPv4 multicast address generator invalid or out of place\n", - msgtag, ip, mcgen_base, mcgen_count, mcgen_idx); + GVERROR ("%s: %s,%d,%d,%d: IPv4 multicast address generator invalid or out of place\n", + msgtag, ip, mcgen_base, mcgen_count, mcgen_idx); return -1; } if (port_mode >= 0) { loc.port = (unsigned) port_mode; - DDS_LOG(DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string(buf, sizeof(buf), &loc)); - add_to_addrset (as, &loc); + GVLOG (DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); + add_to_addrset (gv, as, &loc); } else { - DDS_LOG(DDS_LC_CONFIG, "%s: add ", msgtag); - if (!ddsi_is_mcaddr (&loc)) + GVLOG (DDS_LC_CONFIG, "%s: add ", msgtag); + if (!ddsi_is_mcaddr (gv, &loc)) { - int i; - for (i = 0; i <= config.maxAutoParticipantIndex; i++) + assert (gv->config.maxAutoParticipantIndex >= 0); + for (uint32_t i = 0; i <= (uint32_t) gv->config.maxAutoParticipantIndex; i++) { - int port = config.port_base + config.port_dg * config.domainId.value + i * config.port_pg + config.port_d1; + uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + i * gv->config.port_pg + gv->config.port_d1; loc.port = (unsigned) port; if (i == 0) - DDS_LOG(DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); else - DDS_LOG(DDS_LC_CONFIG, ", :%d", port); - add_to_addrset (as, &loc); + GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, port); + add_to_addrset (gv, as, &loc); } } else { - int port = port_mode; - if (port == -1) - port = config.port_base + config.port_dg * config.domainId.value + config.port_d0; + uint32_t port; + if (port_mode == -1) + port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0; + else + port = (uint32_t) port_mode; loc.port = (unsigned) port; - DDS_LOG(DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc)); - add_to_addrset (as, &loc); + GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); + add_to_addrset (gv, as, &loc); } } - DDS_LOG(DDS_LC_CONFIG, "\n"); + GVLOG (DDS_LC_CONFIG, "\n"); return 0; } -DDSRT_WARNING_MSVC_OFF(4996); -int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc) +int add_addresses_to_addrset (const struct q_globals *gv, struct addrset *as, const char *addrs, int port_mode, const char *msgtag, int req_mc) { /* port_mode: -1 => take from string, if 0 & unicast, add for a range of participant indices; port_mode >= 0 => always set port to port_mode */ + DDSRT_WARNING_MSVC_OFF(4996); char *addrs_copy, *ip, *cursor, *a; int retval = -1; addrs_copy = ddsrt_strdup (addrs); @@ -142,7 +146,7 @@ int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mo { int port = 0, pos; int mcgen_base = -1, mcgen_count = -1, mcgen_idx = -1; - if (config.transport_selector == TRANS_UDP || config.transport_selector == TRANS_TCP) + if (gv->config.transport_selector == TRANS_UDP || gv->config.transport_selector == TRANS_TCP) { if (port_mode == -1 && sscanf (a, "%[^:]:%d%n", ip, &port, &pos) == 2 && a[pos] == 0) ; /* XYZ:PORT */ @@ -168,10 +172,10 @@ int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mo } if ((port > 0 && port <= 65535) || (port_mode == -1 && port == -1)) { - if (add_addresses_to_addrset_1 (as, ip, port, msgtag, req_mc, mcgen_base, mcgen_count, mcgen_idx) < 0) + if (add_addresses_to_addrset_1 (gv, as, ip, port, msgtag, req_mc, mcgen_base, mcgen_count, mcgen_idx) < 0) goto error; } else { - DDS_ERROR("%s: %s: port %d invalid\n", msgtag, a, port); + GVERROR ("%s: %s: port %d invalid\n", msgtag, a, port); } } retval = 0; @@ -179,8 +183,8 @@ int add_addresses_to_addrset (struct addrset *as, const char *addrs, int port_mo ddsrt_free (ip); ddsrt_free (addrs_copy); return retval; + DDSRT_WARNING_MSVC_ON(4996); } -DDSRT_WARNING_MSVC_ON(4996); int compare_locators (const nn_locator_t *a, const nn_locator_t *b) { @@ -244,14 +248,14 @@ int is_unspec_locator (const nn_locator_t *loc) } #ifdef DDSI_INCLUDE_SSM -int addrset_contains_ssm (const struct addrset *as) +int addrset_contains_ssm (const struct q_globals *gv, const struct addrset *as) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (as); for (n = ddsrt_avl_citer_first (&addrset_treedef, &as->mcaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) { - if (ddsi_is_ssm_mcaddr (&n->loc)) + if (ddsi_is_ssm_mcaddr (gv, &n->loc)) { UNLOCK (as); return 1; @@ -261,14 +265,14 @@ int addrset_contains_ssm (const struct addrset *as) return 0; } -int addrset_any_ssm (const struct addrset *as, nn_locator_t *dst) +int addrset_any_ssm (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (as); for (n = ddsrt_avl_citer_first (&addrset_treedef, &as->mcaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) { - if (ddsi_is_ssm_mcaddr (&n->loc)) + if (ddsi_is_ssm_mcaddr (gv, &n->loc)) { *dst = n->loc; UNLOCK (as); @@ -279,14 +283,14 @@ int addrset_any_ssm (const struct addrset *as, nn_locator_t *dst) return 0; } -int addrset_any_non_ssm_mc (const struct addrset *as, nn_locator_t *dst) +int addrset_any_non_ssm_mc (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (as); for (n = ddsrt_avl_citer_first (&addrset_treedef, &as->mcaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) { - if (!ddsi_is_ssm_mcaddr (&n->loc)) + if (!ddsi_is_ssm_mcaddr (gv, &n->loc)) { *dst = n->loc; UNLOCK (as); @@ -307,12 +311,12 @@ int addrset_purge (struct addrset *as) return 0; } -void add_to_addrset (struct addrset *as, const nn_locator_t *loc) +void add_to_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc) { if (!is_unspec_locator (loc)) { ddsrt_avl_ipath_t path; - ddsrt_avl_ctree_t *tree = ddsi_is_mcaddr (loc) ? &as->mcaddrs : &as->ucaddrs; + ddsrt_avl_ctree_t *tree = ddsi_is_mcaddr (gv, loc) ? &as->mcaddrs : &as->ucaddrs; LOCK (as); if (ddsrt_avl_clookup_ipath (&addrset_treedef, tree, loc, &path) == NULL) { @@ -324,10 +328,10 @@ void add_to_addrset (struct addrset *as, const nn_locator_t *loc) } } -void remove_from_addrset (struct addrset *as, const nn_locator_t *loc) +void remove_from_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc) { ddsrt_avl_dpath_t path; - ddsrt_avl_ctree_t *tree = ddsi_is_mcaddr (loc) ? &as->mcaddrs : &as->ucaddrs; + ddsrt_avl_ctree_t *tree = ddsi_is_mcaddr (gv, loc) ? &as->mcaddrs : &as->ucaddrs; struct addrset_node *n; LOCK (as); if ((n = ddsrt_avl_clookup_dpath (&addrset_treedef, tree, loc, &path)) != NULL) @@ -338,69 +342,51 @@ void remove_from_addrset (struct addrset *as, const nn_locator_t *loc) UNLOCK (as); } -void copy_addrset_into_addrset_uc (struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_uc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (asadd); for (n = ddsrt_avl_citer_first (&addrset_treedef, &asadd->ucaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) - add_to_addrset (as, &n->loc); + add_to_addrset (gv, as, &n->loc); UNLOCK (asadd); } -void copy_addrset_into_addrset_mc (struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_mc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (asadd); for (n = ddsrt_avl_citer_first (&addrset_treedef, &asadd->mcaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) - add_to_addrset (as, &n->loc); + add_to_addrset (gv, as, &n->loc); UNLOCK (asadd); } -void copy_addrset_into_addrset (struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) { - copy_addrset_into_addrset_uc (as, asadd); - copy_addrset_into_addrset_mc (as, asadd); + copy_addrset_into_addrset_uc (gv, as, asadd); + copy_addrset_into_addrset_mc (gv, as, asadd); } #ifdef DDSI_INCLUDE_SSM -void copy_addrset_into_addrset_no_ssm_mc (struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_no_ssm_mc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; LOCK (asadd); for (n = ddsrt_avl_citer_first (&addrset_treedef, &asadd->mcaddrs, &it); n; n = ddsrt_avl_citer_next (&it)) { - if (!ddsi_is_ssm_mcaddr (&n->loc)) - add_to_addrset (as, &n->loc); + if (!ddsi_is_ssm_mcaddr (gv, &n->loc)) + add_to_addrset (gv, as, &n->loc); } UNLOCK (asadd); } -void copy_addrset_into_addrset_no_ssm (struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_no_ssm (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) { - copy_addrset_into_addrset_uc (as, asadd); - copy_addrset_into_addrset_no_ssm_mc (as, asadd); -} - -void addrset_purge_ssm (struct addrset *as) -{ - struct addrset_node *n; - LOCK (as); - n = ddsrt_avl_cfind_min (&addrset_treedef, &as->mcaddrs); - while (n) - { - struct addrset_node *n1 = n; - n = ddsrt_avl_cfind_succ (&addrset_treedef, &as->mcaddrs, n); - if (ddsi_is_ssm_mcaddr (&n1->loc)) - { - ddsrt_avl_cdelete (&addrset_treedef, &as->mcaddrs, n1); - ddsrt_free (n1); - } - } - UNLOCK (as); + copy_addrset_into_addrset_uc (gv, as, asadd); + copy_addrset_into_addrset_no_ssm_mc (gv, as, asadd); } #endif @@ -541,15 +527,13 @@ void addrset_forall (struct addrset *as, addrset_forall_fun_t f, void *arg) int addrset_forone (struct addrset *as, addrset_forone_fun_t f, void *arg) { - unsigned i; addrset_node_t n; ddsrt_avl_ctree_t *trees[2]; ddsrt_avl_citer_t iter; trees[0] = &as->mcaddrs; trees[1] = &as->ucaddrs; - - for (i = 0; i < 2u; i++) + for (int i = 0; i < 2; i++) { n = (addrset_node_t) ddsrt_avl_citer_first (&addrset_treedef, trees[i], &iter); while (n) @@ -567,23 +551,26 @@ int addrset_forone (struct addrset *as, addrset_forone_fun_t f, void *arg) struct log_addrset_helper_arg { uint32_t tf; + struct q_globals *gv; }; static void log_addrset_helper (const nn_locator_t *n, void *varg) { const struct log_addrset_helper_arg *arg = varg; + const struct q_globals *gv = arg->gv; char buf[DDSI_LOCSTRLEN]; - if (dds_get_log_mask() & arg->tf) - DDS_LOG(arg->tf, " %s", ddsi_locator_to_string(buf, sizeof(buf), n)); + if (gv->logconfig.c.mask & arg->tf) + GVLOG (arg->tf, " %s", ddsi_locator_to_string (gv, buf, sizeof(buf), n)); } -void nn_log_addrset (uint32_t tf, const char *prefix, const struct addrset *as) +void nn_log_addrset (struct q_globals *gv, uint32_t tf, const char *prefix, const struct addrset *as) { - if (dds_get_log_mask() & tf) + if (gv->logconfig.c.mask & tf) { struct log_addrset_helper_arg arg; arg.tf = tf; - DDS_LOG(tf, "%s", prefix); + arg.gv = gv; + GVLOG (tf, "%s", prefix); addrset_forall ((struct addrset *) as, log_addrset_helper, &arg); /* drop const, we know it is */ } } diff --git a/src/core/ddsi/src/q_bswap.c b/src/core/ddsi/src/q_bswap.c index 2899b69..c3ee3cf 100644 --- a/src/core/ddsi/src/q_bswap.c +++ b/src/core/ddsi/src/q_bswap.c @@ -53,28 +53,28 @@ nn_guid_t nn_ntoh_guid (nn_guid_t g) return g; } -void bswap_sequence_number_set_hdr (nn_sequence_number_set_t *snset) +void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset) { bswapSN (&snset->bitmap_base); snset->numbits = bswap4u (snset->numbits); } -void bswap_sequence_number_set_bitmap (nn_sequence_number_set_t *snset) +void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits) { - unsigned i, n = (snset->numbits + 31) / 32; - for (i = 0; i < n; i++) - snset->bits[i] = bswap4u (snset->bits[i]); + const uint32_t n = (snset->numbits + 31) / 32; + for (uint32_t i = 0; i < n; i++) + bits[i] = bswap4u (bits[i]); } -void bswap_fragment_number_set_hdr (nn_fragment_number_set_t *fnset) +void bswap_fragment_number_set_hdr (nn_fragment_number_set_header_t *fnset) { fnset->bitmap_base = bswap4u (fnset->bitmap_base); fnset->numbits = bswap4u (fnset->numbits); } -void bswap_fragment_number_set_bitmap (nn_fragment_number_set_t *fnset) +void bswap_fragment_number_set_bitmap (nn_fragment_number_set_header_t *fnset, uint32_t *bits) { - unsigned i, n = (fnset->numbits + 31) / 32; - for (i = 0; i < n; i++) - fnset->bits[i] = bswap4u (fnset->bits[i]); + const uint32_t n = (fnset->numbits + 31) / 32; + for (uint32_t i = 0; i < n; i++) + bits[i] = bswap4u (bits[i]); } diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index d12bc21..b45eba5 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -10,6 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include +#include #include #include #include @@ -30,23 +31,26 @@ #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_nwif.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsrt/xmlparser.h" #include "dds/version.h" -#define WARN_DEPRECATED_ALIAS 1 -#define WARN_DEPRECATED_UNIT 1 #define MAX_PATH_DEPTH 10 /* max nesting level of configuration elements */ struct cfgelem; struct cfgst; -typedef int(*init_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); -typedef int(*update_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value); -typedef void(*free_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); -typedef void(*print_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default); +enum update_result { + URES_SUCCESS, /* value processed successfully */ + URES_ERROR, /* invalid value, reject configuration */ + URES_SKIP_ELEMENT /* entire subtree should be ignored */ +}; + +typedef int (*init_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); +typedef enum update_result (*update_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value); +typedef void (*free_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); +typedef void (*print_fun_t) (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources); #ifdef DDSI_INCLUDE_SECURITY struct q_security_plugins q_security_plugin = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -74,22 +78,55 @@ struct cfgelem { struct cfgst_nodekey { const struct cfgelem *e; + void *p; }; struct cfgst_node { ddsrt_avl_node_t avlnode; struct cfgst_nodekey key; int count; + uint32_t sources; int failed; - int is_default; +}; + +enum implicit_toplevel { + ITL_DISALLOWED = -1, + ITL_ALLOWED = 0, + ITL_INSERTED_1 = 1, + ITL_INSERTED_2 = 2 }; struct cfgst { ddsrt_avl_tree_t found; struct config *cfg; + const struct ddsrt_log_cfg *logcfg; /* for LOG_LC_CONFIG */ /* error flag set so that we can continue parsing for some errors and still fail properly */ int error; + /* Whether this is the first element in this source: used to reject about configurations + where the deprecated Domain/Id element is used but is set after some other things + have been set. The underlying reason being that the configuration handling can't + backtrack and so needs to reject a configuration for an unrelated domain before + anything is set. + + The new form, where the id is an attribute of the Domain element, avoids this + by guaranteeing that the id comes first. It seems most likely that the Domain/Id + was either not set or at the start of the file and that this is therefore good + enough. */ + bool first_data_in_source; + + /* Whether inserting an implicit CycloneDDS is allowed (for making it easier to hack + a configuration through the environment variables, and if allowed, whether it has + been inserted */ + enum implicit_toplevel implicit_toplevel; + + /* current input, mask with 1 bit set */ + uint32_t source; + + /* ~ current input and line number */ + char *input; + int line; + /* path_depth, isattr and path together control the formatting of error messages by cfg_error() */ int path_depth; @@ -98,32 +135,12 @@ struct cfgst { void *parent[MAX_PATH_DEPTH]; }; -/* "trace" is special: it enables (nearly) everything */ -static const char *logcat_names[] = { - "fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "trace", NULL -}; -static const uint32_t logcat_codes[] = { - DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL -}; - -/* "trace" is special: it enables (nearly) everything */ -static const char *xcheck_names[] = { - "whc", "rhc", "all", NULL -}; -static const uint32_t xcheck_codes[] = { - DDS_XCHECK_WHC, DDS_XCHECK_RHC, ~(uint32_t)0 -}; - -/* We want the tracing/verbosity settings to be fixed while parsing - the configuration, so we update this variable instead. */ -static uint32_t enabled_logcats; - static int cfgst_node_cmp(const void *va, const void *vb); static const ddsrt_avl_treedef_t cfgst_found_treedef = DDSRT_AVL_TREEDEF_INITIALIZER(offsetof(struct cfgst_node, avlnode), offsetof(struct cfgst_node, key), cfgst_node_cmp, 0); -#define DU(fname) static int uf_##fname (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -#define PF(fname) static void pf_##fname (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) +#define DU(fname) static enum update_result uf_##fname (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +#define PF(fname) static void pf_##fname (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) #define DUPF(fname) DU(fname) ; PF(fname) PF(nop); DUPF(networkAddress); @@ -138,7 +155,7 @@ PF(boolean_default); DUPF(string); DU(tracingOutputFileName); DU(verbosity); -DUPF(logcat); +DUPF(tracemask); DUPF(xcheck); DUPF(int); DUPF(uint); @@ -216,7 +233,7 @@ DI(if_thread_properties); #define MGROUP(name, children, attrs) name, children, attrs #define ATTR(name) name, NULL, NULL #define DEPRECATED_ATTR(name) "|" name, NULL, NULL -/* MOVED: whereto must be a path relative to DDSI2Service, may not be used in/for lists and only for elements, may not be chained */ +/* MOVED: whereto must be a path starting with CycloneDDS, may not be used in/for lists and only for elements, may not be chained */ #define MOVED(name, whereto) ">" name, NULL, NULL, 0, whereto, 0, 0, 0, 0, 0, 0, NULL #if 0 #define BLURB(text) text @@ -240,15 +257,18 @@ static const struct cfgelem general_cfgelems[] = { BLURB("

This element allows explicitly overruling the network address DDSI2E advertises in the discovery protocol, which by default is the address of the preferred network interface (General/NetworkInterfaceAddress), to allow DDSI2E to communicate across a Network Address Translation (NAT) device.

") }, { LEAF("ExternalNetworkMask"), 1, "0.0.0.0", ABSOFF(externalMaskString), 0, uf_string, ff_free, pf_string, BLURB("

This element specifies the network mask of the external network address. This element is relevant only when an external network address (General/ExternalNetworkAddress) is explicitly configured. In this case locators received via the discovery protocol that are within the same external subnet (as defined by this mask) will be translated to an internal address by replacing the network portion of the external address with the corresponding portion of the preferred network interface address. This option is IPv4-only.

") }, - { LEAF("AllowMulticast"), 1, "true", ABSOFF(allowMulticast), 0, uf_allow_multicast, 0, pf_allow_multicast, + { LEAF("AllowMulticast"), 1, "default", ABSOFF(allowMulticast), 0, uf_allow_multicast, 0, pf_allow_multicast, BLURB("

This element controls whether DDSI2E uses multicasts for data traffic.

\n\ -

It is a comma-separated list of some of the following keywords: \"spdp\", \"asm\", \"ssm\", or either of \"false\" or \"true\".

\n\ +

It is a comma-separated list of some of the following keywords: \"spdp\", \"asm\", \"ssm\", or either of \"false\" or \"true\", or \"default\".

\n\
    \n\
  • spdp: enables the use of ASM (any-source multicast) for participant discovery, joining the multicast group on the discovery socket, transmitting SPDP messages to this group, but never advertising nor using any multicast address in any discovery message, thus forcing unicast communications for all endpoint discovery and user data.
  • \n\
  • asm: enables the use of ASM for all traffic, including receiving SPDP but not transmitting SPDP messages via multicast
  • \n\
  • ssm: enables the use of SSM (source-specific multicast) for all non-SPDP traffic (if supported)
  • \n\
\n\ -

When set to \"false\" all multicasting is disabled. The default, \"true\" enables full use of multicasts. Listening for multicasts can be controlled by General/MulticastRecvNetworkInterfaceAddresses.

") }, +

When set to \"false\" all multicasting is disabled. The default, \"true\" enables full use of multicasts. Listening for multicasts can be controlled by General/MulticastRecvNetworkInterfaceAddresses.

\n\ +

\"default\" maps on spdp if the network is a WiFi network, on true if it is a wired network

") }, + { LEAF("PreferMulticast"), 1, "false", ABSOFF(prefer_multicast), 0, uf_boolean, 0, pf_boolean, + BLURB("

When false (default) Cyclone DDS uses unicast for data whenever there a single unicast suffices. Setting this to true makes it prefer multicasting data, falling back to unicast only when no multicast address is available.

") }, { LEAF("MulticastTimeToLive"), 1, "32", ABSOFF(multicast_ttl), 0, uf_natint_255, 0, pf_int, BLURB("

This element specifies the time-to-live setting for outgoing multicast packets.

") }, { LEAF("DontRoute"), 1, "false", ABSOFF(dontRoute), 0, uf_boolean, 0, pf_boolean, @@ -288,7 +308,7 @@ static const struct cfgelem securityprofile_cfgattrs[] = { }; static const struct cfgelem security_cfgelems[] = { - { LEAF_W_ATTRS("SecurityProfile", securityprofile_cfgattrs), 0, 0, ABSOFF(securityProfiles), if_security_profile, 0, 0, 0, + { LEAF_W_ATTRS("SecurityProfile", securityprofile_cfgattrs), INT_MAX, 0, ABSOFF(securityProfiles), if_security_profile, 0, 0, 0, BLURB("

This element defines a DDSI2E security profile.

") }, END_MARKER }; @@ -310,7 +330,7 @@ static const struct cfgelem networkpartition_cfgattrs[] = { }; static const struct cfgelem networkpartitions_cfgelems[] = { - { LEAF_W_ATTRS("NetworkPartition", networkpartition_cfgattrs), 0, 0, ABSOFF(networkPartitions), if_network_partition, 0, 0, 0, + { LEAF_W_ATTRS("NetworkPartition", networkpartition_cfgattrs), INT_MAX, 0, ABSOFF(networkPartitions), if_network_partition, 0, 0, 0, BLURB("

This element defines a DDSI2E network partition.

") }, END_MARKER }; @@ -322,7 +342,7 @@ static const struct cfgelem ignoredpartitions_cfgattrs[] = { }; static const struct cfgelem ignoredpartitions_cfgelems[] = { - { LEAF_W_ATTRS("IgnoredPartition", ignoredpartitions_cfgattrs), 0, 0, ABSOFF(ignoredPartitions), if_ignored_partition, 0, 0, 0, + { LEAF_W_ATTRS("IgnoredPartition", ignoredpartitions_cfgattrs), INT_MAX, 0, ABSOFF(ignoredPartitions), if_ignored_partition, 0, 0, 0, BLURB("

This element can be used to prevent certain combinations of DCPS partition and topic from being transmitted over the network. DDSI2E will complete ignore readers and writers for which all DCPS partitions as well as their topic is ignored, not even creating DDSI readers and writers to mirror the DCPS ones.

") }, END_MARKER }; @@ -336,7 +356,7 @@ static const struct cfgelem partitionmappings_cfgattrs[] = { }; static const struct cfgelem partitionmappings_cfgelems[] = { - { LEAF_W_ATTRS("PartitionMapping", partitionmappings_cfgattrs), 0, 0, ABSOFF(partitionMappings), if_partition_mapping, 0, 0, 0, + { LEAF_W_ATTRS("PartitionMapping", partitionmappings_cfgattrs), INT_MAX, 0, ABSOFF(partitionMappings), if_partition_mapping, 0, 0, 0, BLURB("

This element defines a mapping from a DCPS partition/topic combination to a DDSI2E network partition. This allows partitioning data flows by using special multicast addresses for part of the data and possibly also encrypting the data flow.

") }, END_MARKER }; @@ -381,7 +401,7 @@ static const struct cfgelem channel_cfgattrs[] = { }; static const struct cfgelem channels_cfgelems[] = { - { MGROUP("Channel", channel_cfgelems, channel_cfgattrs), 42, 0, ABSOFF(channels), if_channel, 0, 0, 0, + { MGROUP("Channel", channel_cfgelems, channel_cfgattrs), INT_MAX, 0, ABSOFF(channels), if_channel, 0, 0, 0, BLURB("

This element defines a channel.

") }, END_MARKER }; @@ -418,7 +438,7 @@ static const struct cfgelem thread_properties_cfgelems[] = { }; static const struct cfgelem threads_cfgelems[] = { - { MGROUP("Thread", thread_properties_cfgelems, thread_properties_cfgattrs), 1000, 0, ABSOFF(thread_properties), if_thread_properties, 0, 0, 0, + { MGROUP("Thread", thread_properties_cfgelems, thread_properties_cfgattrs), INT_MAX, 0, ABSOFF(thread_properties), if_thread_properties, 0, 0, 0, BLURB("

This element is used to set thread properties.

") }, END_MARKER }; @@ -436,8 +456,6 @@ static const struct cfgelem compatibility_cfgelems[] = { { LEAF ("ManySocketsMode"), 1, "single", ABSOFF (many_sockets_mode), 0, uf_many_sockets_mode, 0, pf_many_sockets_mode, BLURB("

This option specifies whether a network socket will be created for each domain participant on a host. The specification seems to assume that each participant has a unique address, and setting this option will ensure this to be the case. This is not the defeault.

\n\

Disabling it slightly improves performance and reduces network traffic somewhat. It also causes the set of port numbers needed by DDSI2E to become predictable, which may be useful for firewall and NAT configuration.

") }, - { LEAF("ArrivalOfDataAssertsPpAndEpLiveliness"), 1, "true", ABSOFF(arrival_of_data_asserts_pp_and_ep_liveliness), 0, uf_boolean, 0, pf_boolean, - BLURB("

When set to true, arrival of a message from a peer asserts liveliness of that peer. When set to false, only SPDP and explicit lease renewals have this effect.

") }, { LEAF("AssumeRtiHasPmdEndpoints"), 1, "false", ABSOFF(assume_rti_has_pmd_endpoints), 0, uf_boolean, 0, pf_boolean, BLURB("

This option assumes ParticipantMessageData endpoints required by the liveliness protocol are present in RTI participants even when not properly advertised by the participant discovery protocol.

") }, END_MARKER @@ -512,9 +530,9 @@ static const struct cfgelem unsupp_cfgelems[] = { { MOVED("FragmentSize", "CycloneDDS/General/FragmentSize") }, { LEAF("DeliveryQueueMaxSamples"), 1, "256", ABSOFF(delivery_queue_maxsamples), 0, uf_uint, 0, pf_uint, BLURB("

This element controls the Maximum size of a delivery queue, expressed in samples. Once a delivery queue is full, incoming samples destined for that queue are dropped until space becomes available again.

") }, - { LEAF("PrimaryReorderMaxSamples"), 1, "64", ABSOFF(primary_reorder_maxsamples), 0, uf_uint, 0, pf_uint, + { LEAF("PrimaryReorderMaxSamples"), 1, "128", ABSOFF(primary_reorder_maxsamples), 0, uf_uint, 0, pf_uint, BLURB("

This element sets the maximum size in samples of a primary re-order administration. Each proxy writer has one primary re-order administration to buffer the packet flow in case some packets arrive out of order. Old samples are forwarded to secondary re-order administrations associated with readers in need of historical data.

") }, - { LEAF("SecondaryReorderMaxSamples"), 1, "16", ABSOFF(secondary_reorder_maxsamples), 0, uf_uint, 0, pf_uint, + { LEAF("SecondaryReorderMaxSamples"), 1, "128", ABSOFF(secondary_reorder_maxsamples), 0, uf_uint, 0, pf_uint, BLURB("

This element sets the maximum size in samples of a secondary re-order administration. The secondary re-order administration is per reader in need of historical data.

") }, { LEAF("DefragUnreliableMaxSamples"), 1, "4", ABSOFF(defrag_unreliable_maxsamples), 0, uf_uint, 0, pf_uint, BLURB("

This element sets the maximum number of samples that can be defragmented simultaneously for a best-effort writers.

") }, @@ -526,9 +544,6 @@ static const struct cfgelem unsupp_cfgelems[] = {
  • writers: all participants have the writers, but just one has the readers;
  • \n\
  • minimal: only one participant has built-in endpoints.
  • \n\

    The default is writers, as this is thought to be compliant and reasonably efficient. Minimal may or may not be compliant but is most efficient, and full is inefficient but certain to be compliant. See also Internal/ConservativeBuiltinReaderStartup.

    ") }, - { LEAF("ConservativeBuiltinReaderStartup"), 1, "false", ABSOFF(conservative_builtin_reader_startup), 0, uf_boolean, 0, pf_boolean, - BLURB("

    This element forces all DDSI2E built-in discovery-related readers to request all historical data, instead of just one for each \"topic\". There is no indication that any of the current DDSI implementations requires changing of this setting, but it is conceivable that an implementation might track which participants have been informed of the existence of endpoints and which have not been, refusing communication with those that have \"can't\" know.

    \n\ -

    Should it be necessary to hide DDSI2E's shared discovery behaviour, set this to true and Internal/BuiltinEndpointSet to full.

    ") }, { LEAF("MeasureHbToAckLatency"), 1, "false", ABSOFF(meas_hb_to_ack_latency), 0, uf_boolean, 0, pf_boolean, BLURB("

    This element enables heartbeat-to-ack latency among DDSI2E services by prepending timestamps to Heartbeat and AckNack messages and calculating round trip times. This is non-standard behaviour. The measured latencies are quite noisy and are currently not used anywhere.

    ") }, { LEAF("UnicastResponseToSPDPMessages"), 1, "true", ABSOFF(unicast_response_to_spdp_messages), 0, uf_boolean, 0, pf_boolean, @@ -541,12 +556,12 @@ static const struct cfgelem unsupp_cfgelems[] = { BLURB("

    This elements configures the maximum number of DCPS domain participants this DDSI2E instance is willing to service. 0 is unlimited.

    ") }, { LEAF("AccelerateRexmitBlockSize"), 1, "0", ABSOFF(accelerate_rexmit_block_size), 0, uf_uint, 0, pf_uint, BLURB("

    Proxy readers that are assumed to sill be retrieving historical data get this many samples retransmitted when they NACK something, even if some of these samples have sequence numbers outside the set covered by the NACK.

    ") }, - { LEAF("RetransmitMerging"), 1, "adaptive", ABSOFF(retransmit_merging), 0, uf_retransmit_merging, 0, pf_retransmit_merging, + { LEAF("RetransmitMerging"), 1, "never", ABSOFF(retransmit_merging), 0, uf_retransmit_merging, 0, pf_retransmit_merging, BLURB("

    This elements controls the addressing and timing of retransmits. Possible values are:

    \n\
    • never: retransmit only to the NACK-ing reader;
    • \n \
    • adaptive: attempt to combine retransmits needed for reliability, but send historical (transient-local) data to the requesting reader only;
    • \n\
    • always: do not distinguish between different causes, always try to merge.
    \n\ -

    The default is adaptive. See also Internal/RetransmitMergingPeriod.

    ") }, +

    The default is never. See also Internal/RetransmitMergingPeriod.

    ") }, { LEAF("RetransmitMergingPeriod"), 1, "5 ms", ABSOFF(retransmit_merging_period), 0, uf_duration_us_1s, 0, pf_duration, BLURB("

    This setting determines the size of the time window in which a NACK of some sample is ignored because a retransmit of that sample has been multicasted too recently. This setting has no effect on unicasted retransmits.

    \n\

    See also Internal/RetransmitMerging.

    ") }, @@ -632,19 +647,19 @@ static const struct cfgelem sizing_cfgelems[] = { }; static const struct cfgelem discovery_ports_cfgelems[] = { - { LEAF("Base"), 1, "7400", ABSOFF(port_base), 0, uf_port, 0, pf_int, + { LEAF("Base"), 1, "7400", ABSOFF(port_base), 0, uf_port, 0, pf_uint, BLURB("

    This element specifies the base port number (refer to the DDSI 2.1 specification, section 9.6.1, constant PB).

    ") }, - { LEAF("DomainGain"), 1, "250", ABSOFF(port_dg), 0, uf_int, 0, pf_int, + { LEAF("DomainGain"), 1, "250", ABSOFF(port_dg), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the domain gain, relating domain ids to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant DG).

    ") }, - { LEAF("ParticipantGain"), 1, "2", ABSOFF(port_pg), 0, uf_int, 0, pf_int, + { LEAF("ParticipantGain"), 1, "2", ABSOFF(port_pg), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the participant gain, relating p0, articipant index to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant PG).

    ") }, - { LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(port_d0), 0, uf_int, 0, pf_int, + { LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(port_d0), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d0).

    ") }, - { LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(port_d1), 0, uf_int, 0, pf_int, + { LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(port_d1), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d1).

    ") }, - { LEAF("MulticastDataOffset"), 1, "1", ABSOFF(port_d2), 0, uf_int, 0, pf_int, + { LEAF("MulticastDataOffset"), 1, "1", ABSOFF(port_d2), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d2).

    ") }, - { LEAF("UnicastDataOffset"), 1, "11", ABSOFF(port_d3), 0, uf_int, 0, pf_int, + { LEAF("UnicastDataOffset"), 1, "11", ABSOFF(port_d3), 0, uf_uint, 0, pf_uint, BLURB("

    This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d3).

    ") }, END_MARKER }; @@ -706,13 +721,13 @@ static const struct cfgelem discovery_peer_cfgattrs[] = { }; static const struct cfgelem discovery_peers_group_cfgelems[] = { - { MGROUP("Peer", NULL, discovery_peer_cfgattrs), 0, NULL, ABSOFF(peers_group), if_peer, 0, 0, 0, + { MGROUP("Peer", NULL, discovery_peer_cfgattrs), INT_MAX, NULL, ABSOFF(peers_group), if_peer, 0, 0, 0, BLURB("

    This element statically configures an addresses for discovery.

    ") }, END_MARKER }; static const struct cfgelem discovery_peers_cfgelems[] = { - { MGROUP("Peer", NULL, discovery_peer_cfgattrs), 0, NULL, ABSOFF(peers), if_peer, 0, 0, 0, + { MGROUP("Peer", NULL, discovery_peer_cfgattrs), INT_MAX, NULL, ABSOFF(peers), if_peer, 0, 0, 0, BLURB("

    This element statically configures an addresses for discovery.

    ") }, { GROUP("Group", discovery_peers_group_cfgelems), BLURB("

    This element statically configures a fault tolerant group of addresses for discovery. Each member of the group is tried in sequence until one succeeds.

    ") }, @@ -746,7 +761,7 @@ static const struct cfgelem discovery_cfgelems[] = { }; static const struct cfgelem tracing_cfgelems[] = { - { LEAF("EnableCategory"), 1, "", 0, 0, 0, uf_logcat, 0, pf_logcat, + { LEAF("EnableCategory"), 1, "", 0, 0, 0, uf_tracemask, 0, pf_tracemask, BLURB("

    This element enables individual logging categories. These are enabled in addition to those enabled by Tracing/Verbosity. Recognised categories are:

    \n\
    • fatal: all fatal errors, errors causing immediate termination
    • \n\
    • error: failures probably impacting correctness but not necessarily causing immediate termination
    • \n\ @@ -776,7 +791,7 @@ static const struct cfgelem tracing_cfgelems[] = {
    • finest: finer + trace
    \n\

    While none prevents any message from being written to a DDSI2 log file.

    \n\

    The categorisation of tracing output is incomplete and hence most of the verbosity levels and categories are not of much use in the current release. This is an ongoing process and here we describe the target situation rather than the current situation. Currently, the most useful verbosity levels are config, fine and finest.

    ") }, - { LEAF("OutputFile"), 1, DDS_PROJECT_NAME_NOSPACE_SMALL".log", ABSOFF(tracingOutputFileName), 0, uf_tracingOutputFileName, ff_free, pf_string, + { LEAF("OutputFile"), 1, "cyclonedds.log", ABSOFF(tracefile), 0, uf_tracingOutputFileName, ff_free, pf_string, BLURB("

    This option specifies where the logging is printed to. Note that stdout and stderr are treated as special values, representing \"standard out\" and \"standard error\" respectively. No file is created unless logging categories are enabled using the Tracing/Verbosity or Tracing/EnabledCategory settings.

    ") }, { LEAF("AppendToFile"), 1, "false", ABSOFF(tracingAppendToFile), 0, uf_boolean, 0, pf_boolean, BLURB("

    This option specifies whether the output is to be appended to an existing log file. The default is to create a new log file each time, which is generally the best option if a detailed log is generated.

    ") }, @@ -785,14 +800,14 @@ static const struct cfgelem tracing_cfgelems[] = { END_MARKER }; -static const struct cfgelem domain_cfgelems[] = { - { LEAF("Id"), 1, "any", ABSOFF(domainId), 0, uf_domainId, 0, pf_domainId, NULL }, +static const struct cfgelem domain_cfgattrs[] = { + { LEAF("Id"), 0, "any", ABSOFF(domainId), 0, uf_domainId, 0, pf_domainId, + BLURB("

    Domain id this configuration applies to, or \"any\" if it applies to all domain ids.

    ") }, END_MARKER }; -static const struct cfgelem root_cfgelems[] = { - { GROUP("Domain", domain_cfgelems), - BLURB("

    The General element specifying Domain related settings.

    ") }, +static const struct cfgelem domain_cfgelems[] = { + { MOVED("Id", "CycloneDDS/Domain[@Id]") }, { GROUP("General", general_cfgelems), BLURB("

    The General element specifies overall DDSI2E service settings.

    ") }, #ifdef DDSI_INCLUDE_ENCRYPTION @@ -827,12 +842,39 @@ static const struct cfgelem root_cfgelems[] = { { GROUP("SSL", ssl_cfgelems), BLURB("

    The SSL element allows specifying various parameters related to using SSL/TLS for DDSI over TCP.

    ") }, #endif - { MOVED("DDSI2E|DDSI2", "CycloneDDS") }, + END_MARKER +}; + +static const struct cfgelem root_cfgelems[] = { + { GROUP_W_ATTRS("Domain", domain_cfgelems, domain_cfgattrs), + BLURB("

    The General element specifying Domain related settings.

    ") }, + { MOVED("General", "CycloneDDS/Domain/General") }, +#ifdef DDSI_INCLUDE_ENCRYPTION + { MOVED("Security", "CycloneDDS/Domain/Security") }, +#endif +#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS + { MOVED("Partitioning", "CycloneDDS/Domain/Partitioning") }, +#endif +#ifdef DDSI_INCLUDE_NETWORK_CHANNELS + { MOVED("Channels", "CycloneDDS/Domain/Channels") }, +#endif + { MOVED("Threads", "CycloneDDS/Domain/Threads") }, + { MOVED("Sizing", "CycloneDDS/Domain/Sizing") }, + { MOVED("Compatibility", "CycloneDDS/Domain/Compatibility") }, + { MOVED("Discovery", "CycloneDDS/Domain/Discovery") }, + { MOVED("Tracing", "CycloneDDS/Domain/Tracing") }, + { MOVED("Internal|Unsupported", "CycloneDDS/Domain/Internal") }, + { MOVED("TCP", "CycloneDDS/Domain/TCP") }, + { MOVED("ThreadPool", "CycloneDDS/Domain/ThreadPool") }, +#ifdef DDSI_INCLUDE_SSL + { MOVED("SSL", "CycloneDDS/Domain/SSL") }, +#endif + { MOVED("DDSI2E|DDSI2", "CycloneDDS/Domain") }, END_MARKER }; static const struct cfgelem cyclonedds_root_cfgelems[] = { - { DDS_PROJECT_NAME_NOSPACE, root_cfgelems, NULL, NODATA, NULL }, + { "CycloneDDS", root_cfgelems, NULL, NODATA, BLURB("CycloneDDS configuration") }, END_MARKER }; @@ -851,9 +893,6 @@ static const struct cfgelem root_cfgelem = { #undef ABSOFF #undef CO -struct config config; -struct ddsi_plugin ddsi_plugin; - static const struct unit unittab_duration[] = { { "ns", 1 }, { "us", 1000 }, @@ -909,7 +948,11 @@ static const struct unit unittab_bandwidth_Bps[] = { }; #endif -static void cfgst_push(struct cfgst *cfgst, int isattr, const struct cfgelem *elem, void *parent) +static void free_configured_elements (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); +static void free_configured_element (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem); +static const struct cfgelem *lookup_element (const char *target, bool *isattr); + +static void cfgst_push (struct cfgst *cfgst, int isattr, const struct cfgelem *elem, void *parent) { assert(cfgst->path_depth < MAX_PATH_DEPTH); assert(isattr == 0 || isattr == 1); @@ -919,19 +962,26 @@ static void cfgst_push(struct cfgst *cfgst, int isattr, const struct cfgelem *el cfgst->path_depth++; } -static void cfgst_pop(struct cfgst *cfgst) +static void cfgst_pop (struct cfgst *cfgst) { assert(cfgst->path_depth > 0); cfgst->path_depth--; } -static const struct cfgelem *cfgst_tos(const struct cfgst *cfgst) +static const struct cfgelem *cfgst_tos_w_isattr (const struct cfgst *cfgst, bool *isattr) { assert(cfgst->path_depth > 0); + *isattr = cfgst->isattr[cfgst->path_depth - 1]; return cfgst->path[cfgst->path_depth - 1]; } -static void *cfgst_parent(const struct cfgst *cfgst) +static const struct cfgelem *cfgst_tos (const struct cfgst *cfgst) +{ + bool dummy_isattr; + return cfgst_tos_w_isattr (cfgst, &dummy_isattr); +} + +static void *cfgst_parent (const struct cfgst *cfgst) { assert(cfgst->path_depth > 0); return cfgst->parent[cfgst->path_depth - 1]; @@ -943,46 +993,47 @@ struct cfg_note_buf { char *buf; }; -static size_t cfg_note_vsnprintf(struct cfg_note_buf *bb, const char *fmt, va_list ap) +static size_t cfg_note_vsnprintf (struct cfg_note_buf *bb, const char *fmt, va_list ap) { int x; x = vsnprintf(bb->buf + bb->bufpos, bb->bufsize - bb->bufpos, fmt, ap); - if ( x >= 0 && (size_t) x >= bb->bufsize - bb->bufpos ) { + if (x >= 0 && (size_t) x >= bb->bufsize - bb->bufpos) + { size_t nbufsize = ((bb->bufsize + (size_t) x + 1) + 1023) & (size_t) (-1024); - char *nbuf = ddsrt_realloc(bb->buf, nbufsize); + char *nbuf = ddsrt_realloc (bb->buf, nbufsize); bb->buf = nbuf; bb->bufsize = nbufsize; return nbufsize; } - if ( x < 0 ) + if (x < 0) DDS_FATAL("cfg_note_vsnprintf: vsnprintf failed\n"); else bb->bufpos += (size_t) x; return 0; } -static void cfg_note_snprintf(struct cfg_note_buf *bb, const char *fmt, ...) +static void cfg_note_snprintf (struct cfg_note_buf *bb, const char *fmt, ...) { /* The reason the 2nd call to os_vsnprintf is here and not inside cfg_note_vsnprintf is because I somehow doubt that all platforms implement va_copy() */ va_list ap; size_t r; - va_start(ap, fmt); - r = cfg_note_vsnprintf(bb, fmt, ap); - va_end(ap); - if ( r > 0 ) { + va_start (ap, fmt); + r = cfg_note_vsnprintf (bb, fmt, ap); + va_end (ap); + if (r > 0) { int s; - va_start(ap, fmt); - s = vsnprintf(bb->buf + bb->bufpos, bb->bufsize - bb->bufpos, fmt, ap); - if ( s < 0 || (size_t) s >= bb->bufsize - bb->bufpos ) - DDS_FATAL("cfg_note_snprintf: vsnprintf failed\n"); - va_end(ap); + va_start (ap, fmt); + s = vsnprintf (bb->buf + bb->bufpos, bb->bufsize - bb->bufpos, fmt, ap); + if (s < 0 || (size_t) s >= bb->bufsize - bb->bufpos) + DDS_FATAL ("cfg_note_snprintf: vsnprintf failed\n"); + va_end (ap); bb->bufpos += (size_t) s; } } -static size_t cfg_note(struct cfgst *cfgst, uint32_t cat, size_t bsz, const char *fmt, va_list ap) +static size_t cfg_note (struct cfgst *cfgst, uint32_t cat, size_t bsz, const char *fmt, const char *suffix, va_list ap) { /* Have to snprintf our way to a single string so we can OS_REPORT as well as nn_log. Otherwise configuration errors will be lost @@ -993,177 +1044,196 @@ static size_t cfg_note(struct cfgst *cfgst, uint32_t cat, size_t bsz, const char int i, sidx; size_t r; - if (cat & DDS_LC_ERROR) { + if (cat & DDS_LC_ERROR) cfgst->error = 1; - } bb.bufpos = 0; bb.bufsize = (bsz == 0) ? 1024 : bsz; - if ( (bb.buf = ddsrt_malloc(bb.bufsize)) == NULL ) - DDS_FATAL("cfg_note: out of memory\n"); + if ((bb.buf = ddsrt_malloc(bb.bufsize)) == NULL) + DDS_FATAL ("cfg_note: out of memory\n"); - cfg_note_snprintf(&bb, "config: "); + cfg_note_snprintf (&bb, "config: "); /* Path to element/attribute causing the error. Have to stop once an attribute is reached: a NULL marker may have been pushed onto the stack afterward in the default handling. */ sidx = 0; - while ( sidx < cfgst->path_depth && cfgst->path[sidx]->name == NULL ) + while (sidx < cfgst->path_depth && cfgst->path[sidx]->name == NULL) sidx++; const struct cfgelem *prev_path = NULL; - for ( i = sidx; i < cfgst->path_depth && (i == sidx || !cfgst->isattr[i - 1]); i++ ) { - if ( cfgst->path[i] == NULL ) { + for (i = sidx; i < cfgst->path_depth && (i == sidx || !cfgst->isattr[i - 1]); i++) + { + if (cfgst->path[i] == NULL) + { assert(i > sidx); - cfg_note_snprintf(&bb, "/#text"); - } else if ( cfgst->isattr[i] ) { - cfg_note_snprintf(&bb, "[@%s]", cfgst->path[i]->name); - } else if (cfgst->path[i] == prev_path) { + cfg_note_snprintf (&bb, "/#text"); + } + else if (cfgst->isattr[i]) + { + cfg_note_snprintf (&bb, "[@%s]", cfgst->path[i]->name); + } + else if (cfgst->path[i] == prev_path) + { /* skip printing this level: it means a group contained an element indicating that it was moved to the first group (i.e., stripping a level) -- this is currently only used for stripping out the DDSI2E level, and the sole purpose of this special case is making any warnings from elements contained within it look reasonable by always printing the new location */ - } else { + } + else + { /* first character is '>' means it was moved, so print what follows instead */ const char *name = cfgst->path[i]->name + ((cfgst->path[i]->name[0] == '>') ? 1 : 0); - const char *p = strchr(name, '|'); + const char *p = strchr (name, '|'); int n = p ? (int) (p - name) : (int) strlen(name); - cfg_note_snprintf(&bb, "%s%*.*s", (i == sidx) ? "" : "/", n, n, name); + cfg_note_snprintf (&bb, "%s%*.*s", (i == sidx) ? "" : "/", n, n, name); } prev_path = cfgst->path[i]; } - cfg_note_snprintf(&bb, ": "); - if ( (r = cfg_note_vsnprintf(&bb, fmt, ap)) > 0 ) { + cfg_note_snprintf (&bb, ": "); + if ((r = cfg_note_vsnprintf (&bb, fmt, ap)) > 0) + { /* Can't reset ap ... and va_copy isn't widely available - so instead abort and hope the caller tries again with a larger initial buffer */ - ddsrt_free(bb.buf); + ddsrt_free (bb.buf); return r; } - switch ( cat ) { - case DDS_LC_CONFIG: - DDS_LOG(cat, "%s\n", bb.buf); - break; - case DDS_LC_WARNING: - DDS_WARNING("%s\n", bb.buf); - break; - case DDS_LC_ERROR: - DDS_ERROR("%s\n", bb.buf); - break; - default: - DDS_FATAL("cfg_note unhandled category %u for message %s\n", (unsigned) cat, bb.buf); - break; + cfg_note_snprintf (&bb, "%s", suffix); + + if (cat & (DDS_LC_WARNING | DDS_LC_ERROR)) + { + if (cfgst->input == NULL) + cfg_note_snprintf (&bb, " (line %d)", cfgst->line); + else + { + cfg_note_snprintf (&bb, " (%s line %d)", cfgst->input, cfgst->line); + cfgst->input = NULL; + } } - ddsrt_free(bb.buf); + if (cfgst->logcfg) + DDS_CLOG (cat, cfgst->logcfg, "%s\n", bb.buf); + else + DDS_ILOG (cat, cfgst->cfg->domainId, "%s\n", bb.buf); + + ddsrt_free (bb.buf); return 0; } -#if WARN_DEPRECATED_ALIAS || WARN_DEPRECATED_UNIT -static void cfg_warning(struct cfgst *cfgst, const char *fmt, ...) +static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...) { va_list ap; size_t bsz = 0; do { - va_start(ap, fmt); - bsz = cfg_note(cfgst, DDS_LC_WARNING, bsz, fmt, ap); - va_end(ap); - } while ( bsz > 0 ); + va_start (ap, fmt); + bsz = cfg_note (cfgst, DDS_LC_WARNING, bsz, fmt, "", ap); + va_end (ap); + } while (bsz > 0); } -#endif -static int cfg_error(struct cfgst *cfgst, const char *fmt, ...) +static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...) { va_list ap; size_t bsz = 0; do { - va_start(ap, fmt); - bsz = cfg_note(cfgst, DDS_LC_ERROR, bsz, fmt, ap); - va_end(ap); - } while ( bsz > 0 ); - return 0; + va_start (ap, fmt); + bsz = cfg_note (cfgst, DDS_LC_ERROR, bsz, fmt, "", ap); + va_end (ap); + } while (bsz > 0); + return URES_ERROR; } -static int cfg_log(struct cfgst *cfgst, const char *fmt, ...) +static void cfg_logelem (struct cfgst *cfgst, uint32_t sources, const char *fmt, ...) { + /* 89 = 1 + 2 + 31 + 1 + 10 + 2*22: the number of characters in + a string formed by concatenating all numbers from 0 .. 31 in decimal notation, + 31 separators, a opening and closing brace pair, a terminating 0, and a leading + space */ + char srcinfo[89]; va_list ap; size_t bsz = 0; + srcinfo[0] = ' '; + srcinfo[1] = '{'; + int pos = 2; + for (uint32_t i = 0, m = 1; i < 32; i++, m <<= 1) + if (sources & m) + pos += snprintf (srcinfo + pos, sizeof (srcinfo) - (size_t) pos, "%s%"PRIu32, (pos == 2) ? "" : ",", i); + srcinfo[pos] = '}'; + srcinfo[pos + 1] = 0; + assert ((size_t) pos <= sizeof (srcinfo) - 2); do { - va_start(ap, fmt); - bsz = cfg_note(cfgst, DDS_LC_CONFIG, bsz, fmt, ap); - va_end(ap); - } while ( bsz > 0 ); - return 0; + va_start (ap, fmt); + bsz = cfg_note (cfgst, DDS_LC_CONFIG, bsz, fmt, srcinfo, ap); + va_end (ap); + } while (bsz > 0); } -static int list_index(const char *list[], const char *elem) +static int list_index (const char *list[], const char *elem) { - int i; - for ( i = 0; list[i] != NULL; i++ ) { - if ( ddsrt_strcasecmp(list[i], elem) == 0 ) + for (int i = 0; list[i] != NULL; i++) + if (ddsrt_strcasecmp (list[i], elem) == 0) return i; - } return -1; } -static int64_t lookup_multiplier(struct cfgst *cfgst, const struct unit *unittab, const char *value, int unit_pos, int value_is_zero, int64_t def_mult, int err_on_unrecognised) +static int64_t lookup_multiplier (struct cfgst *cfgst, const struct unit *unittab, const char *value, int unit_pos, int value_is_zero, int64_t def_mult, int err_on_unrecognised) { - assert(0 <= unit_pos && (size_t) unit_pos <= strlen(value)); - while ( value[unit_pos] == ' ' ) + assert (0 <= unit_pos && (size_t) unit_pos <= strlen(value)); + while (value[unit_pos] == ' ') unit_pos++; - if ( value[unit_pos] == 0 ) { - if ( value_is_zero ) { + if (value[unit_pos] == 0) + { + if (value_is_zero) { /* No matter what unit, 0 remains just that. For convenience, always allow 0 to be specified without a unit */ return 1; - } else if ( def_mult == 0 && err_on_unrecognised ) { - cfg_error(cfgst, "%s: unit is required", value); + } else if (def_mult == 0 && err_on_unrecognised) { + cfg_error (cfgst, "%s: unit is required", value); return 0; } else { -#if WARN_DEPRECATED_UNIT - cfg_warning(cfgst, "%s: use of default unit is deprecated", value); -#endif + cfg_warning (cfgst, "%s: use of default unit is deprecated", value); return def_mult; } - } else { - int i; - for ( i = 0; unittab[i].name != NULL; i++ ) { - if ( strcmp(unittab[i].name, value + unit_pos) == 0 ) + } + else + { + for (int i = 0; unittab[i].name != NULL; i++) + if (strcmp(unittab[i].name, value + unit_pos) == 0) return unittab[i].multiplier; - } - if ( err_on_unrecognised ) + if (err_on_unrecognised) cfg_error(cfgst, "%s: unrecognised unit", value + unit_pos); return 0; } } -static void *cfg_address(UNUSED_ARG(struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem) +static void *cfg_address (UNUSED_ARG (struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem) { - assert(cfgelem->multiplicity == 1); + assert (cfgelem->multiplicity <= 1); return (char *) parent + cfgelem->elem_offset; } -static void *cfg_deref_address(UNUSED_ARG(struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem) +static void *cfg_deref_address (UNUSED_ARG (struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem) { - assert(cfgelem->multiplicity != 1); + assert (cfgelem->multiplicity > 1); return *((void **) ((char *) parent + cfgelem->elem_offset)); } -static void *if_common(UNUSED_ARG(struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem, unsigned size) +static void *if_common (UNUSED_ARG (struct cfgst *cfgst), void *parent, struct cfgelem const * const cfgelem, unsigned size) { struct config_listelem **current = (struct config_listelem **) ((char *) parent + cfgelem->elem_offset); - struct config_listelem *new = ddsrt_malloc(size); + struct config_listelem *new = ddsrt_malloc (size); new->next = *current; *current = new; return new; } -static int if_thread_properties(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_thread_properties (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - struct config_thread_properties_listelem *new = if_common(cfgst, parent, cfgelem, sizeof(*new)); - if ( new == NULL ) + struct config_thread_properties_listelem *new = if_common (cfgst, parent, cfgelem, sizeof(*new)); + if (new == NULL) return -1; new->name = NULL; return 0; @@ -1172,8 +1242,8 @@ static int if_thread_properties(struct cfgst *cfgst, void *parent, struct cfgele #ifdef DDSI_INCLUDE_NETWORK_CHANNELS static int if_channel(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - struct config_channel_listelem *new = if_common(cfgst, parent, cfgelem, sizeof(*new)); - if ( new == NULL ) + struct config_channel_listelem *new = if_common (cfgst, parent, cfgelem, sizeof(*new)); + if (new == NULL) return -1; new->name = NULL; new->channel_reader_ts = NULL; @@ -1186,19 +1256,19 @@ static int if_channel(struct cfgst *cfgst, void *parent, struct cfgelem const * #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ #ifdef DDSI_INCLUDE_ENCRYPTION -static int if_security_profile(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_security_profile (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - if ( if_common(cfgst, parent, cfgelem, sizeof(struct config_securityprofile_listelem)) == NULL ) + if (if_common (cfgst, parent, cfgelem, sizeof (struct config_securityprofile_listelem)) == NULL) return -1; return 0; } #endif /* DDSI_INCLUDE_ENCRYPTION */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -static int if_network_partition(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_network_partition (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - struct config_networkpartition_listelem *new = if_common(cfgst, parent, cfgelem, sizeof(*new)); - if ( new == NULL ) + struct config_networkpartition_listelem *new = if_common (cfgst, parent, cfgelem, sizeof(*new)); + if (new == NULL) return -1; new->address_string = NULL; #ifdef DDSI_INCLUDE_ENCRYPTION @@ -1208,990 +1278,56 @@ static int if_network_partition(struct cfgst *cfgst, void *parent, struct cfgele return 0; } -static int if_ignored_partition(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_ignored_partition (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - if ( if_common(cfgst, parent, cfgelem, sizeof(struct config_ignoredpartition_listelem)) == NULL ) + if (if_common (cfgst, parent, cfgelem, sizeof (struct config_ignoredpartition_listelem)) == NULL) return -1; return 0; } -static int if_partition_mapping(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_partition_mapping (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - if ( if_common(cfgst, parent, cfgelem, sizeof(struct config_partitionmapping_listelem)) == NULL ) + if (if_common (cfgst, parent, cfgelem, sizeof (struct config_partitionmapping_listelem)) == NULL) return -1; return 0; } #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ -static int if_peer(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static int if_peer (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - struct config_peer_listelem *new = if_common(cfgst, parent, cfgelem, sizeof(struct config_peer_listelem)); - if ( new == NULL ) + struct config_peer_listelem *new = if_common (cfgst, parent, cfgelem, sizeof (struct config_peer_listelem)); + if (new == NULL) return -1; new->peer = NULL; return 0; } -static void ff_free(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static void ff_free (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - void **elem = cfg_address(cfgst, parent, cfgelem); - ddsrt_free(*elem); + void ** const elem = cfg_address (cfgst, parent, cfgelem); + ddsrt_free (*elem); } -static int uf_boolean(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) +static void pf_nop (UNUSED_ARG (struct cfgst *cfgst), UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (uint32_t sources)) { - static const char *vs[] = { "false", "true", NULL }; - int *elem = cfg_address(cfgst, parent, cfgelem); - int idx = list_index(vs, value); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - else { - *elem = idx; - return 1; - } } -static int uf_boolean_default (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +static enum update_result do_uint32_bitset (struct cfgst *cfgst, uint32_t *cats, const char **names, const uint32_t *codes, const char *value) { - static const char *vs[] = { "default", "false", "true", NULL }; - static const enum boolean_default ms[] = { - BOOLDEF_DEFAULT, BOOLDEF_FALSE, BOOLDEF_TRUE, 0, - }; - enum boolean_default *elem = cfg_address (cfgst, parent, cfgelem); - int idx = list_index (vs, value); - assert (sizeof (vs) / sizeof (*vs) == sizeof (ms) / sizeof (*ms)); - if (idx < 0) - return cfg_error (cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -#if 0 -static void pf_boolean_default (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum besmode *p = cfg_address (cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch (*p) + char *copy = ddsrt_strdup (value), *cursor = copy, *tok; + while ((tok = ddsrt_strsep (&cursor, ",")) != NULL) { - case BOOLDEF_DEFAULT: str = "default"; break; - case BOOLDEF_FALSE: str = "false"; break; - case BOOLDEF_TRUE: str = "true"; break; - } - cfg_log (cfgst, "%s%s", str, is_default ? " [def]" : ""); -} -#endif - -static int do_uint32_bitset(struct cfgst *cfgst, uint32_t *cats, const char **names, const uint32_t *codes, const char *value) -{ - char *copy = ddsrt_strdup(value), *cursor = copy, *tok; - while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) { - int idx = list_index(names, tok); - if ( idx < 0 ) { - int ret = cfg_error(cfgst, "'%s' in '%s' undefined", tok, value); - ddsrt_free(copy); + const int idx = list_index (names, tok); + if (idx < 0) + { + const enum update_result ret = cfg_error (cfgst, "'%s' in '%s' undefined", tok, value); + ddsrt_free (copy); return ret; } *cats |= codes[idx]; } - ddsrt_free(copy); - return 1; -} - -static int uf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - return do_uint32_bitset (cfgst, &enabled_logcats, logcat_names, logcat_codes, value); -} - -static int uf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - uint32_t *elem = cfg_address(cfgst, parent, cfgelem); - return do_uint32_bitset (cfgst, elem, xcheck_names, xcheck_codes, value); -} - -static int uf_verbosity(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { - "finest", "finer", "fine", "config", "info", "warning", "severe", "none", NULL - }; - static const uint32_t lc[] = { - DDS_LC_ALL, DDS_LC_TRAFFIC | DDS_LC_TIMING, DDS_LC_DISCOVERY | DDS_LC_THROTTLE, DDS_LC_CONFIG, DDS_LC_INFO, DDS_LC_WARNING, DDS_LC_ERROR | DDS_LC_FATAL, 0, 0 - }; - int idx = list_index(vs, value); - assert(sizeof(vs) / sizeof(*vs) == sizeof(lc) / sizeof(*lc)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - else { - int i; - for ( i = (int) (sizeof(vs) / sizeof(*vs)) - 1; i >= idx; i-- ) - enabled_logcats |= lc[i]; - return 1; - } -} - -static int uf_besmode(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { - "full", "writers", "minimal", NULL - }; - static const enum besmode ms[] = { - BESMODE_FULL, BESMODE_WRITERS, BESMODE_MINIMAL, 0, - }; - int idx = list_index(vs, value); - enum besmode *elem = cfg_address(cfgst, parent, cfgelem); - assert(sizeof(vs) / sizeof(*vs) == sizeof(ms) / sizeof(*ms)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_besmode(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum besmode *p = cfg_address(cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch ( *p ) { - case BESMODE_FULL: str = "full"; break; - case BESMODE_WRITERS: str = "writers"; break; - case BESMODE_MINIMAL: str = "minimal"; break; - } - cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -#ifdef DDSI_INCLUDE_SSL -static int uf_min_tls_version(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { - "1.2", "1.3", NULL - }; - static const struct ssl_min_version ms[] = { - {1,2}, {1,3}, {0,0} - }; - int idx = list_index(vs, value); - struct ssl_min_version *elem = cfg_address(cfgst, parent, cfgelem); - assert(sizeof(vs) / sizeof(*vs) == sizeof(ms) / sizeof(*ms)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_min_tls_version(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - struct ssl_min_version *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%d.%d%s", p->major, p->minor, is_default ? " [def]" : ""); -} -#endif - -static int uf_retransmit_merging(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { - "never", "adaptive", "always", NULL - }; - static const enum retransmit_merging ms[] = { - REXMIT_MERGE_NEVER, REXMIT_MERGE_ADAPTIVE, REXMIT_MERGE_ALWAYS, 0, - }; - int idx = list_index(vs, value); - enum retransmit_merging *elem = cfg_address(cfgst, parent, cfgelem); - assert(sizeof(vs) / sizeof(*vs) == sizeof(ms) / sizeof(*ms)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_retransmit_merging(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum retransmit_merging *p = cfg_address(cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch ( *p ) { - case REXMIT_MERGE_NEVER: str = "never"; break; - case REXMIT_MERGE_ADAPTIVE: str = "adaptive"; break; - case REXMIT_MERGE_ALWAYS: str = "always"; break; - } - cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -static int uf_string(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - char **elem = cfg_address(cfgst, parent, cfgelem); - *elem = ddsrt_strdup(value); - return 1; -} - -DDSRT_WARNING_MSVC_OFF(4996); -static int uf_natint64_unit(struct cfgst *cfgst, int64_t *elem, const char *value, const struct unit *unittab, int64_t def_mult, int64_t min, int64_t max) -{ - int pos; - double v_dbl; - int64_t v_int; - int64_t mult; - /* try convert as integer + optional unit; if that fails, try - floating point + optional unit (round, not truncate, to integer) */ - if ( *value == 0 ) { - *elem = 0; /* some static analyzers don't "get it" */ - return cfg_error(cfgst, "%s: empty string is not a valid value", value); - } else if ( sscanf(value, "%lld%n", (long long int *) &v_int, &pos) == 1 && (mult = lookup_multiplier(cfgst, unittab, value, pos, v_int == 0, def_mult, 0)) != 0 ) { - assert(mult > 0); - if ( v_int < 0 || v_int > max / mult || mult * v_int < min) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = mult * v_int; - return 1; - } else if ( sscanf(value, "%lf%n", &v_dbl, &pos) == 1 && (mult = lookup_multiplier(cfgst, unittab, value, pos, v_dbl == 0, def_mult, 1)) != 0 ) { - double dmult = (double) mult; - assert(dmult > 0); - if ( (int64_t) (v_dbl * dmult + 0.5) < min || (int64_t) (v_dbl * dmult + 0.5) > max ) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = (int64_t) (v_dbl * dmult + 0.5); - return 1; - } else { - *elem = 0; /* some static analyzers don't "get it" */ - return cfg_error(cfgst, "%s: invalid value", value); - } -} -DDSRT_WARNING_MSVC_ON(4996); - -#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING -static int uf_bandwidth(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - int64_t bandwidth_bps = 0; - if ( strncmp(value, "inf", 3) == 0 ) { - /* special case: inf needs no unit */ - int *elem = cfg_address(cfgst, parent, cfgelem); - if ( strspn(value + 3, " ") != strlen(value + 3) && - lookup_multiplier(cfgst, unittab_bandwidth_bps, value, 3, 1, 8, 1) == 0 ) - return 0; - *elem = 0; - return 1; - } else if ( !uf_natint64_unit(cfgst, &bandwidth_bps, value, unittab_bandwidth_bps, 8, INT64_MAX) ) { - return 0; - } else if ( bandwidth_bps / 8 > INT_MAX ) { - return cfg_error(cfgst, "%s: value out of range", value); - } else { - uint32_t *elem = cfg_address(cfgst, parent, cfgelem); - *elem = (uint32_t) (bandwidth_bps / 8); - return 1; - } -} -#endif - -static int uf_memsize(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - int64_t size = 0; - if ( !uf_natint64_unit(cfgst, &size, value, unittab_memsize, 1, 0, INT32_MAX) ) - return 0; - else { - uint32_t *elem = cfg_address(cfgst, parent, cfgelem); - *elem = (uint32_t) size; - return 1; - } -} - -#ifdef DDSI_INCLUDE_ENCRYPTION -static int uf_cipher(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - if ( q_security_plugin.cipher_type_from_string ) { - q_cipherType *elem = cfg_address(cfgst, parent, cfgelem); - if ( (q_security_plugin.cipher_type_from_string) (value, elem) ) { - return 1; - } else { - return cfg_error(cfgst, "%s: undefined value", value); - } - } - return 1; -} -#endif /* DDSI_INCLUDE_ENCRYPTION */ - - -static int uf_tracingOutputFileName(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) -{ - struct config *cfg = cfgst->cfg; - { - cfg->tracingOutputFileName = ddsrt_strdup(value); - } - return 1; -} - -static int uf_ipv4(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - /* Not actually doing any checking yet */ - return uf_string(cfgst, parent, cfgelem, first, value); -} - -static int uf_networkAddress(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - if ( ddsrt_strcasecmp(value, "auto") != 0 ) - return uf_ipv4(cfgst, parent, cfgelem, first, value); - else { - char **elem = cfg_address(cfgst, parent, cfgelem); - *elem = NULL; - return 1; - } -} - -static void ff_networkAddresses(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) -{ - char ***elem = cfg_address(cfgst, parent, cfgelem); - int i; - for ( i = 0; (*elem)[i]; i++ ) - ddsrt_free((*elem)[i]); - ddsrt_free(*elem); -} - -static int uf_networkAddresses_simple(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - char ***elem = cfg_address(cfgst, parent, cfgelem); - if ( (*elem = ddsrt_malloc(2 * sizeof(char *))) == NULL ) - return cfg_error(cfgst, "out of memory"); - if ( ((*elem)[0] = ddsrt_strdup(value)) == NULL ) { - ddsrt_free(*elem); - *elem = NULL; - return cfg_error(cfgst, "out of memory"); - } - (*elem)[1] = NULL; - return 1; -} - -static int uf_networkAddresses(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - /* Check for keywords first */ - { - static const char *keywords[] = { "all", "any", "none" }; - int i; - for ( i = 0; i < (int) (sizeof(keywords) / sizeof(*keywords)); i++ ) { - if ( ddsrt_strcasecmp(value, keywords[i]) == 0 ) - return uf_networkAddresses_simple(cfgst, parent, cfgelem, first, keywords[i]); - } - } - - /* If not keyword, then comma-separated list of addresses */ - { - char ***elem = cfg_address(cfgst, parent, cfgelem); - char *copy; - unsigned count; - - /* First count how many addresses we have - but do it stupidly by - counting commas and adding one (so two commas in a row are both - counted) */ - { - const char *scan = value; - count = 1; - while ( *scan ) - count += (*scan++ == ','); - } - - copy = ddsrt_strdup(value); - - /* Allocate an array of address strings (which may be oversized a - bit because of the counting of the commas) */ - *elem = ddsrt_malloc((count + 1) * sizeof(char *)); - - { - char *cursor = copy, *tok; - unsigned idx = 0; - while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) { - assert(idx < count); - (*elem)[idx] = ddsrt_strdup(tok); - idx++; - } - (*elem)[idx] = NULL; - } - ddsrt_free(copy); - } - return 1; -} - -static int uf_allow_multicast(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ -#ifdef DDSI_INCLUDE_SSM - static const char *vs[] = { "false", "spdp", "asm", "ssm", "true", NULL }; - static const unsigned bs[] = { AMC_FALSE, AMC_SPDP, AMC_ASM, AMC_SSM, AMC_TRUE }; -#else - static const char *vs[] = { "false", "spdp", "asm", "true", NULL }; - static const unsigned bs[] = { AMC_FALSE, AMC_SPDP, AMC_ASM, AMC_TRUE }; -#endif - char *copy = ddsrt_strdup(value), *cursor = copy, *tok; - unsigned *elem = cfg_address(cfgst, parent, cfgelem); - if ( copy == NULL ) - return cfg_error(cfgst, "out of memory"); - *elem = 0; - while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) { - int idx = list_index(vs, tok); - if ( idx < 0 ) { - int ret = cfg_error(cfgst, "'%s' in '%s' undefined", tok, value); - ddsrt_free(copy); - return ret; - } - *elem |= bs[idx]; - } - ddsrt_free(copy); - return 1; -} - -static void pf_allow_multicast(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - unsigned *p = cfg_address(cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch ( *p ) { - case AMC_FALSE: str = "false"; break; - case AMC_SPDP: str = "spdp"; break; - case AMC_ASM: str = "asm"; break; -#ifdef DDSI_INCLUDE_SSM - case AMC_SSM: str = "ssm"; break; - case (AMC_SPDP | AMC_ASM): str = "spdp,asm"; break; - case (AMC_SPDP | AMC_SSM): str = "spdp,ssm"; break; -#endif - case AMC_TRUE: str = "true"; break; - } - cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -static int uf_sched_class(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { "realtime", "timeshare", "default" }; - static const ddsrt_sched_t ms[] = { DDSRT_SCHED_REALTIME, DDSRT_SCHED_TIMESHARE, DDSRT_SCHED_DEFAULT }; - int idx = list_index(vs, value); - ddsrt_sched_t *elem = cfg_address(cfgst, parent, cfgelem); - assert(sizeof(vs) / sizeof(*vs) == sizeof(ms) / sizeof(*ms)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_sched_class(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - ddsrt_sched_t *p = cfg_address(cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch ( *p ) { - case DDSRT_SCHED_DEFAULT: str = "default"; break; - case DDSRT_SCHED_TIMESHARE: str = "timeshare"; break; - case DDSRT_SCHED_REALTIME: str = "realtime"; break; - } - cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -DDSRT_WARNING_MSVC_OFF(4996); -static int uf_maybe_int32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - struct config_maybe_int32 *elem = cfg_address(cfgst, parent, cfgelem); - int pos; - if ( ddsrt_strcasecmp(value, "default") == 0 ) { - elem->isdefault = 1; - elem->value = 0; - return 1; - } else if ( sscanf(value, "%"PRId32"%n", &elem->value, &pos) == 1 && value[pos] == 0 ) { - elem->isdefault = 0; - return 1; - } else { - return cfg_error(cfgst, "'%s': neither 'default' nor a decimal integer\n", value); - } -} -DDSRT_WARNING_MSVC_ON(4996); - -static int uf_maybe_memsize(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - struct config_maybe_uint32 *elem = cfg_address(cfgst, parent, cfgelem); - int64_t size = 0; - if ( ddsrt_strcasecmp(value, "default") == 0 ) { - elem->isdefault = 1; - elem->value = 0; - return 1; - } else if ( !uf_natint64_unit(cfgst, &size, value, unittab_memsize, 1, 0, INT32_MAX) ) { - return 0; - } else { - elem->isdefault = 0; - elem->value = (uint32_t) size; - return 1; - } -} - -static int uf_int(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - int *elem = cfg_address(cfgst, parent, cfgelem); - char *endptr; - long v = strtol(value, &endptr, 10); - if ( *value == 0 || *endptr != 0 ) - return cfg_error(cfgst, "%s: not a decimal integer", value); - if ( v != (int) v ) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = (int) v; - return 1; -} - -static int uf_duration_gen(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, const char *value, int64_t def_mult, int64_t min_ns, int64_t max_ns) -{ - return uf_natint64_unit(cfgst, cfg_address(cfgst, parent, cfgelem), value, unittab_duration, def_mult, min_ns, max_ns); -} - -static int uf_duration_inf(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - if ( ddsrt_strcasecmp(value, "inf") == 0 ) { - int64_t *elem = cfg_address(cfgst, parent, cfgelem); - *elem = T_NEVER; - return 1; - } else { - return uf_duration_gen(cfgst, parent, cfgelem, value, 0, 0, T_NEVER - 1); - } -} - -static int uf_duration_ms_1hr(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - return uf_duration_gen(cfgst, parent, cfgelem, value, T_MILLISECOND, 0, 3600 * T_SECOND); -} - -static int uf_duration_ms_1s(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - return uf_duration_gen(cfgst, parent, cfgelem, value, T_MILLISECOND, 0, T_SECOND); -} - -static int uf_duration_us_1s(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - return uf_duration_gen(cfgst, parent, cfgelem, value, 1000, 0, T_SECOND); -} - -static int uf_duration_100ms_1hr(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - return uf_duration_gen(cfgst, parent, cfgelem, value, 0, 100 * T_MILLISECOND, 3600 * T_SECOND); -} - -#if 0 -static int uf_int32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - int32_t *elem = cfg_address(cfgst, parent, cfgelem); - char *endptr; - long v = strtol(value, &endptr, 10); - if ( *value == 0 || *endptr != 0 ) - return cfg_error(cfgst, "%s: not a decimal integer", value); - if ( v != (int32_t) v ) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = (int32_t) v; - return 1; -} -#endif - -#if 0 -static int uf_uint32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - uint32_t *elem = cfg_address(cfgst, parent, cfgelem); - char *endptr; - unsigned long v = strtoul(value, &endptr, 10); - if ( *value == 0 || *endptr != 0 ) - return cfg_error(cfgst, "%s: not a decimal integer", value); - if ( v != (uint32_t) v ) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = (uint32_t) v; - return 1; -} -#endif - -static int uf_uint(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - unsigned *elem = cfg_address(cfgst, parent, cfgelem); - char *endptr; - unsigned long v = strtoul(value, &endptr, 10); - if ( *value == 0 || *endptr != 0 ) - return cfg_error(cfgst, "%s: not a decimal integer", value); - if ( v != (unsigned) v ) - return cfg_error(cfgst, "%s: value out of range", value); - *elem = (unsigned) v; - return 1; -} - -static int uf_int_min_max(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value, int min, int max) -{ - int *elem = cfg_address(cfgst, parent, cfgelem); - if ( !uf_int(cfgst, parent, cfgelem, first, value) ) - return 0; - else if ( *elem < min || *elem > max ) - return cfg_error(cfgst, "%s: out of range", value); - else - return 1; -} - -DDSRT_WARNING_MSVC_OFF(4996); -static int uf_domainId(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - struct config_maybe_int32 *elem = cfg_address(cfgst, parent, cfgelem); - int pos; - if (ddsrt_strcasecmp(value, "any") == 0) { - elem->isdefault = 1; - elem->value = 0; - return 1; - } else if (sscanf(value, "%"PRId32"%n", &elem->value, &pos) == 1 && value[pos] == 0 && elem->value >= 0 && elem->value <= 230) { - elem->isdefault = 0; - return 1; - } else { - return cfg_error(cfgst, "'%s': neither 'any' nor a decimal integer in 0 .. 230\n", value); - } -} -DDSRT_WARNING_MSVC_ON(4996); - -static int uf_participantIndex(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - int *elem = cfg_address(cfgst, parent, cfgelem); - if ( ddsrt_strcasecmp(value, "auto") == 0 ) { - *elem = PARTICIPANT_INDEX_AUTO; - return 1; - } else if ( ddsrt_strcasecmp(value, "none") == 0 ) { - *elem = PARTICIPANT_INDEX_NONE; - return 1; - } else { - return uf_int_min_max(cfgst, parent, cfgelem, first, value, 0, 120); - } -} - -static int uf_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - return uf_int_min_max(cfgst, parent, cfgelem, first, value, 1, 65535); -} - -static int uf_dyn_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - return uf_int_min_max(cfgst, parent, cfgelem, first, value, -1, 65535); -} - -static int uf_natint(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - return uf_int_min_max(cfgst, parent, cfgelem, first, value, 0, INT32_MAX); -} - -static int uf_natint_255(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - return uf_int_min_max(cfgst, parent, cfgelem, first, value, 0, 255); -} - -static int uf_transport_selector (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) -{ - static const char *vs[] = { "default", "udp", "udp6", "tcp", "tcp6", "raweth", NULL }; - static const enum transport_selector ms[] = { - TRANS_DEFAULT, TRANS_UDP, TRANS_UDP6, TRANS_TCP, TRANS_TCP6, TRANS_RAWETH, 0, - }; - enum transport_selector *elem = cfg_address (cfgst, parent, cfgelem); - int idx = list_index (vs, value); - assert (sizeof (vs) / sizeof (*vs) == sizeof (ms) / sizeof (*ms)); - if (idx < 0) - return cfg_error (cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_transport_selector (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum transport_selector *p = cfg_address (cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch (*p) - { - case TRANS_DEFAULT: str = "default"; break; - case TRANS_UDP: str = "udp"; break; - case TRANS_UDP6: str = "udp6"; break; - case TRANS_TCP: str = "tcp"; break; - case TRANS_TCP6: str = "tcp6"; break; - case TRANS_RAWETH: str = "raweth"; break; - } - cfg_log (cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -static int uf_many_sockets_mode (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) -{ - static const char *vs[] = { "false", "true", "single", "none", "many", NULL }; - static const enum many_sockets_mode ms[] = { - MSM_SINGLE_UNICAST, MSM_MANY_UNICAST, MSM_SINGLE_UNICAST, MSM_NO_UNICAST, MSM_MANY_UNICAST, 0, - }; - enum many_sockets_mode *elem = cfg_address (cfgst, parent, cfgelem); - int idx = list_index (vs, value); - assert (sizeof (vs) / sizeof (*vs) == sizeof (ms) / sizeof (*ms)); - if (idx < 0) - return cfg_error (cfgst, "'%s': undefined value", value); - *elem = ms[idx]; - return 1; -} - -static void pf_many_sockets_mode (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum many_sockets_mode *p = cfg_address (cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch (*p) - { - case MSM_SINGLE_UNICAST: str = "single"; break; - case MSM_MANY_UNICAST: str = "many"; break; - case MSM_NO_UNICAST: str = "none"; break; - } - cfg_log (cfgst, "%s%s", str, is_default ? " [def]" : ""); -} - -static int uf_deaf_mute (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) -{ - return uf_boolean (cfgst, parent, cfgelem, first, value); -} - -static int do_update(struct cfgst *cfgst, update_fun_t upd, void *parent, struct cfgelem const * const cfgelem, const char *value, int is_default) -{ - struct cfgst_node *n; - struct cfgst_nodekey key; - ddsrt_avl_ipath_t np; - int ok; - key.e = cfgelem; - if ( (n = ddsrt_avl_lookup_ipath(&cfgst_found_treedef, &cfgst->found, &key, &np)) == NULL ) { - if ( (n = ddsrt_malloc(sizeof(*n))) == NULL ) - return cfg_error(cfgst, "out of memory"); - - n->key = key; - n->count = 0; - n->failed = 0; - n->is_default = is_default; - ddsrt_avl_insert_ipath(&cfgst_found_treedef, &cfgst->found, n, &np); - } - if ( cfgelem->multiplicity == 0 || n->count < cfgelem->multiplicity ) - ok = upd(cfgst, parent, cfgelem, (n->count == n->failed), value); - else - ok = cfg_error(cfgst, "only %d instance%s allowed", cfgelem->multiplicity, (cfgelem->multiplicity == 1) ? "" : "s"); - n->count++; - if ( !ok ) { - n->failed++; - } - return ok; -} - -static int set_default(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) -{ - if ( cfgelem->defvalue == NULL ) - return cfg_error(cfgst, "element missing in configuration"); - return do_update(cfgst, cfgelem->update, parent, cfgelem, cfgelem->defvalue, 1); -} - -static int set_defaults(struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem, int clear_found) -{ - const struct cfgelem *ce; - int ok = 1; - for ( ce = cfgelem; ce && ce->name; ce++ ) { - struct cfgst_node *n; - struct cfgst_nodekey key; - key.e = ce; - cfgst_push(cfgst, isattr, ce, parent); - if ( ce->multiplicity == 1 ) { - if ( ddsrt_avl_lookup(&cfgst_found_treedef, &cfgst->found, &key) == NULL ) { - if ( ce->update ) { - int ok1; - cfgst_push(cfgst, 0, NULL, NULL); - ok1 = set_default(cfgst, parent, ce); - cfgst_pop(cfgst); - ok = ok && ok1; - } - } - if ( (n = ddsrt_avl_lookup(&cfgst_found_treedef, &cfgst->found, &key)) != NULL ) { - if ( clear_found ) { - ddsrt_avl_delete(&cfgst_found_treedef, &cfgst->found, n); - ddsrt_free(n); - } - } - if ( ce->children ) { - int ok1 = set_defaults(cfgst, parent, 0, ce->children, clear_found); - ok = ok && ok1; - } - if ( ce->attributes ) { - int ok1 = set_defaults(cfgst, parent, 1, ce->attributes, clear_found); - ok = ok && ok1; - } - } - cfgst_pop(cfgst); - } - return ok; -} - -static void pf_nop(UNUSED_ARG(struct cfgst *cfgst), UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default)) -{ -} - -static void pf_string(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - char **p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%s%s", *p ? *p : "(null)", is_default ? " [def]" : ""); -} - -static void pf_int64_unit(struct cfgst *cfgst, int64_t value, int is_default, const struct unit *unittab, const char *zero_unit) -{ - if ( value == 0 ) { - /* 0s is a bit of a special case: we don't want to print 0hr (or - whatever unit will have the greatest multiplier), so hard-code - as 0s */ - cfg_log(cfgst, "0 %s%s", zero_unit, is_default ? " [def]" : ""); - } else { - int64_t m = 0; - const char *unit = NULL; - int i; - for ( i = 0; unittab[i].name != NULL; i++ ) { - if ( unittab[i].multiplier > m && (value % unittab[i].multiplier) == 0 ) { - m = unittab[i].multiplier; - unit = unittab[i].name; - } - } - assert(m > 0); - assert(unit != NULL); - cfg_log(cfgst, "%lld %s%s", value / m, unit, is_default ? " [def]" : ""); - } -} - -#ifdef DDSI_INCLUDE_ENCRYPTION -static void pf_key(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default)) -{ - cfg_log(cfgst, ""); -} - -static void pf_cipher(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - q_cipherType *p = cfg_address(cfgst, parent, cfgelem); - if ( q_security_plugin.cipher_type ) { - cfg_log(cfgst, "%s%s", (q_security_plugin.cipher_type) (*p), is_default ? " [def]" : ""); - } -} -#endif /* DDSI_INCLUDE_ENCRYPTION */ - -static void pf_networkAddress(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - char **p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%s%s", *p ? *p : "auto", is_default ? " [def]" : ""); -} - -static void pf_participantIndex(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - int *p = cfg_address(cfgst, parent, cfgelem); - switch ( *p ) { - case PARTICIPANT_INDEX_NONE: - cfg_log(cfgst, "none%s", is_default ? " [def]" : ""); - break; - case PARTICIPANT_INDEX_AUTO: - cfg_log(cfgst, "auto%s", is_default ? " [def]" : ""); - break; - default: - cfg_log(cfgst, "%d%s", *p, is_default ? " [def]" : ""); - break; - } -} - -static void pf_networkAddresses(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - int i; - char ***p = cfg_address(cfgst, parent, cfgelem); - for ( i = 0; (*p)[i] != NULL; i++ ) - cfg_log(cfgst, "%s%s", (*p)[i], is_default ? " [def]" : ""); -} - -static void pf_int(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - int *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%d%s", *p, is_default ? " [def]" : ""); -} - -static void pf_uint(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - unsigned *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%u%s", *p, is_default ? " [def]" : ""); -} - -static void pf_duration(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - const int64_t *elem = cfg_address(cfgst, parent, cfgelem); - if ( *elem == T_NEVER ) - cfg_log(cfgst, "inf%s", is_default ? " [def]" : ""); - else - pf_int64_unit(cfgst, *elem, is_default, unittab_duration, "s"); -} - -#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING -static void pf_bandwidth(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - const uint32_t *elem = cfg_address(cfgst, parent, cfgelem); - if ( *elem == 0 ) - cfg_log(cfgst, "inf%s", is_default ? " [def]" : ""); - else - pf_int64_unit(cfgst, *elem, is_default, unittab_bandwidth_Bps, "B/s"); -} -#endif - -static void pf_memsize(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - const int *elem = cfg_address(cfgst, parent, cfgelem); - pf_int64_unit(cfgst, *elem, is_default, unittab_memsize, "B"); -} - -#if 0 -static void pf_int32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - int32_t *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%d%s", *p, is_default ? " [def]" : ""); -} -#endif - -#if 0 -static void pf_uint32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - uint32_t *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%u%s", *p, is_default ? " [def]" : ""); -} -#endif - -static void pf_maybe_int32(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - struct config_maybe_int32 *p = cfg_address(cfgst, parent, cfgelem); - if ( p->isdefault ) - cfg_log(cfgst, "default%s", is_default ? " [def]" : ""); - else - cfg_log(cfgst, "%d%s", p->value, is_default ? " [def]" : ""); -} - -static void pf_maybe_memsize(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - struct config_maybe_uint32 *p = cfg_address(cfgst, parent, cfgelem); - if ( p->isdefault ) - cfg_log(cfgst, "default%s", is_default ? " [def]" : ""); - else - pf_int64_unit(cfgst, p->value, is_default, unittab_memsize, "B"); -} - -static void pf_domainId(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - struct config_maybe_int32 *p = cfg_address(cfgst, parent, cfgelem); - if ( p->isdefault ) - cfg_log(cfgst, "any (%d)%s", p->value, is_default ? " [def]" : ""); - else - cfg_log(cfgst, "%d%s", p->value, is_default ? " [def]" : ""); -} - -static void pf_boolean(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - int *p = cfg_address(cfgst, parent, cfgelem); - cfg_log(cfgst, "%s%s", *p ? "true" : "false", is_default ? " [def]" : ""); -} - -static int uf_standards_conformance(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - static const char *vs[] = { - "pedantic", "strict", "lax", NULL - }; - static const uint32_t lc[] = { - NN_SC_PEDANTIC, NN_SC_STRICT, NN_SC_LAX, 0 - }; - enum nn_standards_conformance *elem = cfg_address(cfgst, parent, cfgelem); - int idx = list_index(vs, value); - assert(sizeof(vs) / sizeof(*vs) == sizeof(lc) / sizeof(*lc)); - if ( idx < 0 ) - return cfg_error(cfgst, "'%s': undefined value", value); - else { - *elem = lc[idx]; - return 1; - } -} - -static void pf_standards_conformance(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) -{ - enum nn_standards_conformance *p = cfg_address(cfgst, parent, cfgelem); - const char *str = "INVALID"; - switch ( *p ) { - case NN_SC_PEDANTIC: str = "pedantic"; break; - case NN_SC_STRICT: str = "strict"; break; - case NN_SC_LAX: str = "lax"; break; - } - cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); + ddsrt_free (copy); + return URES_SUCCESS; } static unsigned uint32_popcnt (uint32_t x) @@ -2205,376 +1341,1262 @@ static unsigned uint32_popcnt (uint32_t x) return n; } -static void do_print_uint32_bitset (struct cfgst *cfgst, uint32_t mask, size_t ncodes, const char **names, const uint32_t *codes, const char *suffix) +static void do_print_uint32_bitset (struct cfgst *cfgst, uint32_t mask, size_t ncodes, const char **names, const uint32_t *codes, uint32_t sources, const char *suffix) { char res[256] = "", *resp = res; const char *prefix = ""; #ifndef NDEBUG { size_t max = 0; - for (size_t i = 0; i < ncodes; i++ ) - max += 1 + strlen(names[i]); + for (size_t i = 0; i < ncodes; i++) + max += 1 + strlen (names[i]); max += 11; /* ,0x%x */ max += 1; /* \0 */ - assert(max <= sizeof(res)); + assert (max <= sizeof (res)); } #endif - while (mask) { + while (mask) + { size_t i_best = 0; unsigned pc_best = 0; - for (size_t i = 0; i < ncodes; i++) { + for (size_t i = 0; i < ncodes; i++) + { uint32_t m = mask & codes[i]; - if (m == codes[i]) { + if (m == codes[i]) + { unsigned pc = uint32_popcnt (m); - if (pc > pc_best) { + if (pc > pc_best) + { i_best = i; pc_best = pc; } } } - if (pc_best != 0) { - resp += snprintf(resp, 256, "%s%s", prefix, names[i_best]); + if (pc_best != 0) + { + resp += snprintf (resp, 256, "%s%s", prefix, names[i_best]); mask &= ~codes[i_best]; prefix = ","; - } else { + } + else + { resp += snprintf (resp, 256, "%s0x%x", prefix, (unsigned) mask); mask = 0; } } - assert (resp <= res + sizeof(res)); - cfg_log (cfgst, "%s%s", res, suffix); + assert (resp <= res + sizeof (res)); + cfg_logelem (cfgst, sources, "%s%s", res, suffix); } -static void pf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default)) +static enum update_result uf_natint64_unit(struct cfgst *cfgst, int64_t *elem, const char *value, const struct unit *unittab, int64_t def_mult, int64_t min, int64_t max) { - /* can't do default indicator: user may have specified Verbosity, in - which case EnableCategory is at default, but for these two - settings, I don't mind. */ - do_print_uint32_bitset (cfgst, config.enabled_logcats, sizeof(logcat_codes) / sizeof(*logcat_codes), logcat_names, logcat_codes, ""); + DDSRT_WARNING_MSVC_OFF(4996); + int pos; + double v_dbl; + int64_t v_int; + int64_t mult; + /* try convert as integer + optional unit; if that fails, try + floating point + optional unit (round, not truncate, to integer) */ + if (*value == 0) { + *elem = 0; /* some static analyzers don't "get it" */ + return cfg_error(cfgst, "%s: empty string is not a valid value", value); + } else if (sscanf (value, "%lld%n", (long long int *) &v_int, &pos) == 1 && (mult = lookup_multiplier (cfgst, unittab, value, pos, v_int == 0, def_mult, 0)) != 0) { + assert(mult > 0); + if (v_int < 0 || v_int > max / mult || mult * v_int < min) + return cfg_error (cfgst, "%s: value out of range", value); + *elem = mult * v_int; + return URES_SUCCESS; + } else if (sscanf(value, "%lf%n", &v_dbl, &pos) == 1 && (mult = lookup_multiplier (cfgst, unittab, value, pos, v_dbl == 0, def_mult, 1)) != 0) { + double dmult = (double) mult; + assert (dmult > 0); + if ((int64_t) (v_dbl * dmult + 0.5) < min || (int64_t) (v_dbl * dmult + 0.5) > max) + return cfg_error(cfgst, "%s: value out of range", value); + *elem = (int64_t) (v_dbl * dmult + 0.5); + return URES_SUCCESS; + } else { + *elem = 0; /* some static analyzers don't "get it" */ + return cfg_error (cfgst, "%s: invalid value", value); + } + DDSRT_WARNING_MSVC_ON(4996); } -static void pf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) +static void pf_int64_unit (struct cfgst *cfgst, int64_t value, uint32_t sources, const struct unit *unittab, const char *zero_unit) { - const uint32_t *p = cfg_address(cfgst, parent, cfgelem); + if (value == 0) { + /* 0s is a bit of a special case: we don't want to print 0hr (or + whatever unit will have the greatest multiplier), so hard-code + as 0s */ + cfg_logelem (cfgst, sources, "0 %s", zero_unit); + } else { + int64_t m = 0; + const char *unit = NULL; + int i; + for (i = 0; unittab[i].name != NULL; i++) + { + if (unittab[i].multiplier > m && (value % unittab[i].multiplier) == 0) + { + m = unittab[i].multiplier; + unit = unittab[i].name; + } + } + assert (m > 0); + assert (unit != NULL); + cfg_logelem (cfgst, sources, "%lld %s", value / m, unit); + } +} + +#define GENERIC_ENUM_CTYPE_UF(type_, c_type_) \ + DDSRT_STATIC_ASSERT (sizeof (en_##type_##_vs) / sizeof (*en_##type_##_vs) == \ + sizeof (en_##type_##_ms) / sizeof (*en_##type_##_ms)); \ + \ + static enum update_result uf_##type_ (struct cfgst *cfgst, void *parent, UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) \ + { \ + const int idx = list_index (en_##type_##_vs, value); \ + c_type_ * const elem = cfg_address (cfgst, parent, cfgelem); \ + /* idx >= length of ms check is to shut up clang's static analyzer */ \ + if (idx < 0 || idx >= (int) (sizeof (en_##type_##_ms) / sizeof (en_##type_##_ms[0]))) \ + return cfg_error (cfgst, "'%s': undefined value", value); \ + *elem = en_##type_##_ms[idx]; \ + return URES_SUCCESS; \ + } +#define GENERIC_ENUM_CTYPE_PF(type_, c_type_) \ + static void pf_##type_ (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) \ + { \ + c_type_ const * const p = cfg_address (cfgst, parent, cfgelem); \ + const char *str = "INVALID"; \ + /* i < length of ms check is to shut up clang's static analyzer */ \ + for (int i = 0; en_##type_##_vs[i] != NULL && i < (int) (sizeof (en_##type_##_ms) / sizeof (en_##type_##_ms[0])); i++) { \ + if (en_##type_##_ms[i] == *p) \ + { \ + str = en_##type_##_vs[i]; \ + break; \ + } \ + } \ + cfg_logelem(cfgst, sources, "%s", str); \ + } +#define GENERIC_ENUM_CTYPE(type_, c_type_) \ + GENERIC_ENUM_CTYPE_UF(type_, c_type_) \ + GENERIC_ENUM_CTYPE_PF(type_, c_type_) +#define GENERIC_ENUM_UF(type_) GENERIC_ENUM_CTYPE_UF(type_, enum type_) +#define GENERIC_ENUM(type_) GENERIC_ENUM_CTYPE(type_, enum type_) + +static const char *en_boolean_vs[] = { "false", "true", NULL }; +static const int en_boolean_ms[] = { 0, 1, 0 }; +GENERIC_ENUM_CTYPE (boolean, int) + +static const char *en_boolean_default_vs[] = { "default", "false", "true", NULL }; +static const enum boolean_default en_boolean_default_ms[] = { BOOLDEF_DEFAULT, BOOLDEF_FALSE, BOOLDEF_TRUE, 0 }; +GENERIC_ENUM_UF (boolean_default) + +static const char *en_besmode_vs[] = { "full", "writers", "minimal", NULL }; +static const enum besmode en_besmode_ms[] = { BESMODE_FULL, BESMODE_WRITERS, BESMODE_MINIMAL, 0 }; +GENERIC_ENUM (besmode) + +static const char *en_retransmit_merging_vs[] = { "never", "adaptive", "always", NULL }; +static const enum retransmit_merging en_retransmit_merging_ms[] = { REXMIT_MERGE_NEVER, REXMIT_MERGE_ADAPTIVE, REXMIT_MERGE_ALWAYS, 0 }; +GENERIC_ENUM (retransmit_merging) + +static const char *en_sched_class_vs[] = { "realtime", "timeshare", "default", NULL }; +static const ddsrt_sched_t en_sched_class_ms[] = { DDSRT_SCHED_REALTIME, DDSRT_SCHED_TIMESHARE, DDSRT_SCHED_DEFAULT, 0 }; +GENERIC_ENUM_CTYPE (sched_class, ddsrt_sched_t) + +static const char *en_transport_selector_vs[] = { "default", "udp", "udp6", "tcp", "tcp6", "raweth", NULL }; +static const enum transport_selector en_transport_selector_ms[] = { TRANS_DEFAULT, TRANS_UDP, TRANS_UDP6, TRANS_TCP, TRANS_TCP6, TRANS_RAWETH, 0 }; +GENERIC_ENUM (transport_selector) + +/* by putting the "true" and "false" aliases at the end, they won't come out of the + generic printing function */ +static const char *en_many_sockets_mode_vs[] = { "single", "none", "many", "false", "true", NULL }; +static const enum many_sockets_mode en_many_sockets_mode_ms[] = { + MSM_SINGLE_UNICAST, MSM_NO_UNICAST, MSM_MANY_UNICAST, MSM_SINGLE_UNICAST, MSM_MANY_UNICAST, 0 }; +GENERIC_ENUM (many_sockets_mode) + +static const char *en_standards_conformance_vs[] = { "pedantic", "strict", "lax", NULL }; +static const enum nn_standards_conformance en_standards_conformance_ms[] = { NN_SC_PEDANTIC, NN_SC_STRICT, NN_SC_LAX, 0 }; +GENERIC_ENUM_CTYPE (standards_conformance, enum nn_standards_conformance) + +/* "trace" is special: it enables (nearly) everything */ +static const char *tracemask_names[] = { + "fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "trace", NULL +}; +static const uint32_t tracemask_codes[] = { + DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL +}; + +static enum update_result uf_tracemask (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) +{ + return do_uint32_bitset (cfgst, &cfgst->cfg->tracemask, tracemask_names, tracemask_codes, value); +} + +static enum update_result uf_verbosity (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) +{ + static const char *vs[] = { + "finest", "finer", "fine", "config", "info", "warning", "severe", "none", NULL + }; + static const uint32_t lc[] = { + DDS_LC_ALL, DDS_LC_TRAFFIC | DDS_LC_TIMING, DDS_LC_DISCOVERY | DDS_LC_THROTTLE, DDS_LC_CONFIG, DDS_LC_INFO, DDS_LC_WARNING, DDS_LC_ERROR | DDS_LC_FATAL, 0, 0 + }; + const int idx = list_index (vs, value); + assert (sizeof (vs) / sizeof (*vs) == sizeof (lc) / sizeof (*lc)); + if (idx < 0) + return cfg_error (cfgst, "'%s': undefined value", value); + for (int i = (int) (sizeof (vs) / sizeof (*vs)) - 1; i >= idx; i--) + cfgst->cfg->tracemask |= lc[i]; + return URES_SUCCESS; +} + +static void pf_tracemask (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), uint32_t sources) +{ + /* EnableCategory is also (and often) set by Verbosity, so make an effort to locate the sources for verbosity and merge them in */ + struct cfgst_node *n; + struct cfgst_nodekey key; + bool isattr; + key.e = lookup_element ("CycloneDDS/Domain/Tracing/Verbosity", &isattr); + key.p = NULL; + assert (key.e != NULL); + if ((n = ddsrt_avl_lookup_succ_eq (&cfgst_found_treedef, &cfgst->found, &key)) != NULL && n->key.e == key.e) + sources |= n->sources; + do_print_uint32_bitset (cfgst, cfgst->cfg->tracemask, sizeof (tracemask_codes) / sizeof (*tracemask_codes), tracemask_names, tracemask_codes, sources, ""); +} + +static const char *xcheck_names[] = { + "whc", "rhc", "all", NULL +}; +static const uint32_t xcheck_codes[] = { + DDS_XCHECK_WHC, DDS_XCHECK_RHC, ~(uint32_t) 0 +}; + +static enum update_result uf_xcheck (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + return do_uint32_bitset (cfgst, elem, xcheck_names, xcheck_codes, value); +} + +static void pf_xcheck (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + const uint32_t * const p = cfg_address (cfgst, parent, cfgelem); #ifndef NDEBUG - const char *suffix = is_default ? " [def]" : ""; + const char *suffix = ""; #else const char *suffix = " [ignored]"; - (void)is_default; #endif - do_print_uint32_bitset (cfgst, *p, sizeof(xcheck_codes) / sizeof(*xcheck_codes), xcheck_names, xcheck_codes, suffix); + do_print_uint32_bitset (cfgst, *p, sizeof (xcheck_codes) / sizeof (*xcheck_codes), xcheck_names, xcheck_codes, sources, suffix); } -static void print_configitems(struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem, int unchecked) +#ifdef DDSI_INCLUDE_SSL +static enum update_result uf_min_tls_version (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) { - const struct cfgelem *ce; - for ( ce = cfgelem; ce && ce->name; ce++ ) { - struct cfgst_nodekey key; + static const char *vs[] = { + "1.2", "1.3", NULL + }; + static const struct ssl_min_version ms[] = { + {1,2}, {1,3}, {0,0} + }; + const int idx = list_index (vs, value); + struct ssl_min_version * const elem = cfg_address (cfgst, parent, cfgelem); + assert (sizeof (vs) / sizeof (*vs) == sizeof (ms) / sizeof (*ms)); + if (idx < 0) + return cfg_error(cfgst, "'%s': undefined value", value); + *elem = ms[idx]; + return URES_SUCCESS; +} + +static void pf_min_tls_version (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + struct ssl_min_version * const p = cfg_address (cfgst, parent, cfgelem); + cfg_logelem (cfgst, sources, "%d.%d", p->major, p->minor); +} +#endif + +static enum update_result uf_string (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + char ** const elem = cfg_address (cfgst, parent, cfgelem); + *elem = ddsrt_strdup (value); + return URES_SUCCESS; +} + +static void pf_string (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + char ** const p = cfg_address (cfgst, parent, cfgelem); + cfg_logelem (cfgst, sources, "%s", *p ? *p : "(null)"); +} + +#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING +static enum update_result uf_bandwidth (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + int64_t bandwidth_bps = 0; + if (strncmp (value, "inf", 3) == 0) { + /* special case: inf needs no unit */ + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + if (strspn (value + 3, " ") != strlen (value + 3) && + lo.up_multiplier (cfgst, unittab_bandwidth_bps, value, 3, 1, 8, 1) == 0) + return URES_ERROR; + *elem = 0; + return URES_SUCCESS; + } else if (uf_natint64_unit (cfgst, &bandwidth_bps, value, unittab_bandwidth_bps, 8, INT64_MAX) != URES_SUCCESS) { + return URES_ERROR; + } else if (bandwidth_bps / 8 > INT_MAX) { + return cfg_error (cfgst, "%s: value out of range", value); + } else { + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + *elem = (uint32_t) (bandwidth_bps / 8); + return URES_SUCCESS; + } +} + +static void pf_bandwidth(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + uint32_t const * const elem = cfg_address (cfgst, parent, cfgelem); + if (*elem == 0) + cfg_logelem (cfgst, sources, "inf"); + else + pf_int64_unit (cfgst, *elem, sources, unittab_bandwidth_Bps, "B/s"); +} +#endif + +static enum update_result uf_memsize (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + int64_t size = 0; + if (uf_natint64_unit (cfgst, &size, value, unittab_memsize, 1, 0, INT32_MAX) != URES_SUCCESS) + return URES_ERROR; + else { + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + *elem = (uint32_t) size; + return URES_SUCCESS; + } +} + +static void pf_memsize (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + int const * const elem = cfg_address (cfgst, parent, cfgelem); + pf_int64_unit (cfgst, *elem, sources, unittab_memsize, "B"); +} + +#ifdef DDSI_INCLUDE_ENCRYPTION +static enum update_result uf_cipher(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) +{ + if (q_security_plugin.cipher_type_from_string) + { + q_cipherType * const elem = cfg_address (cfgst, parent, cfgelem); + if (! q_security_plugin.cipher_type_from_string (value, elem)) + return cfg_error (cfgst, "%s: undefined value", value); + } + return URES_SUCCESS; +} + +static void pf_cipher (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + q_cipherType const * const p = cfg_address (cfgst, parent, cfgelem); + if (q_security_plugin.cipher_type) + cfg_logelem (cfgst, sources, "%s", (q_security_plugin.cipher_type) (*p)); +} + +static void pf_key (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), uint32_t sources) +{ + cfg_logelem (cfgst, sources, ""); +} +#endif /* DDSI_INCLUDE_ENCRYPTION */ + +static enum update_result uf_tracingOutputFileName (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) +{ + struct config * const cfg = cfgst->cfg; + cfg->tracefile = ddsrt_strdup (value); + return URES_SUCCESS; +} + +static enum update_result uf_ipv4 (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + /* Not actually doing any checking yet */ + return uf_string (cfgst, parent, cfgelem, first, value); +} + +static enum update_result uf_networkAddress (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + if (ddsrt_strcasecmp (value, "auto") != 0) + return uf_ipv4 (cfgst, parent, cfgelem, first, value); + else + { + char ** const elem = cfg_address (cfgst, parent, cfgelem); + *elem = NULL; + return URES_SUCCESS; + } +} + +static void pf_networkAddress (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + char ** const p = cfg_address (cfgst, parent, cfgelem); + cfg_logelem (cfgst, sources, "%s", *p ? *p : "auto"); +} + +static enum update_result uf_networkAddresses_simple (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + char *** const elem = cfg_address (cfgst, parent, cfgelem); + if ((*elem = ddsrt_malloc (2 * sizeof(char *))) == NULL) + return cfg_error (cfgst, "out of memory"); + if (((*elem)[0] = ddsrt_strdup (value)) == NULL) { + ddsrt_free (*elem); + *elem = NULL; + return cfg_error (cfgst, "out of memory"); + } + (*elem)[1] = NULL; + return URES_SUCCESS; +} + +static enum update_result uf_networkAddresses (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + /* Check for keywords first */ + { + static const char *keywords[] = { "all", "any", "none" }; + for (int i = 0; i < (int) (sizeof (keywords) / sizeof (*keywords)); i++) { + if (ddsrt_strcasecmp (value, keywords[i]) == 0) + return uf_networkAddresses_simple (cfgst, parent, cfgelem, first, keywords[i]); + } + } + + /* If not keyword, then comma-separated list of addresses */ + { + char *** const elem = cfg_address (cfgst, parent, cfgelem); + char *copy; + uint32_t count; + + /* First count how many addresses we have - but do it stupidly by + counting commas and adding one (so two commas in a row are both + counted) */ + { + const char *scan = value; + count = 1; + while (*scan) + count += (*scan++ == ','); + } + + copy = ddsrt_strdup (value); + + /* Allocate an array of address strings (which may be oversized a + bit because of the counting of the commas) */ + *elem = ddsrt_malloc ((count + 1) * sizeof(char *)); + + { + char *cursor = copy, *tok; + uint32_t idx = 0; + while ((tok = ddsrt_strsep (&cursor, ",")) != NULL) { + assert (idx < count); + (*elem)[idx] = ddsrt_strdup (tok); + idx++; + } + (*elem)[idx] = NULL; + } + ddsrt_free (copy); + } + return URES_SUCCESS; +} + +static void pf_networkAddresses (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + char *** const p = cfg_address (cfgst, parent, cfgelem); + for (int i = 0; (*p)[i] != NULL; i++) + cfg_logelem (cfgst, sources, "%s", (*p)[i]); +} + +static void ff_networkAddresses (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +{ + char *** const elem = cfg_address (cfgst, parent, cfgelem); + for (int i = 0; (*elem)[i]; i++) + ddsrt_free ((*elem)[i]); + ddsrt_free (*elem); +} + +#ifdef DDSI_INCLUDE_SSM +static const char *allow_multicast_names[] = { "false", "spdp", "asm", "ssm", "true", NULL }; +static const uint32_t allow_multicast_codes[] = { AMC_FALSE, AMC_SPDP, AMC_ASM, AMC_SSM, AMC_TRUE }; +#else +static const char *allow_multicast_names[] = { "false", "spdp", "asm", "true", NULL }; +static const uint32_t allow_multicast_codes[] = { AMC_FALSE, AMC_SPDP, AMC_ASM, AMC_TRUE }; +#endif + +static enum update_result uf_allow_multicast (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) +{ + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + if (ddsrt_strcasecmp (value, "default") == 0) + { + *elem = AMC_DEFAULT; + return URES_SUCCESS; + } + else + { + *elem = 0; + return do_uint32_bitset (cfgst, elem, allow_multicast_names, allow_multicast_codes, value); + } +} + +static void pf_allow_multicast(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + uint32_t *p = cfg_address (cfgst, parent, cfgelem); + if (*p == AMC_DEFAULT) + { + cfg_logelem (cfgst, sources, "default"); + } + else + { + do_print_uint32_bitset (cfgst, *p, sizeof (allow_multicast_codes) / sizeof (*allow_multicast_codes), allow_multicast_names, allow_multicast_codes, sources, ""); + } +} + +static enum update_result uf_maybe_int32 (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + DDSRT_WARNING_MSVC_OFF(4996); + struct config_maybe_int32 * const elem = cfg_address (cfgst, parent, cfgelem); + int pos; + if (ddsrt_strcasecmp (value, "default") == 0) { + elem->isdefault = 1; + elem->value = 0; + return URES_SUCCESS; + } else if (sscanf (value, "%"SCNd32"%n", &elem->value, &pos) == 1 && value[pos] == 0) { + elem->isdefault = 0; + return URES_SUCCESS; + } else { + return cfg_error (cfgst, "'%s': neither 'default' nor a decimal integer\n", value); + } + DDSRT_WARNING_MSVC_ON(4996); +} + +static void pf_maybe_int32 (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + struct config_maybe_int32 const * const p = cfg_address (cfgst, parent, cfgelem); + if (p->isdefault) + cfg_logelem (cfgst, sources, "default"); + else + cfg_logelem (cfgst, sources, "%d", p->value); +} + +static enum update_result uf_maybe_memsize (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + struct config_maybe_uint32 * const elem = cfg_address (cfgst, parent, cfgelem); + int64_t size = 0; + if (ddsrt_strcasecmp (value, "default") == 0) { + elem->isdefault = 1; + elem->value = 0; + return URES_SUCCESS; + } else if (uf_natint64_unit (cfgst, &size, value, unittab_memsize, 1, 0, INT32_MAX) != URES_SUCCESS) { + return URES_ERROR; + } else { + elem->isdefault = 0; + elem->value = (uint32_t) size; + return URES_SUCCESS; + } +} + +static void pf_maybe_memsize (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + struct config_maybe_uint32 const * const p = cfg_address (cfgst, parent, cfgelem); + if (p->isdefault) + cfg_logelem (cfgst, sources, "default"); + else + pf_int64_unit (cfgst, p->value, sources, unittab_memsize, "B"); +} + +static enum update_result uf_int (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + int * const elem = cfg_address (cfgst, parent, cfgelem); + char *endptr; + long v = strtol (value, &endptr, 10); + if (*value == 0 || *endptr != 0) + return cfg_error (cfgst, "%s: not a decimal integer", value); + if (v != (int) v) + return cfg_error (cfgst, "%s: value out of range", value); + *elem = (int) v; + return URES_SUCCESS; +} + +static enum update_result uf_int_min_max (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value, int min, int max) +{ + int *elem = cfg_address (cfgst, parent, cfgelem); + if (uf_int (cfgst, parent, cfgelem, first, value) != URES_SUCCESS) + return URES_ERROR; + else if (*elem < min || *elem > max) + return cfg_error (cfgst, "%s: out of range", value); + else + return URES_SUCCESS; +} + +static void pf_int (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + int const * const p = cfg_address (cfgst, parent, cfgelem); + cfg_logelem (cfgst, sources, "%d", *p); +} + +static enum update_result uf_dyn_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + return uf_int_min_max(cfgst, parent, cfgelem, first, value, -1, 65535); +} + +static enum update_result uf_natint(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + return uf_int_min_max(cfgst, parent, cfgelem, first, value, 0, INT32_MAX); +} + +static enum update_result uf_natint_255(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + return uf_int_min_max(cfgst, parent, cfgelem, first, value, 0, 255); +} + +static enum update_result uf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + unsigned * const elem = cfg_address (cfgst, parent, cfgelem); + char *endptr; + unsigned long v = strtoul (value, &endptr, 10); + if (*value == 0 || *endptr != 0) + return cfg_error (cfgst, "%s: not a decimal integer", value); + if (v != (unsigned) v) + return cfg_error (cfgst, "%s: value out of range", value); + *elem = (unsigned) v; + return URES_SUCCESS; +} + +static void pf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + unsigned const * const p = cfg_address (cfgst, parent, cfgelem); + cfg_logelem (cfgst, sources, "%u", *p); +} + +static enum update_result uf_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + int *elem = cfg_address (cfgst, parent, cfgelem); + if (uf_uint (cfgst, parent, cfgelem, first, value) != URES_SUCCESS) + return URES_ERROR; + else if (*elem < 1 || *elem > 65535) + return cfg_error (cfgst, "%s: out of range", value); + else + return URES_SUCCESS; +} + +static enum update_result uf_duration_gen (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, const char *value, int64_t def_mult, int64_t min_ns, int64_t max_ns) +{ + return uf_natint64_unit (cfgst, cfg_address (cfgst, parent, cfgelem), value, unittab_duration, def_mult, min_ns, max_ns); +} + +static enum update_result uf_duration_inf (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + if (ddsrt_strcasecmp (value, "inf") == 0) { + int64_t * const elem = cfg_address (cfgst, parent, cfgelem); + *elem = T_NEVER; + return URES_SUCCESS; + } else { + return uf_duration_gen (cfgst, parent, cfgelem, value, 0, 0, T_NEVER - 1); + } +} + +static enum update_result uf_duration_ms_1hr (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + return uf_duration_gen (cfgst, parent, cfgelem, value, T_MILLISECOND, 0, 3600 * T_SECOND); +} + +static enum update_result uf_duration_ms_1s (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + return uf_duration_gen (cfgst, parent, cfgelem, value, T_MILLISECOND, 0, T_SECOND); +} + +static enum update_result uf_duration_us_1s (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + return uf_duration_gen (cfgst, parent, cfgelem, value, 1000, 0, T_SECOND); +} + +static enum update_result uf_duration_100ms_1hr (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + return uf_duration_gen (cfgst, parent, cfgelem, value, 0, 100 * T_MILLISECOND, 3600 * T_SECOND); +} + +static void pf_duration (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + int64_t const * const elem = cfg_address (cfgst, parent, cfgelem); + if (*elem == T_NEVER) + cfg_logelem (cfgst, sources, "inf"); + else + pf_int64_unit (cfgst, *elem, sources, unittab_duration, "s"); +} + +static enum update_result uf_domainId (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value) +{ + DDSRT_WARNING_MSVC_OFF(4996); + uint32_t * const elem = cfg_address (cfgst, parent, cfgelem); + uint32_t tmpval; + int pos; + if (ddsrt_strcasecmp (value, "any") == 0) { + return URES_SUCCESS; + } else if (sscanf (value, "%"SCNu32"%n", &tmpval, &pos) == 1 && value[pos] == 0 && tmpval != UINT32_MAX) { + if (*elem == UINT32_MAX || *elem == tmpval) + { + if (!cfgst->first_data_in_source) + cfg_warning (cfgst, "not the first data in this source for compatible domain id"); + *elem = tmpval; + return URES_SUCCESS; + } + else if (!cfgst->first_data_in_source) + { + /* something has been set and we can't undo any earlier assignments, so this is an error */ + return cfg_error (cfgst, "not the first data in this source for incompatible domain id"); + } + else + { + //cfg_warning (cfgst, "%"PRIu32" is incompatible with domain id being configured (%"PRIu32"), skipping", tmpval, elem->value); + return URES_SKIP_ELEMENT; + } + } else { + return cfg_error (cfgst, "'%s': neither 'any' nor a less than 2**32-1", value); + } + DDSRT_WARNING_MSVC_ON(4996); +} + +static void pf_domainId(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + uint32_t const * const p = cfg_address (cfgst, parent, cfgelem); + if (*p == UINT32_MAX) + cfg_logelem (cfgst, sources, "any"); + else + cfg_logelem (cfgst, sources, "%"PRIu32, *p); +} + +static enum update_result uf_participantIndex (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + int * const elem = cfg_address (cfgst, parent, cfgelem); + if (ddsrt_strcasecmp (value, "auto") == 0) { + *elem = PARTICIPANT_INDEX_AUTO; + return URES_SUCCESS; + } else if (ddsrt_strcasecmp (value, "none") == 0) { + *elem = PARTICIPANT_INDEX_NONE; + return URES_SUCCESS; + } else { + return uf_int_min_max (cfgst, parent, cfgelem, first, value, 0, 120); + } +} + +static void pf_participantIndex (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) +{ + int const * const p = cfg_address (cfgst, parent, cfgelem); + switch (*p) + { + case PARTICIPANT_INDEX_NONE: + cfg_logelem (cfgst, sources, "none"); + break; + case PARTICIPANT_INDEX_AUTO: + cfg_logelem (cfgst, sources, "auto"); + break; + default: + cfg_logelem (cfgst, sources, "%d", *p); + break; + } +} + +static enum update_result uf_deaf_mute (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value) +{ + return uf_boolean (cfgst, parent, cfgelem, first, value); +} + +static struct cfgst_node *lookup_or_create_elem_record (struct cfgst *cfgst, struct cfgelem const * const cfgelem, void *parent, uint32_t source) +{ + struct cfgst_node *n; + struct cfgst_nodekey key; + ddsrt_avl_ipath_t np; + key.e = cfgelem; + key.p = parent; + if ((n = ddsrt_avl_lookup_ipath (&cfgst_found_treedef, &cfgst->found, &key, &np)) == NULL) + { + if ((n = ddsrt_malloc (sizeof (*n))) == NULL) + { + cfg_error (cfgst, "out of memory"); + return NULL; + } + n->key = key; + n->count = 0; + n->failed = 0; + n->sources = source; + ddsrt_avl_insert_ipath (&cfgst_found_treedef, &cfgst->found, n, &np); + } + return n; +} + +static enum update_result do_update (struct cfgst *cfgst, update_fun_t upd, void *parent, struct cfgelem const * const cfgelem, const char *value, uint32_t source) +{ + struct cfgst_node *n; + enum update_result res; + n = lookup_or_create_elem_record (cfgst, cfgelem, parent, source); + if (cfgelem->multiplicity == 1 && n->count == 1 && source > n->sources) + free_configured_element (cfgst, parent, cfgelem); + if (cfgelem->multiplicity == 0 || n->count < cfgelem->multiplicity) + res = upd (cfgst, parent, cfgelem, (n->count == n->failed), value); + else + res = cfg_error (cfgst, "only %d instance%s allowed", cfgelem->multiplicity, (cfgelem->multiplicity == 1) ? "" : "s"); + n->count++; + n->sources |= source; + /* deciding to skip an entire subtree in the config is not an error */ + if (res == URES_ERROR) + n->failed++; + return res; +} + +static int set_default (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +{ + enum update_result res; + if (cfgelem->defvalue == NULL) + { + cfg_error (cfgst, "element missing in configuration"); + return 0; + } + res = do_update (cfgst, cfgelem->update, parent, cfgelem, cfgelem->defvalue, 0); + return (res != URES_ERROR); +} + +static int set_defaults (struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem) +{ + int ok = 1; + for (const struct cfgelem *ce = cfgelem; ce && ce->name; ce++) + { struct cfgst_node *n; - if ( ce->name[0] == '>' || ce->name[0] == '|') /* moved or deprecated, so don't care */ - continue; + struct cfgst_nodekey key; key.e = ce; - cfgst_push(cfgst, isattr, ce, parent); - if ( ce->multiplicity == 1 ) { - if ( (n = ddsrt_avl_lookup(&cfgst_found_treedef, &cfgst->found, &key)) != NULL ) { - cfgst_push(cfgst, 0, NULL, NULL); - ce->print(cfgst, parent, ce, n->is_default); - cfgst_pop(cfgst); - } else { - if ( unchecked && ce->print ) { - cfgst_push(cfgst, 0, NULL, NULL); - ce->print(cfgst, parent, ce, 0); - cfgst_pop(cfgst); + key.p = parent; + cfgst_push (cfgst, isattr, ce, parent); + if (ce->multiplicity <= 1) + { + if ((n = ddsrt_avl_lookup (&cfgst_found_treedef, &cfgst->found, &key)) == NULL) + { + if (ce->update) + { + int ok1; + cfgst_push (cfgst, 0, NULL, NULL); + ok1 = set_default (cfgst, parent, ce); + cfgst_pop (cfgst); + ok = ok && ok1; } } - - if ( ce->children ) - print_configitems(cfgst, parent, 0, ce->children, unchecked); - if ( ce->attributes ) - print_configitems(cfgst, parent, 1, ce->attributes, unchecked); - } else { - struct config_listelem *p = cfg_deref_address(cfgst, parent, ce); - while ( p ) { - cfgst_push(cfgst, 0, NULL, NULL); - if ( ce->print ) { - ce->print(cfgst, p, ce, 0); - } - cfgst_pop(cfgst); - if ( ce->attributes ) - print_configitems(cfgst, p, 1, ce->attributes, 1); - if ( ce->children ) - print_configitems(cfgst, p, 0, ce->children, 1); - p = p->next; - } + if (ce->children) + ok = ok && set_defaults (cfgst, parent, 0, ce->children); + if (ce->attributes) + ok = ok && set_defaults (cfgst, parent, 1, ce->attributes); } - cfgst_pop(cfgst); + cfgst_pop (cfgst); } + return ok; } -static void free_all_elements(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +static void print_configitems (struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem, uint32_t sources) { - const struct cfgelem *ce; - - for ( ce = cfgelem; ce && ce->name; ce++ ) { - if ( ce->name[0] == '>' ) /* moved, so don't care */ - continue; - - if ( ce->free ) - ce->free(cfgst, parent, ce); - - if ( ce->multiplicity == 1 ) { - if ( ce->children ) - free_all_elements(cfgst, parent, ce->children); - if ( ce->attributes ) - free_all_elements(cfgst, parent, ce->attributes); - } else { - struct config_listelem *p = cfg_deref_address(cfgst, parent, ce); - struct config_listelem *r; - while ( p ) { - if ( ce->attributes ) - free_all_elements(cfgst, p, ce->attributes); - if ( ce->children ) - free_all_elements(cfgst, p, ce->children); - r = p; - p = p->next; - ddsrt_free(r); - } - } - } -} - -static void free_configured_elements(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) -{ - const struct cfgelem *ce; - for ( ce = cfgelem; ce && ce->name; ce++ ) { + for (const struct cfgelem *ce = cfgelem; ce && ce->name; ce++) + { struct cfgst_nodekey key; struct cfgst_node *n; - if ( ce->name[0] == '>' ) /* moved, so don't care */ + if (ce->name[0] == '>' || ce->name[0] == '|') /* moved or deprecated, so don't care */ continue; key.e = ce; - if ( (n = ddsrt_avl_lookup(&cfgst_found_treedef, &cfgst->found, &key)) != NULL ) { - if ( ce->free && n->count > n->failed ) - ce->free(cfgst, parent, ce); - } + key.p = parent; + cfgst_push (cfgst, isattr, ce, parent); + if ((n = ddsrt_avl_lookup(&cfgst_found_treedef, &cfgst->found, &key)) != NULL) + sources = n->sources; - if ( ce->multiplicity == 1 ) { - if ( ce->children ) - free_configured_elements(cfgst, parent, ce->children); - if ( ce->attributes ) - free_configured_elements(cfgst, parent, ce->attributes); - } else { - struct config_listelem *p = cfg_deref_address(cfgst, parent, ce); - struct config_listelem *r; - while ( p ) { - if ( ce->attributes ) - free_all_elements(cfgst, p, ce->attributes); - if ( ce->children ) - free_all_elements(cfgst, p, ce->children); - r = p; + if (ce->multiplicity <= 1) + { + cfgst_push (cfgst, 0, NULL, NULL); + if (ce->print) + ce->print (cfgst, parent, ce, sources); + cfgst_pop (cfgst); + if (ce->children) + print_configitems (cfgst, parent, 0, ce->children, sources); + if (ce->attributes) + print_configitems (cfgst, parent, 1, ce->attributes, sources); + } + else + { + struct config_listelem *p = cfg_deref_address (cfgst, parent, ce); + while (p) + { + cfgst_push (cfgst, 0, NULL, NULL); + if (ce->print) + ce->print (cfgst, p, ce, sources); + cfgst_pop(cfgst); + if (ce->attributes) + print_configitems (cfgst, p, 1, ce->attributes, sources); + if (ce->children) + print_configitems (cfgst, p, 0, ce->children, sources); p = p->next; - ddsrt_free(r); + } + } + cfgst_pop (cfgst); + } +} + + +static void free_all_elements (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +{ + for (const struct cfgelem *ce = cfgelem; ce && ce->name; ce++) + { + if (ce->name[0] == '>') /* moved, so don't care */ + continue; + + if (ce->free) + ce->free (cfgst, parent, ce); + + if (ce->multiplicity <= 1) { + if (ce->children) + free_all_elements (cfgst, parent, ce->children); + if (ce->attributes) + free_all_elements (cfgst, parent, ce->attributes); + } else { + struct config_listelem *p = cfg_deref_address (cfgst, parent, ce); + while (p) { + struct config_listelem *p1 = p->next; + if (ce->attributes) + free_all_elements (cfgst, p, ce->attributes); + if (ce->children) + free_all_elements (cfgst, p, ce->children); + ddsrt_free (p); + p = p1; } } } } -static int matching_name_index(const char *name_w_aliases, const char *name) +static void free_configured_element (struct cfgst *cfgst, void *parent, struct cfgelem const * const ce) { - const char *ns = name_w_aliases, *p = strchr(ns, '|'); + struct cfgst_nodekey key; + struct cfgst_node *n; + if (ce->name[0] == '>') /* moved, so don't care */ + return; + key.e = ce; + key.p = parent; + if ((n = ddsrt_avl_lookup (&cfgst_found_treedef, &cfgst->found, &key)) != NULL) + { + if (ce->free && n->count > n->failed) + ce->free (cfgst, parent, ce); + n->count = n->failed = 0; + } + + if (ce->multiplicity <= 1) + { + if (ce->children) + free_configured_elements (cfgst, parent, ce->children); + if (ce->attributes) + free_configured_elements (cfgst, parent, ce->attributes); + } + else + { + /* FIXME: this used to require free_all_elements because there would be no record stored for + configuration elements within lists, but with that changed, I think this can now just use + free_configured_elements */ + struct config_listelem *p = cfg_deref_address (cfgst, parent, ce); + while (p) { + struct config_listelem * const p1 = p->next; + if (ce->attributes) + free_all_elements (cfgst, p, ce->attributes); + if (ce->children) + free_all_elements (cfgst, p, ce->children); + ddsrt_free (p); + p = p1; + } + } +} + +static void free_configured_elements (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +{ + for (const struct cfgelem *ce = cfgelem; ce && ce->name; ce++) + free_configured_element (cfgst, parent, ce); +} + +static int matching_name_index (const char *name_w_aliases, const char *name) +{ + const char *ns = name_w_aliases, *p = strchr (ns, '|'); int idx = 0; - while ( p ) { - if ( ddsrt_strncasecmp(ns, name, (size_t) (p - ns)) == 0 && name[p - ns] == 0 ) { + while (p) + { + if (ddsrt_strncasecmp (ns, name, (size_t) (p - ns)) == 0 && name[p - ns] == 0) + { /* ns upto the pipe symbol is a prefix of name, and name is terminated at that point */ return idx; } /* If primary name followed by '||' instead of '|', aliases are non-warning */ ns = p + 1 + (idx == 0 && p[1] == '|'); - p = strchr(ns, '|'); + p = strchr (ns, '|'); idx++; } - return (ddsrt_strcasecmp(ns, name) == 0) ? idx : -1; + return (ddsrt_strcasecmp (ns, name) == 0) ? idx : -1; } -static const struct cfgelem *lookup_redirect(const char *target) +static const struct cfgelem *lookup_element (const char *target, bool *isattr) { const struct cfgelem *cfgelem = cyclonedds_root_cfgelems; - char *target_copy = ddsrt_strdup(target), *p1; - const char *p = target_copy; - while ( p ) { - p1 = strchr(p, '/'); - if ( p1 ) *p1++ = 0; - for ( ; cfgelem->name; cfgelem++ ) { - /* not supporting multiple redirects */ - assert(cfgelem->name[0] != '>'); - if ( matching_name_index(cfgelem->name, p) >= 0 ) + char *target_copy = ddsrt_strdup (target); + char *p = target_copy; + *isattr = false; + while (p) + { + char *p1 = p + strcspn (p, "/["); + switch (*p1) + { + case '\0': + p1 = NULL; break; + case '/': + *p1++ = 0; + break; + case '[': + assert (p1[1] == '@' && p1[strlen (p1) - 1] == ']'); + p1[strlen (p1) - 1] = 0; + *p1 = 0; p1 += 2; + *isattr = true; + break; + default: + assert (0); } - if ( p1 ) { - cfgelem = cfgelem->children; + for (; cfgelem->name; cfgelem++) + { + if (matching_name_index (cfgelem->name, p) >= 0) + { + /* not supporting chained redirects */ + assert (cfgelem->name[0] != '>'); + break; + } } + if (p1) + cfgelem = *isattr ? cfgelem->attributes : cfgelem->children; p = p1; } - ddsrt_free(target_copy); + ddsrt_free (target_copy); return cfgelem; } -static int proc_elem_open(void *varg, UNUSED_ARG(uintptr_t parentinfo), UNUSED_ARG(uintptr_t *eleminfo), const char *name) +static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED_ARG (uintptr_t *eleminfo), const char *name, int line) { struct cfgst * const cfgst = varg; - const struct cfgelem *cfgelem = cfgst_tos(cfgst); + + cfgst->line = line; + if (cfgst->implicit_toplevel == ITL_ALLOWED) + { + if (ddsrt_strcasecmp (name, "CycloneDDS") == 0) + cfgst->implicit_toplevel = ITL_DISALLOWED; + else + { + cfgst_push (cfgst, 0, &cyclonedds_root_cfgelems[0], cfgst_parent (cfgst)); + /* Most likely one would want to override some domain settings without bothering, + so also allow an implicit "Domain" */ + cfgst->implicit_toplevel = ITL_INSERTED_1; + if (ddsrt_strcasecmp (name, "Domain") != 0) + { + cfgst_push (cfgst, 0, &root_cfgelems[0], cfgst_parent (cfgst)); + cfgst->implicit_toplevel = ITL_INSERTED_2; + } + } + } + + const struct cfgelem *cfgelem = cfgst_tos (cfgst); const struct cfgelem *cfg_subelem; int moved = 0; - if ( cfgelem == NULL ) { + + if (cfgelem == NULL) + { /* Ignoring, but do track the structure so we can know when to stop ignoring */ - cfgst_push(cfgst, 0, NULL, NULL); + cfgst_push (cfgst, 0, NULL, NULL); return 1; } - for ( cfg_subelem = cfgelem->children; cfg_subelem && cfg_subelem->name && strcmp(cfg_subelem->name, "*") != 0; cfg_subelem++ ) { + for (cfg_subelem = cfgelem->children; cfg_subelem && cfg_subelem->name && strcmp (cfg_subelem->name, "*") != 0; cfg_subelem++) + { const char *csename = cfg_subelem->name; int idx; moved = (csename[0] == '>'); - if ( moved ) + if (moved) csename++; - idx = matching_name_index(csename, name); -#if WARN_DEPRECATED_ALIAS - if ( idx > 0 ) { - if (csename[0] == '|') { - cfg_warning(cfgst, "'%s': deprecated setting", name); - } else { - int n = (int) (strchr(csename, '|') - csename); - if ( csename[n + 1] != '|' ) { - cfg_warning(cfgst, "'%s': deprecated alias for '%*.*s'", name, n, n, csename); + idx = matching_name_index (csename, name); + if (idx > 0) + { + if (csename[0] == '|') + cfg_warning (cfgst, "'%s': deprecated setting", name); + else + { + int n = (int) (strchr (csename, '|') - csename); + if (csename[n + 1] != '|') { + cfg_warning (cfgst, "'%s': deprecated alias for '%*.*s'", name, n, n, csename); } } } -#endif - if ( idx >= 0 ) { + if (idx >= 0) break; - } } - if ( cfg_subelem == NULL || cfg_subelem->name == NULL ) { - cfgst_push(cfgst, 0, NULL, NULL); - return cfg_error(cfgst, "%s: unknown element", name); - } else if ( strcmp(cfg_subelem->name, "*") == 0 ) { + if (cfg_subelem == NULL || cfg_subelem->name == NULL) + { + cfg_error (cfgst, "%s: unknown element", name); + cfgst_push (cfgst, 0, NULL, NULL); + return 0; + } + else if (strcmp (cfg_subelem->name, "*") == 0) + { /* Push a marker that we are to ignore this part of the DOM tree */ - cfgst_push(cfgst, 0, NULL, NULL); + cfgst_push (cfgst, 0, NULL, NULL); return 1; - } else { + } + else + { void *parent, *dynparent; - if ( moved ) { + if (moved) + { struct cfgelem const * const cfg_subelem_orig = cfg_subelem; - cfg_subelem = lookup_redirect(cfg_subelem->defvalue); -#if WARN_DEPRECATED_ALIAS - cfgst_push(cfgst, 0, cfg_subelem_orig, NULL); - cfg_warning(cfgst, "setting%s moved to //%s", cfg_subelem->children ? "s" : "", cfg_subelem_orig->defvalue); - cfgst_pop(cfgst); -#endif + bool isattr; + cfg_subelem = lookup_element (cfg_subelem->defvalue, &isattr); + cfgst_push (cfgst, 0, cfg_subelem_orig, NULL); + cfg_warning (cfgst, "setting%s moved to //%s", cfg_subelem->children ? "s" : "", cfg_subelem_orig->defvalue); + cfgst_pop (cfgst); } - parent = cfgst_parent(cfgst); - assert(cfgelem->init || cfgelem->multiplicity == 1); /*multi-items must have an init-func */ - if ( cfg_subelem->init ) { - if ( cfg_subelem->init(cfgst, parent, cfg_subelem) < 0 ) + parent = cfgst_parent (cfgst); + assert (cfgelem->init || cfgelem->multiplicity == 1); /* multi-items must have an init-func */ + if (cfg_subelem->init) + { + if (cfg_subelem->init (cfgst, parent, cfg_subelem) < 0) return 0; } - if ( cfg_subelem->multiplicity != 1 ) - dynparent = cfg_deref_address(cfgst, parent, cfg_subelem); - else + if (cfg_subelem->multiplicity <= 1) dynparent = parent; + else + dynparent = cfg_deref_address (cfgst, parent, cfg_subelem); - cfgst_push(cfgst, 0, cfg_subelem, dynparent); + cfgst_push (cfgst, 0, cfg_subelem, dynparent); + + if (cfg_subelem == &cyclonedds_root_cfgelems[0]) + { + cfgst->source = (cfgst->source == 0) ? 1 : cfgst->source << 1; + cfgst->first_data_in_source = true; + } + else if (cfg_subelem >= &root_cfgelems[0] && cfg_subelem < &root_cfgelems[0] + sizeof (root_cfgelems) / sizeof (root_cfgelems[0])) + { + if (!cfgst->first_data_in_source) + cfgst->source = (cfgst->source == 0) ? 1 : cfgst->source << 1; + cfgst->first_data_in_source = true; + } return 1; } } -static int proc_attr(void *varg, UNUSED_ARG(uintptr_t eleminfo), const char *name, const char *value) +static int proc_update_cfgelem (struct cfgst *cfgst, const struct cfgelem *ce, const char *value, bool isattr) +{ + void *parent = cfgst_parent (cfgst); + char *xvalue = ddsrt_expand_envvars (value, cfgst->cfg->domainId); + enum update_result res; + cfgst_push (cfgst, isattr, isattr ? ce : NULL, parent); + res = do_update (cfgst, ce->update, parent, ce, xvalue, cfgst->source); + cfgst_pop (cfgst); + ddsrt_free (xvalue); + + /* Push a marker that we are to ignore this part of the DOM tree -- see the + handling of WILDCARD ("*"). This is currently only used for domain ids, + and there it is either: + - , in which case the element at the top of the stack is + Domain, which is the element to ignore, or: + - X, in which case the element at the top of the stack Id, + and we need to strip ignore the one that is one down. + + The configuration processing doesn't allow an element to contain text and + have children at the same time, and with that restriction it never makes + sense to ignore just the TOS element if it is text: that would be better + done in the update function itself. + + So replacing the top stack entry for an attribute and the top two entries + if it's text is a reasonable interpretation of SKIP. And it seems quite + likely that it won't be used for anything else ... */ + if (res == URES_SKIP_ELEMENT) + { + cfgst_pop (cfgst); + if (!isattr) + { + cfgst_pop (cfgst); + cfgst_push (cfgst, 0, NULL, NULL); + } + cfgst_push (cfgst, 0, NULL, NULL); + } + else + { + cfgst->first_data_in_source = false; + } + return res != URES_ERROR; +} + +static int proc_attr (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *name, const char *value, int line) { /* All attributes are processed immediately after opening the element */ struct cfgst * const cfgst = varg; - const struct cfgelem *cfgelem = cfgst_tos(cfgst); + const struct cfgelem *cfgelem = cfgst_tos (cfgst); const struct cfgelem *cfg_attr; - if ( cfgelem == NULL ) + cfgst->line = line; + if (cfgelem == NULL) return 1; - for ( cfg_attr = cfgelem->attributes; cfg_attr && cfg_attr->name; cfg_attr++ ) { - if ( ddsrt_strcasecmp(cfg_attr->name, name) == 0 ) + for (cfg_attr = cfgelem->attributes; cfg_attr && cfg_attr->name; cfg_attr++) + if (ddsrt_strcasecmp(cfg_attr->name, name) == 0) break; - } - if ( cfg_attr == NULL || cfg_attr->name == NULL ) - return cfg_error(cfgst, "%s: unknown attribute", name); - else { - void *parent = cfgst_parent(cfgst); - char *xvalue = ddsrt_expand_envvars(value); - int ok; - cfgst_push(cfgst, 1, cfg_attr, parent); - ok = do_update(cfgst, cfg_attr->update, parent, cfg_attr, xvalue, 0); - cfgst_pop(cfgst); - ddsrt_free(xvalue); - return ok; + if (cfg_attr != NULL && cfg_attr->name != NULL) + return proc_update_cfgelem (cfgst, cfg_attr, value, true); + else + { + cfg_error (cfgst, "%s: unknown attribute", name); + return 0; } } -static int proc_elem_data(void *varg, UNUSED_ARG(uintptr_t eleminfo), const char *value) +static int proc_elem_data (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *value, int line) { struct cfgst * const cfgst = varg; - const struct cfgelem *cfgelem = cfgst_tos(cfgst); - if ( cfgelem == NULL ) + bool isattr; /* elem may have been moved to an attr */ + const struct cfgelem *cfgelem = cfgst_tos_w_isattr (cfgst, &isattr); + cfgst->line = line; + if (cfgelem == NULL) return 1; - if ( cfgelem->update == 0 ) - return cfg_error(cfgst, "%s: no data expected", value); - else { - void *parent = cfgst_parent(cfgst); - char *xvalue = ddsrt_expand_envvars(value); - int ok; - cfgst_push(cfgst, 0, NULL, parent); - ok = do_update(cfgst, cfgelem->update, parent, cfgelem, xvalue, 0); - cfgst_pop(cfgst); - ddsrt_free(xvalue); - return ok; + if (cfgelem->update != 0) + return proc_update_cfgelem (cfgst, cfgelem, value, isattr); + else + { + cfg_error (cfgst, "%s: no data expected", value); + return 0; } } -static int proc_elem_close(void *varg, UNUSED_ARG(uintptr_t eleminfo)) +static int proc_elem_close (void *varg, UNUSED_ARG (uintptr_t eleminfo), int line) { struct cfgst * const cfgst = varg; - const struct cfgelem * cfgelem = cfgst_tos(cfgst); + const struct cfgelem * cfgelem = cfgst_tos (cfgst); int ok = 1; - if ( cfgelem && cfgelem->multiplicity != 1 ) { - void *parent = cfgst_parent(cfgst); + cfgst->line = line; + if (cfgelem && cfgelem->multiplicity > 1) + { + void *parent = cfgst_parent (cfgst); int ok1; - ok1 = set_defaults(cfgst, parent, 1, cfgelem->attributes, 1); + ok1 = set_defaults (cfgst, parent, 1, cfgelem->attributes); ok = ok && ok1; - ok1 = set_defaults(cfgst, parent, 0, cfgelem->children, 1); + ok1 = set_defaults (cfgst, parent, 0, cfgelem->children); ok = ok && ok1; } - cfgst_pop(cfgst); + cfgst_pop (cfgst); return ok; } -static void proc_error(void *varg, const char *msg, int line) +static void proc_error (void *varg, const char *msg, int line) { struct cfgst * const cfgst = varg; - cfg_error(cfgst, "parser error %s at line %d", msg, line); + cfg_error (cfgst, "parser error %s at line %d", msg, line); } - -static int cfgst_node_cmp(const void *va, const void *vb) +static int cfgst_node_cmp (const void *va, const void *vb) { - return memcmp(va, vb, sizeof(struct cfgst_nodekey)); + return memcmp (va, vb, sizeof (struct cfgst_nodekey)); } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -static int set_default_channel(struct config *cfg) +static int set_default_channel (struct config *cfg) { - if ( cfg->channels == NULL ) { + if (cfg->channels == NULL) + { /* create one default channel if none configured */ struct config_channel_listelem *c; - if ( (c = ddsrt_malloc(sizeof(*c))) == NULL ) + if ((c = ddsrt_malloc (sizeof (*c))) == NULL) return ERR_OUT_OF_MEMORY; c->next = NULL; - c->name = ddsrt_strdup("user"); + c->name = ddsrt_strdup ("user"); c->priority = 0; c->resolution = 1 * T_MILLISECOND; #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING @@ -2592,83 +2614,111 @@ static int set_default_channel(struct config *cfg) return 0; } -static int sort_channels_cmp(const void *va, const void *vb) +static int sort_channels_cmp (const void *va, const void *vb) { const struct config_channel_listelem * const *a = va; const struct config_channel_listelem * const *b = vb; return ((*a)->priority == (*b)->priority) ? 0 : ((*a)->priority < (*b)->priority) ? -1 : 1; } -static int sort_channels_check_nodups(struct config *cfg) +static int sort_channels_check_nodups (struct config *cfg, uint32_t domid) { /* Selecting a channel is much easier & more elegant if the channels are sorted on descending priority. While we do retain the list structure, sorting is much easier in an array, and hence we convert back and forth. */ struct config_channel_listelem **ary, *c; - unsigned i, n; + uint32_t i, n; int result; n = 0; - for ( c = cfg->channels; c; c = c->next ) + for (c = cfg->channels; c; c = c->next) n++; assert(n > 0); - ary = ddsrt_malloc(n * sizeof(*ary)); + ary = ddsrt_malloc (n * sizeof (*ary)); i = 0; - for ( c = cfg->channels; c; c = c->next ) + for (c = cfg->channels; c; c = c->next) ary[i++] = c; - qsort(ary, n, sizeof(*ary), sort_channels_cmp); + qsort (ary, n, sizeof (*ary), sort_channels_cmp); result = 0; - for ( i = 0; i < n - 1; i++ ) { - if ( ary[i]->priority == ary[i + 1]->priority ) { - DDS_ERROR("config: duplicate channel definition for priority %u: channels %s and %s\n", + for (i = 0; i < n - 1; i++) { + if (ary[i]->priority == ary[i + 1]->priority) { + DDS_ILOG (DDS_LC_ERROR, domid, "config: duplicate channel definition for priority %u: channels %s and %s\n", ary[i]->priority, ary[i]->name, ary[i + 1]->name); result = ERR_ENTITY_EXISTS; } } - if ( result == 0 ) { + if (result == 0) + { cfg->channels = ary[0]; - for ( i = 0; i < n - 1; i++ ) + for (i = 0; i < n - 1; i++) ary[i]->next = ary[i + 1]; ary[i]->next = NULL; cfg->max_channel = ary[i]; } - ddsrt_free(ary); + ddsrt_free (ary); return result; } #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ -struct cfgst * config_init (const char *configfile) +static FILE *config_open_file (char *tok, char **cursor, uint32_t domid) +{ + assert (*tok && !(isspace ((unsigned char) *tok) || *tok == ',')); + FILE *fp; + char *comma; + if ((comma = strchr (tok, ',')) == NULL) + *cursor = NULL; + else + { + *comma = 0; + *cursor = comma + 1; + } + DDSRT_WARNING_MSVC_OFF(4996); + if ((fp = fopen (tok, "r")) == NULL) + { + if (strncmp (tok, "file://", 7) != 0 || (fp = fopen (tok + 7, "r")) == NULL) + { + DDS_ILOG (DDS_LC_ERROR, domid, "can't open configuration file %s\n", tok); + return NULL; + } + } + DDSRT_WARNING_MSVC_ON(4996); + return fp; +} + +struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid) { int ok = 1; struct cfgst *cfgst; - memset(&config, 0, sizeof(config)); + memset (cfg, 0, sizeof (*cfg)); - config.tracingOutputFile = stderr; - config.enabled_logcats = DDS_LC_ERROR | DDS_LC_WARNING; + cfgst = ddsrt_malloc (sizeof (*cfgst)); + memset (cfgst, 0, sizeof (*cfgst)); + ddsrt_avl_init (&cfgst_found_treedef, &cfgst->found); + cfgst->cfg = cfg; + cfgst->error = 0; + cfgst->source = 0; + cfgst->logcfg = NULL; + cfgst->first_data_in_source = true; + cfgst->input = "init"; + cfgst->line = 1; /* eventually, we domainId.value will be the real domain id selected, even if it was configured to the default of "any" and has "isdefault" set; initializing it to the default-default value of 0 means "any" in the config & DDS_DOMAIN_DEFAULT in create participant automatically ends up on the right value */ - config.domainId.value = 0; - - cfgst = ddsrt_malloc(sizeof(*cfgst)); - memset(cfgst, 0, sizeof(*cfgst)); - - ddsrt_avl_init(&cfgst_found_treedef, &cfgst->found); - cfgst->cfg = &config; - cfgst->error = 0; + cfgst->cfg->domainId = domid; /* configfile == NULL will get you the default configuration */ if (configfile) { - char *copy = ddsrt_strdup(configfile), *cursor = copy; + char env_input[32]; + char *copy = ddsrt_strdup (configfile), *cursor = copy; struct ddsrt_xmlp_callbacks cb; cb.attr = proc_attr; @@ -2677,64 +2727,71 @@ struct cfgst * config_init (const char *configfile) cb.elem_open = proc_elem_open; cb.error = proc_error; - while (ok && cursor && cursor[0]) { + while (*cursor && (isspace ((unsigned char) *cursor) || *cursor == ',')) + cursor++; + while (ok && cursor && cursor[0]) + { struct ddsrt_xmlp_state *qx; FILE *fp; char *tok; tok = cursor; - if (tok[0] == '<') { + if (tok[0] == '<') + { /* Read XML directly from input string */ qx = ddsrt_xmlp_new_string (tok, cfgst, &cb); - ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG); + ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG | DDSRT_XMLP_MISSING_CLOSE_AS_EOF); fp = NULL; - } else { - char *comma; - if ((comma = strchr (cursor, ',')) == NULL) { - cursor = NULL; - } else { - *comma = 0; - cursor = comma + 1; - } - DDSRT_WARNING_MSVC_OFF(4996); - if ((fp = fopen(tok, "r")) == NULL) { - if (strncmp(tok, "file://", 7) != 0 || (fp = fopen(tok + 7, "r")) == NULL) { - DDS_ERROR("can't open configuration file %s\n", tok); - ddsrt_free(copy); - ddsrt_free(cfgst); - return NULL; - } - } - DDSRT_WARNING_MSVC_ON(4996); - qx = ddsrt_xmlp_new_file(fp, cfgst, &cb); + snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy)); + cfgst->input = env_input; + cfgst->line = 1; + } + else if ((fp = config_open_file (tok, &cursor, domid)) == NULL) + { + ddsrt_free (copy); + goto error; + } + else + { + qx = ddsrt_xmlp_new_file (fp, cfgst, &cb); + cfgst->input = tok; + cfgst->line = 1; } - cfgst_push(cfgst, 0, &root_cfgelem, &config); - ok = (ddsrt_xmlp_parse(qx) >= 0) && !cfgst->error; + cfgst->implicit_toplevel = (fp == NULL) ? ITL_ALLOWED : ITL_DISALLOWED; + cfgst->first_data_in_source = true; + cfgst_push (cfgst, 0, &root_cfgelem, cfgst->cfg); + ok = (ddsrt_xmlp_parse (qx) >= 0) && !cfgst->error; + assert (!ok || + (cfgst->path_depth == 1 && cfgst->implicit_toplevel == ITL_DISALLOWED) || + (cfgst->path_depth == 1 + (int) cfgst->implicit_toplevel)); /* Pop until stack empty: error handling is rather brutal */ - assert(!ok || cfgst->path_depth == 1); - while (cfgst->path_depth > 0) { - cfgst_pop(cfgst); - } - if (fp) { - fclose(fp); - } else if (ok) { + while (cfgst->path_depth > 0) + cfgst_pop (cfgst); + if (fp != NULL) + fclose (fp); + else if (ok) cursor = tok + ddsrt_xmlp_get_bufpos (qx); - } - ddsrt_xmlp_free(qx); - while (cursor && cursor[0] == ',') { - cursor++; + ddsrt_xmlp_free (qx); + assert (fp == NULL || cfgst->implicit_toplevel <= ITL_ALLOWED); + if (cursor) + { + while (*cursor && (isspace ((unsigned char) cursor[0]) || cursor[0] == ',')) + cursor++; } } - ddsrt_free(copy); + ddsrt_free (copy); } /* Set defaults for everything not set that we have a default value for, signal errors for things unset but without a default. */ - { - int ok1 = set_defaults(cfgst, cfgst->cfg, 0, root_cfgelems, 0); - ok = ok && ok1; - } + ok = ok && set_defaults (cfgst, cfgst->cfg, 0, root_cfgelems); + /* Domain id UINT32_MAX can only happen if the application specified DDS_DOMAIN_DEFAULT + and the configuration has "any" (either explicitly or as a default). In that case, + default to 0. (Leaving it as UINT32_MAX while reading the config has the advantage + of warnings/errors being output without a domain id present. */ + if (cfgst->cfg->domainId == UINT32_MAX) + cfgst->cfg->domainId = 0; /* Compatibility settings of IPv6, TCP -- a bit too complicated for the poor framework */ @@ -2744,9 +2801,9 @@ struct cfgst * config_init (const char *configfile) { case TRANS_DEFAULT: if (cfgst->cfg->compat_tcp_enable == BOOLDEF_TRUE) - cfgst->cfg->transport_selector = (config.compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_TCP6 : TRANS_TCP; + cfgst->cfg->transport_selector = (cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_TCP6 : TRANS_TCP; else - cfgst->cfg->transport_selector = (config.compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_UDP6 : TRANS_UDP; + cfgst->cfg->transport_selector = (cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_UDP6 : TRANS_UDP; break; case TRANS_TCP: ok1 = !(cfgst->cfg->compat_tcp_enable == BOOLDEF_FALSE || cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE); @@ -2765,7 +2822,7 @@ struct cfgst * config_init (const char *configfile) break; } if (!ok1) - DDS_ERROR("config: invalid combination of Transport, IPv6, TCP\n"); + DDS_ILOG (DDS_LC_ERROR, domid, "config: invalid combination of Transport, IPv6, TCP\n"); ok = ok && ok1; cfgst->cfg->compat_use_ipv6 = (cfgst->cfg->transport_selector == TRANS_UDP6 || cfgst->cfg->transport_selector == TRANS_TCP6) ? BOOLDEF_TRUE : BOOLDEF_FALSE; cfgst->cfg->compat_tcp_enable = (cfgst->cfg->transport_selector == TRANS_TCP || cfgst->cfg->transport_selector == TRANS_TCP6) ? BOOLDEF_TRUE : BOOLDEF_FALSE; @@ -2774,36 +2831,37 @@ struct cfgst * config_init (const char *configfile) #ifdef DDSI_INCLUDE_NETWORK_CHANNELS /* Default channel gets set outside set_defaults -- a bit too complicated for the poor framework */ - - if ( set_default_channel(cfgst->cfg) < 0 ) { + if (set_default_channel (cfgst->cfg) < 0) ok = 0; - } - if ( cfgst->cfg->channels && sort_channels_check_nodups(cfgst->cfg) < 0 ) { + if (cfgst->cfg->channels && sort_channels_check_nodups (cfgst->cfg) < 0) ok = 0; - } #endif #ifdef DDSI_INCLUDE_ENCRYPTION /* Check security profiles */ { - struct config_securityprofile_listelem *s = config.securityProfiles; - while ( s ) { - switch ( s->cipher ) { + struct config_securityprofile_listelem *s = cfgst->cfg->securityProfiles; + while (s) + { + switch (s->cipher) + { case Q_CIPHER_UNDEFINED: case Q_CIPHER_NULL: /* nop */ - if ( s->key && strlen(s->key) > 0 ) { - DDS_INFO("config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s: cipher key not required\n", s->key); - } + if (s->key && strlen(s->key) > 0) + DDS_ILOG (DDS_LC_INFO, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s: cipher key not required\n", s->key); break; default: /* read the cipherkey if present */ - if ( !s->key || strlen(s->key) == 0 ) { - DDS_ERROR("config: DDSI2Service/Security/SecurityProfile[@cipherkey]: cipher key missing\n"); + if (!s->key || strlen(s->key) == 0) + { + DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: cipher key missing\n"); ok = 0; - } else if ( q_security_plugin.valid_uri && !(q_security_plugin.valid_uri) (s->cipher, s->key) ) { - DDS_ERROR("config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s : incorrect key\n", s->key); + } + else if (q_security_plugin.valid_uri && !(q_security_plugin.valid_uri) (s->cipher, s->key)) + { + DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s : incorrect key\n", s->key); ok = 0; } } @@ -2819,30 +2877,33 @@ struct cfgst * config_init (const char *configfile) securityProfiles and signal errors if profiles do not exist */ #endif /* DDSI_INCLUDE_ENCRYPTION */ { - struct config_networkpartition_listelem *p = config.networkPartitions; - config.nof_networkPartitions = 0; - while ( p ) { + struct config_networkpartition_listelem *p = cfgst->cfg->networkPartitions; + cfgst->cfg->nof_networkPartitions = 0; + while (p) + { #ifdef DDSI_INCLUDE_ENCRYPTION - if ( ddsrt_strcasecmp(p->profileName, "null") == 0 ) + if (ddsrt_strcasecmp(p->profileName, "null") == 0) p->securityProfile = NULL; - else { - struct config_securityprofile_listelem *s = config.securityProfiles; - while ( s && ddsrt_strcasecmp(p->profileName, s->name) != 0 ) + else + { + struct config_securityprofile_listelem *s = cfgst->cfg->securityProfiles; + while (s && ddsrt_strcasecmp(p->profileName, s->name) != 0) s = s->next; - if ( s ) + if (s) p->securityProfile = s; - else { - DDS_ERROR("config: DDSI2Service/Partitioning/NetworkPartitions/NetworkPartition[@securityprofile]: %s: unknown securityprofile\n", p->profileName); + else + { + DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Partitioning/NetworkPartitions/NetworkPartition[@securityprofile]: %s: unknown securityprofile\n", p->profileName); ok = 0; } } #endif /* DDSI_INCLUDE_ENCRYPTION */ - config.nof_networkPartitions++; + cfgst->cfg->nof_networkPartitions++; /* also use crc32 just like native nw and ordinary ddsi2e, only for interoperability because it is asking for trouble & forces us to include a crc32 routine when we have md5 available anyway */ - p->partitionId = config.nof_networkPartitions; /* starting at 1 */ + p->partitionId = cfgst->cfg->nof_networkPartitions; /* starting at 1 */ p->partitionHash = crc32_calc(p->name, strlen(p->name)); p = p->next; } @@ -2851,16 +2912,17 @@ struct cfgst * config_init (const char *configfile) /* Create links from the partitionmappings to the network partitions and signal errors if partitions do not exist */ { - struct config_partitionmapping_listelem * m = config.partitionMappings; - while ( m ) { - struct config_networkpartition_listelem * p = config.networkPartitions; - while ( p && ddsrt_strcasecmp(m->networkPartition, p->name) != 0 ) { + struct config_partitionmapping_listelem * m = cfgst->cfg->partitionMappings; + while (m) + { + struct config_networkpartition_listelem * p = cfgst->cfg->networkPartitions; + while (p && ddsrt_strcasecmp(m->networkPartition, p->name) != 0) p = p->next; - } - if ( p ) { + if (p) m->partition = p; - } else { - DDS_ERROR("config: DDSI2Service/Partitioning/PartitionMappings/PartitionMapping[@networkpartition]: %s: unknown partition\n", m->networkPartition); + else + { + DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Partitioning/PartitionMappings/PartitionMapping[@networkpartition]: %s: unknown partition\n", m->networkPartition); ok = 0; } m = m->next; @@ -2868,104 +2930,107 @@ struct cfgst * config_init (const char *configfile) } #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ - /* Now switch to configured tracing settings */ - config.enabled_logcats = enabled_logcats; - - if ( !ok ) { - free_configured_elements(cfgst, cfgst->cfg, root_cfgelems); - } - - if ( ok ) { - config.valid = 1; + if (ok) + { + cfgst->cfg->valid = 1; return cfgst; - } else { - ddsrt_avl_free(&cfgst_found_treedef, &cfgst->found, ddsrt_free); - ddsrt_free(cfgst); - return NULL; } + +error: + free_configured_elements (cfgst, cfgst->cfg, root_cfgelems); + ddsrt_avl_free (&cfgst_found_treedef, &cfgst->found, ddsrt_free); + ddsrt_free (cfgst); + return NULL; } -void config_print_cfgst(struct cfgst *cfgst) +void config_print_cfgst (struct cfgst *cfgst, const struct ddsrt_log_cfg *logcfg) { - if ( cfgst == NULL ) + if (cfgst == NULL) return; - print_configitems(cfgst, cfgst->cfg, 0, root_cfgelems, 0); + assert (cfgst->logcfg == NULL); + cfgst->logcfg = logcfg; + print_configitems (cfgst, cfgst->cfg, 0, root_cfgelems, 0); } -void config_fini(struct cfgst *cfgst) +void config_free_source_info (struct cfgst *cfgst) { - assert(cfgst); - assert(cfgst->cfg == &config); - assert(config.valid); + assert (!cfgst->error); + ddsrt_avl_free (&cfgst_found_treedef, &cfgst->found, ddsrt_free); +} - free_all_elements(cfgst, cfgst->cfg, root_cfgelems); - dds_set_log_file(stderr); - dds_set_trace_file(stderr); - if (config.tracingOutputFile && config.tracingOutputFile != stdout && config.tracingOutputFile != stderr) { - fclose(config.tracingOutputFile); +void config_fini (struct cfgst *cfgst) +{ + assert (cfgst); + assert (cfgst->cfg != NULL); + assert (cfgst->cfg->valid); + + free_all_elements (cfgst, cfgst->cfg, root_cfgelems); + dds_set_log_file (stderr); + dds_set_trace_file (stderr); + if (cfgst->cfg->tracefp && cfgst->cfg->tracefp != stdout && cfgst->cfg->tracefp != stderr) { + fclose(cfgst->cfg->tracefp); } - memset(&config, 0, sizeof(config)); - config.valid = 0; - - ddsrt_avl_free(&cfgst_found_treedef, &cfgst->found, ddsrt_free); - ddsrt_free(cfgst); + memset (cfgst->cfg, 0, sizeof (*cfgst->cfg)); + ddsrt_avl_free (&cfgst_found_treedef, &cfgst->found, ddsrt_free); + ddsrt_free (cfgst); } #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -static char *get_partition_search_pattern(const char *partition, const char *topic) +static char *get_partition_search_pattern (const char *partition, const char *topic) { - size_t sz = strlen(partition) + strlen(topic) + 2; - char *pt = ddsrt_malloc(sz); - snprintf(pt, sz, "%s.%s", partition, topic); + size_t sz = strlen (partition) + strlen (topic) + 2; + char *pt = ddsrt_malloc (sz); + snprintf (pt, sz, "%s.%s", partition, topic); return pt; } -struct config_partitionmapping_listelem *find_partitionmapping(const char *partition, const char *topic) +struct config_partitionmapping_listelem *find_partitionmapping (const struct config *cfg, const char *partition, const char *topic) { - char *pt = get_partition_search_pattern(partition, topic); + char *pt = get_partition_search_pattern (partition, topic); struct config_partitionmapping_listelem *pm; - for ( pm = config.partitionMappings; pm; pm = pm->next ) - if ( WildcardOverlap(pt, pm->DCPSPartitionTopic) ) + for (pm = cfg->partitionMappings; pm; pm = pm->next) + if (WildcardOverlap (pt, pm->DCPSPartitionTopic)) break; - ddsrt_free(pt); + ddsrt_free (pt); return pm; } -struct config_networkpartition_listelem *find_networkpartition_by_id(uint32_t id) +struct config_networkpartition_listelem *find_networkpartition_by_id (const struct config *cfg, uint32_t id) { struct config_networkpartition_listelem *np; - for ( np = config.networkPartitions; np; np = np->next ) - if ( np->partitionId == id ) + for (np = cfg->networkPartitions; np; np = np->next) + if (np->partitionId == id) return np; return 0; } -int is_ignored_partition(const char *partition, const char *topic) +int is_ignored_partition (const struct config *cfg, const char *partition, const char *topic) { - char *pt = get_partition_search_pattern(partition, topic); + char *pt = get_partition_search_pattern (partition, topic); struct config_ignoredpartition_listelem *ip; - for ( ip = config.ignoredPartitions; ip; ip = ip->next ) - if ( WildcardOverlap(pt, ip->DCPSPartitionTopic) ) + for (ip = cfg->ignoredPartitions; ip; ip = ip->next) + if (WildcardOverlap(pt, ip->DCPSPartitionTopic)) break; - ddsrt_free(pt); + ddsrt_free (pt); return ip != NULL; } #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -struct config_channel_listelem *find_channel(nn_transport_priority_qospolicy_t transport_priority) +struct config_channel_listelem *find_channel (const struct config *cfg, nn_transport_priority_qospolicy_t transport_priority) { struct config_channel_listelem *c; /* Channel selection is to use the channel with the lowest priority not less than transport_priority, or else the one with the highest priority. */ - assert(config.channels != NULL); - assert(config.max_channel != NULL); - for ( c = config.channels; c; c = c->next ) { + assert(cfg->channels != NULL); + assert(cfg->max_channel != NULL); + for (c = cfg->channels; c; c = c->next) + { assert(c->next == NULL || c->next->priority > c->priority); - if ( transport_priority.value <= c->priority ) + if (transport_priority.value <= c->priority) return c; } - return config.max_channel; + return cfg->max_channel; } #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c index 8a75416..227c961 100644 --- a/src/core/ddsi/src/q_ddsi_discovery.c +++ b/src/core/ddsi/src/q_ddsi_discovery.c @@ -40,11 +40,10 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/q_lease.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/ddsi_serdata_default.h" #include "dds/ddsi/q_feature_check.h" -static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet) +static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet) { struct nn_locators_one *l; nn_locator_t first, samenet; @@ -53,7 +52,7 @@ static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_sam memset (&samenet, 0, sizeof (samenet)); /* Special case UDPv4 MC address generators - there is a bit of an type mismatch between an address generator (i.e., a set of addresses) and an address ... Whoever uses them is supposed to know that that is what he wants, so we simply given them priority. */ - if (ddsi_factory_supports (gv.m_factory, NN_LOCATOR_KIND_UDPv4)) + if (ddsi_factory_supports (gv->m_factory, NN_LOCATOR_KIND_UDPv4)) { for (l = locs->first; l != NULL; l = l->next) { @@ -72,20 +71,20 @@ static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_sam { /* Skip locators of the wrong kind */ - if (! ddsi_factory_supports (gv.m_factory, l->loc.kind)) + if (! ddsi_factory_supports (gv->m_factory, l->loc.kind)) { continue; } - if (l->loc.kind == NN_LOCATOR_KIND_UDPv4 && gv.extmask.kind != NN_LOCATOR_KIND_INVALID) + if (l->loc.kind == NN_LOCATOR_KIND_UDPv4 && gv->extmask.kind != NN_LOCATOR_KIND_INVALID) { /* If the examined locator is in the same subnet as our own external IP address, this locator will be translated into one in the same subnet as our own local ip and selected. */ struct in_addr tmp4 = *((struct in_addr *) (l->loc.address + 12)); - const struct in_addr ownip = *((struct in_addr *) (gv.ownloc.address + 12)); - const struct in_addr extip = *((struct in_addr *) (gv.extloc.address + 12)); - const struct in_addr extmask = *((struct in_addr *) (gv.extmask.address + 12)); + const struct in_addr ownip = *((struct in_addr *) (gv->ownloc.address + 12)); + const struct in_addr extip = *((struct in_addr *) (gv->extloc.address + 12)); + const struct in_addr extmask = *((struct in_addr *) (gv->extmask.address + 12)); if ((tmp4.s_addr & extmask.s_addr) == (extip.s_addr & extmask.s_addr)) { @@ -105,7 +104,7 @@ static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_sam addresses unles we're in "link-local" mode ourselves. Then we just hope for the best. */ const struct in6_addr *ip6 = (const struct in6_addr *) l->loc.address; - if (!gv.ipv6_link_local && IN6_IS_ADDR_LINKLOCAL (ip6)) + if (!gv->ipv6_link_local && IN6_IS_ADDR_LINKLOCAL (ip6)) continue; } #endif @@ -116,7 +115,7 @@ static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_sam first_set = 1; } - switch (ddsi_is_nearby_address(&l->loc, (size_t)gv.n_interfaces, gv.interfaces)) + switch (ddsi_is_nearby_address(gv, &l->loc, &gv->ownloc, (size_t) gv->n_interfaces, gv->interfaces)) { case DNAR_DISTANT: break; @@ -158,14 +157,14 @@ static int get_locator (nn_locator_t *loc, const nn_locators_t *locs, int uc_sam *** *****************************************************************************/ -static void maybe_add_pp_as_meta_to_as_disc (const struct addrset *as_meta) +static void maybe_add_pp_as_meta_to_as_disc (struct q_globals *gv, const struct addrset *as_meta) { - if (addrset_empty_mc (as_meta) || !(config.allowMulticast & AMC_SPDP)) + if (addrset_empty_mc (as_meta) || !(gv->config.allowMulticast & AMC_SPDP)) { nn_locator_t loc; if (addrset_any_uc (as_meta, &loc)) { - add_to_addrset (gv.as_disc, &loc); + add_to_addrset (gv, gv->as_disc, &loc); } } } @@ -176,7 +175,7 @@ static int write_mpayload (struct writer *wr, int alive, nn_parameterid_t keypar struct ddsi_plist_sample plist_sample; struct ddsi_serdata *serdata; nn_xmsg_payload_to_plistsample (&plist_sample, keyparam, mpayload); - serdata = ddsi_serdata_from_sample (gv.plist_topic, alive ? SDK_DATA : SDK_KEY, &plist_sample); + serdata = ddsi_serdata_from_sample (wr->e.gv->plist_topic, alive ? SDK_DATA : SDK_KEY, &plist_sample); serdata->statusinfo = alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER; serdata->timestamp = now (); return write_sample_nogc_notk (ts1, NULL, wr, serdata); @@ -198,11 +197,11 @@ int spdp_write (struct participant *pp) return 0; } - DDS_TRACE("spdp_write("PGUIDFMT")\n", PGUID (pp->e.guid)); + ETRACE (pp, "spdp_write("PGUIDFMT")\n", PGUID (pp->e.guid)); if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) { - DDS_TRACE("spdp_write("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); + ETRACE (pp, "spdp_write("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); return 0; } @@ -212,7 +211,7 @@ int spdp_write (struct participant *pp) terribly important, the msg will grow as needed, address space is essentially meaningless because we only use the message to construct the payload. */ - mpayload = nn_xmsg_new (gv.xmsgpool, &pp->e.guid.prefix, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid.prefix, 0, NN_XMSG_KIND_DATA); nn_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET | @@ -236,24 +235,24 @@ int spdp_write (struct participant *pp) def_uni_loc_one.next = NULL; meta_uni_loc_one.next = NULL; - if (config.many_sockets_mode == MSM_MANY_UNICAST) + if (pp->e.gv->config.many_sockets_mode == MSM_MANY_UNICAST) { def_uni_loc_one.loc = pp->m_locator; meta_uni_loc_one.loc = pp->m_locator; } else { - def_uni_loc_one.loc = gv.loc_default_uc; - meta_uni_loc_one.loc = gv.loc_meta_uc; + def_uni_loc_one.loc = pp->e.gv->loc_default_uc; + meta_uni_loc_one.loc = pp->e.gv->loc_meta_uc; } - if (config.publish_uc_locators) + if (pp->e.gv->config.publish_uc_locators) { ps.present |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; ps.aliased |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; } - if (config.allowMulticast) + if (pp->e.gv->config.allowMulticast) { int include = 0; #ifdef DDSI_INCLUDE_SSM @@ -261,12 +260,12 @@ int spdp_write (struct participant *pp) we will simply advertise it. The recipients better understand it means the writers will publish to address and the readers favour SSM. */ - if (ddsi_is_ssm_mcaddr (&gv.loc_default_mc)) - include = (config.allowMulticast & AMC_SSM) != 0; + if (ddsi_is_ssm_mcaddr (pp->e.gv, &pp->e.gv->loc_default_mc)) + include = (pp->e.gv->config.allowMulticast & AMC_SSM) != 0; else - include = (config.allowMulticast & AMC_ASM) != 0; + include = (pp->e.gv->config.allowMulticast & AMC_ASM) != 0; #else - if (config.allowMulticast & AMC_ASM) + if (pp->e.gv->config.allowMulticast & AMC_ASM) include = 1; #endif if (include) @@ -280,39 +279,40 @@ int spdp_write (struct participant *pp) ps.metatraffic_multicast_locators.first = ps.metatraffic_multicast_locators.last = &meta_multi_loc_one; def_multi_loc_one.next = NULL; - def_multi_loc_one.loc = gv.loc_default_mc; + def_multi_loc_one.loc = pp->e.gv->loc_default_mc; meta_multi_loc_one.next = NULL; - meta_multi_loc_one.loc = gv.loc_meta_mc; + meta_multi_loc_one.loc = pp->e.gv->loc_meta_mc; } } - ps.participant_lease_duration = nn_to_ddsi_duration (pp->lease_duration); + ps.participant_lease_duration = pp->lease_duration; /* Add PrismTech specific version information */ { ps.present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; + memset (&ps.prismtech_participant_version_info, 0, sizeof (ps.prismtech_participant_version_info)); ps.prismtech_participant_version_info.version = 0; ps.prismtech_participant_version_info.flags = NN_PRISMTECH_FL_DDSI2_PARTICIPANT_FLAG | NN_PRISMTECH_FL_PTBES_FIXED_0 | NN_PRISMTECH_FL_SUPPORTS_STATUSINFOX; - if (config.besmode == BESMODE_MINIMAL) + if (pp->e.gv->config.besmode == BESMODE_MINIMAL) ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_MINIMAL_BES_MODE; - ddsrt_mutex_lock (&gv.privileged_pp_lock); + ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); if (pp->is_ddsi2_pp) ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2; - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock); ddsrt_gethostname(node, sizeof(node)-1); node[sizeof(node)-1] = '\0'; size = strlen(node) + strlen(DDS_VERSION) + strlen(DDS_HOST_NAME) + strlen(DDS_TARGET_NAME) + 4; /* + ///'\0' */ ps.prismtech_participant_version_info.internals = ddsrt_malloc(size); (void) snprintf(ps.prismtech_participant_version_info.internals, size, "%s/%s/%s/%s", node, DDS_VERSION, DDS_HOST_NAME, DDS_TARGET_NAME); - DDS_TRACE("spdp_write("PGUIDFMT") - internals: %s\n", PGUID (pp->e.guid), ps.prismtech_participant_version_info.internals); + ETRACE (pp, "spdp_write("PGUIDFMT") - internals: %s\n", PGUID (pp->e.guid), ps.prismtech_participant_version_info.internals); } /* Participant QoS's insofar as they are set, different from the default, and mapped to the SPDP data, rather than to the PrismTech-specific CMParticipant endpoint. Currently, that means just USER_DATA. */ - qosdiff = nn_xqos_delta (&pp->plist->qos, &gv.default_plist_pp.qos, QP_USER_DATA); - if (config.explicitly_publish_qos_set_to_default) + qosdiff = nn_xqos_delta (&pp->plist->qos, &pp->e.gv->default_plist_pp.qos, QP_USER_DATA); + if (pp->e.gv->config.explicitly_publish_qos_set_to_default) qosdiff |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; assert (ps.qos.present == 0); @@ -335,11 +335,11 @@ int spdp_dispose_unregister (struct participant *pp) if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) { - DDS_TRACE("spdp_dispose_unregister("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); + ETRACE (pp, "spdp_dispose_unregister("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); return 0; } - mpayload = nn_xmsg_new (gv.xmsgpool, &pp->e.guid.prefix, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid.prefix, 0, NN_XMSG_KIND_DATA); nn_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = pp->e.guid; @@ -381,84 +381,85 @@ static unsigned pseudo_random_delay (const nn_guid_t *x, const nn_guid_t *y, nn_ return (unsigned) (m >> 32); } -static void respond_to_spdp (const nn_guid_t *dest_proxypp_guid) +static void respond_to_spdp (const struct q_globals *gv, const nn_guid_t *dest_proxypp_guid) { struct ephash_enum_participant est; struct participant *pp; nn_mtime_t tnow = now_mt (); - ephash_enum_participant_init (&est); + ephash_enum_participant_init (&est, gv->guid_hash); while ((pp = ephash_enum_participant_next (&est)) != NULL) { /* delay_base has 32 bits, so delay_norm is approximately 1s max; - delay_max <= 1s by config checks */ + delay_max <= 1s by gv.config checks */ unsigned delay_base = pseudo_random_delay (&pp->e.guid, dest_proxypp_guid, tnow); unsigned delay_norm = delay_base >> 2; - int64_t delay_max_ms = config.spdp_response_delay_max / 1000000; + int64_t delay_max_ms = gv->config.spdp_response_delay_max / 1000000; int64_t delay = (int64_t) delay_norm * delay_max_ms / 1000; nn_mtime_t tsched = add_duration_to_mtime (tnow, delay); - DDS_TRACE(" %"PRId64, delay); - if (!config.unicast_response_to_spdp_messages) + GVTRACE (" %"PRId64, delay); + if (!pp->e.gv->config.unicast_response_to_spdp_messages) /* pp can't reach gc_delete_participant => can safely reschedule */ resched_xevent_if_earlier (pp->spdp_xevent, tsched); else - qxev_spdp (tsched, &pp->e.guid, dest_proxypp_guid); + qxev_spdp (gv->xevents, tsched, &pp->e.guid, dest_proxypp_guid); } ephash_enum_participant_fini (&est); } static int handle_SPDP_dead (const struct receiver_state *rst, nn_wctime_t timestamp, const nn_plist_t *datap, unsigned statusinfo) { + struct q_globals * const gv = rst->gv; nn_guid_t guid; - if (!(dds_get_log_mask() & DDS_LC_DISCOVERY)) - DDS_LOG(DDS_LC_DISCOVERY, "SPDP ST%x", statusinfo); + if (!(gv->logconfig.c.mask & DDS_LC_DISCOVERY)) + GVLOGDISC ("SPDP ST%x", statusinfo); if (datap->present & PP_PARTICIPANT_GUID) { guid = datap->participant_guid; - DDS_LOG(DDS_LC_DISCOVERY, " %"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32, PGUID (guid)); + GVLOGDISC (" %"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32, PGUID (guid)); assert (guid.entityid.u == NN_ENTITYID_PARTICIPANT); - if (delete_proxy_participant_by_guid (&guid, timestamp, 0) < 0) + if (delete_proxy_participant_by_guid (gv, &guid, timestamp, 0) < 0) { - DDS_LOG(DDS_LC_DISCOVERY, " unknown"); + GVLOGDISC (" unknown"); } else { - DDS_LOG(DDS_LC_DISCOVERY, " delete"); + GVLOGDISC (" delete"); } } else { - DDS_WARNING("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]); + GVWARNING ("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]); } return 1; } -static void allowmulticast_aware_add_to_addrset (struct addrset *as, const nn_locator_t *loc) +static void allowmulticast_aware_add_to_addrset (const struct q_globals *gv, uint32_t allow_multicast, struct addrset *as, const nn_locator_t *loc) { #if DDSI_INCLUDE_SSM - if (ddsi_is_ssm_mcaddr (loc)) + if (ddsi_is_ssm_mcaddr (gv, loc)) { - if (!(config.allowMulticast & AMC_SSM)) + if (!(allow_multicast & AMC_SSM)) return; } - else if (ddsi_is_mcaddr (loc)) + else if (ddsi_is_mcaddr (gv, loc)) { - if (!(config.allowMulticast & AMC_ASM)) + if (!(allow_multicast & AMC_ASM)) return; } #else - if (ddsi_is_mcaddr (loc) && !(config.allowMulticast & AMC_ASM)) + if (ddsi_is_mcaddr (gv, loc) && !(allow_multicast & AMC_ASM)) return; #endif - add_to_addrset (as, loc); + add_to_addrset (gv, as, loc); } -static struct proxy_participant *find_ddsi2_proxy_participant (const nn_guid_t *ppguid) +static struct proxy_participant *find_ddsi2_proxy_participant (const struct ephash *guid_hash, const nn_guid_t *ppguid) { struct ephash_enum_proxy_participant it; struct proxy_participant *pp; - ephash_enum_proxy_participant_init (&it); + ephash_enum_proxy_participant_init (&it, guid_hash); while ((pp = ephash_enum_proxy_participant_next (&it)) != NULL) { if (vendor_is_eclipse_or_opensplice (pp->vendor) && pp->e.guid.prefix.u[0] == ppguid->prefix.u[0] && pp->is_ddsi2_pp) @@ -468,27 +469,27 @@ static struct proxy_participant *find_ddsi2_proxy_participant (const nn_guid_t * return pp; } -static void make_participants_dependent_on_ddsi2 (const nn_guid_t *ddsi2guid, nn_wctime_t timestamp) +static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const nn_guid_t *ddsi2guid, nn_wctime_t timestamp) { struct ephash_enum_proxy_participant it; struct proxy_participant *pp, *d2pp; struct lease *d2pp_lease; - if ((d2pp = ephash_lookup_proxy_participant_guid (ddsi2guid)) == NULL) + if ((d2pp = ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid)) == NULL) return; d2pp_lease = ddsrt_atomic_ldvoidp (&d2pp->lease); - ephash_enum_proxy_participant_init (&it); + ephash_enum_proxy_participant_init (&it, gv->guid_hash); while ((pp = ephash_enum_proxy_participant_next (&it)) != NULL) { if (vendor_is_eclipse_or_opensplice (pp->vendor) && pp->e.guid.prefix.u[0] == ddsi2guid->prefix.u[0] && !pp->is_ddsi2_pp) { - DDS_TRACE("proxy participant "PGUIDFMT" depends on ddsi2 "PGUIDFMT, PGUID (pp->e.guid), PGUID (*ddsi2guid)); + GVTRACE ("proxy participant "PGUIDFMT" depends on ddsi2 "PGUIDFMT, PGUID (pp->e.guid), PGUID (*ddsi2guid)); ddsrt_mutex_lock (&pp->e.lock); pp->privileged_pp_guid = *ddsi2guid; ddsrt_mutex_unlock (&pp->e.lock); proxy_participant_reassign_lease (pp, d2pp_lease); - DDS_TRACE("\n"); + GVTRACE ("\n"); - if (ephash_lookup_proxy_participant_guid (ddsi2guid) == NULL) + if (ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid) == NULL) { /* If DDSI2 has been deleted here (i.e., very soon after having been created), we don't know whether pp will be @@ -501,13 +502,14 @@ static void make_participants_dependent_on_ddsi2 (const nn_guid_t *ddsi2guid, nn if (pp != NULL) { - DDS_TRACE("make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", PGUID (*ddsi2guid), PGUID (pp->e.guid)); - delete_proxy_participant_by_guid (&pp->e.guid, timestamp, 1); + GVTRACE ("make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", PGUID (*ddsi2guid), PGUID (pp->e.guid)); + delete_proxy_participant_by_guid (gv, &pp->e.guid, timestamp, 1); } } -static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t timestamp, const nn_plist_t *datap) +static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_wctime_t timestamp, const nn_plist_t *datap) { + struct q_globals * const gv = rst->gv; const unsigned bes_sedp_announcer_mask = NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER | NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; @@ -516,12 +518,12 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time unsigned builtin_endpoint_set; unsigned prismtech_builtin_endpoint_set; nn_guid_t privileged_pp_guid; - nn_duration_t lease_duration; + dds_duration_t lease_duration; unsigned custom_flags = 0; if (!(datap->present & PP_PARTICIPANT_GUID) || !(datap->present & PP_BUILTIN_ENDPOINT_SET)) { - DDS_WARNING("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]); + GVWARNING ("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]); return 1; } @@ -537,10 +539,10 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER)) != (NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER | NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER)) && - config.assume_rti_has_pmd_endpoints) + gv->config.assume_rti_has_pmd_endpoints) { - DDS_LOG(DDS_LC_DISCOVERY, "data (SPDP, vendor %u.%u): assuming unadvertised PMD endpoints do exist\n", - rst->vendor.id[0], rst->vendor.id[1]); + GVLOGDISC ("data (SPDP, vendor %u.%u): assuming unadvertised PMD endpoints do exist\n", + rst->vendor.id[0], rst->vendor.id[1]); builtin_endpoint_set |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER | NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; @@ -554,7 +556,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time but it would cause problems with cases where we would be happy with only (say) CM participant. Have to do a backwards-compatible fix because it has already been released with the flags all aliased to bits 0 and 1 ... */ - DDS_LOG(DDS_LC_DISCOVERY, " (ptbes_fixed_0 %x)", prismtech_builtin_endpoint_set); + GVLOGDISC (" (ptbes_fixed_0 %x)", prismtech_builtin_endpoint_set); if (prismtech_builtin_endpoint_set & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER) prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER; if (prismtech_builtin_endpoint_set & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER) @@ -567,43 +569,46 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time consequently the looped back packet may appear to be from an unknown participant. So we handle that, too. */ - if (is_deleted_participant_guid (&datap->participant_guid, DPG_REMOTE)) + if (is_deleted_participant_guid (gv->deleted_participants, &datap->participant_guid, DPG_REMOTE)) { - DDS_LOG(DDS_LC_TRACE, "SPDP ST0 "PGUIDFMT" (recently deleted)", PGUID (datap->participant_guid)); + RSTTRACE ("SPDP ST0 "PGUIDFMT" (recently deleted)", PGUID (datap->participant_guid)); return 1; } { int islocal = 0; - if (ephash_lookup_participant_guid (&datap->participant_guid)) + if (ephash_lookup_participant_guid (gv->guid_hash, &datap->participant_guid)) islocal = 1; if (islocal) { - DDS_LOG(DDS_LC_TRACE, "SPDP ST0 "PGUIDFMT" (local %d)", PGUID (datap->participant_guid), islocal); + RSTTRACE ("SPDP ST0 "PGUIDFMT" (local %d)", PGUID (datap->participant_guid), islocal); return 0; } } - if ((proxypp = ephash_lookup_proxy_participant_guid (&datap->participant_guid)) != NULL) + if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &datap->participant_guid)) != NULL) { /* SPDP processing is so different from normal processing that we are even skipping the automatic lease renewal. Therefore do it regardless of - config.arrival_of_data_asserts_pp_and_ep_liveliness. */ - DDS_LOG(DDS_LC_TRACE, "SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid)); + gv.config.arrival_of_data_asserts_pp_and_ep_liveliness. */ + RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid)); lease_renew (ddsrt_atomic_ldvoidp (&proxypp->lease), now_et ()); ddsrt_mutex_lock (&proxypp->e.lock); - if (proxypp->implicitly_created) + if (proxypp->implicitly_created || seq > proxypp->seq) { - DDS_LOG(DDS_LC_DISCOVERY, " (NEW was-implicitly-created)"); + if (proxypp->implicitly_created) + GVLOGDISC (" (NEW was-implicitly-created)"); + else + GVLOGDISC (" (update)"); proxypp->implicitly_created = 0; - update_proxy_participant_plist_locked (proxypp, datap, UPD_PROXYPP_SPDP, timestamp); + update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp); } ddsrt_mutex_unlock (&proxypp->e.lock); return 0; } - DDS_LOG(DDS_LC_DISCOVERY, "SPDP ST0 "PGUIDFMT" bes %x ptbes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set, prismtech_builtin_endpoint_set); + GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x ptbes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set, prismtech_builtin_endpoint_set); if (datap->present & PP_PARTICIPANT_LEASE_DURATION) { @@ -611,8 +616,8 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time } else { - DDS_LOG(DDS_LC_DISCOVERY, " (PARTICIPANT_LEASE_DURATION defaulting to 100s)"); - lease_duration = nn_to_ddsi_duration (100 * T_SECOND); + GVLOGDISC (" (PARTICIPANT_LEASE_DURATION defaulting to 100s)"); + lease_duration = 100 * T_SECOND; } if (datap->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) { @@ -623,13 +628,13 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time (datap->prismtech_participant_version_info.flags & NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2)) custom_flags |= CF_PARTICIPANT_IS_DDSI2; - DDS_LOG(DDS_LC_DISCOVERY, " (0x%08x-0x%08x-0x%08x-0x%08x-0x%08x %s)", - datap->prismtech_participant_version_info.version, - datap->prismtech_participant_version_info.flags, - datap->prismtech_participant_version_info.unused[0], - datap->prismtech_participant_version_info.unused[1], - datap->prismtech_participant_version_info.unused[2], - datap->prismtech_participant_version_info.internals); + GVLOGDISC (" (0x%08x-0x%08x-0x%08x-0x%08x-0x%08x %s)", + datap->prismtech_participant_version_info.version, + datap->prismtech_participant_version_info.flags, + datap->prismtech_participant_version_info.unused[0], + datap->prismtech_participant_version_info.unused[1], + datap->prismtech_participant_version_info.unused[2], + datap->prismtech_participant_version_info.internals); } /* If any of the SEDP announcer are missing AND the guid prefix of @@ -643,23 +648,23 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time if ((builtin_endpoint_set & bes_sedp_announcer_mask) != bes_sedp_announcer_mask && memcmp (&privileged_pp_guid, &datap->participant_guid, sizeof (nn_guid_t)) != 0) { - DDS_LOG(DDS_LC_DISCOVERY, " (depends on "PGUIDFMT")", PGUID (privileged_pp_guid)); + GVLOGDISC (" (depends on "PGUIDFMT")", PGUID (privileged_pp_guid)); /* never expire lease for this proxy: it won't actually expire until the "privileged" one expires anyway */ - lease_duration = nn_to_ddsi_duration (T_NEVER); + lease_duration = T_NEVER; } else if (vendor_is_eclipse_or_opensplice (rst->vendor) && !(custom_flags & CF_PARTICIPANT_IS_DDSI2)) { /* Non-DDSI2 participants are made dependent on DDSI2 (but DDSI2 itself need not be discovered yet) */ struct proxy_participant *ddsi2; - if ((ddsi2 = find_ddsi2_proxy_participant (&datap->participant_guid)) == NULL) + if ((ddsi2 = find_ddsi2_proxy_participant (gv->guid_hash, &datap->participant_guid)) == NULL) memset (&privileged_pp_guid.prefix, 0, sizeof (privileged_pp_guid.prefix)); else { privileged_pp_guid.prefix = ddsi2->e.guid.prefix; - lease_duration = nn_to_ddsi_duration (T_NEVER); - DDS_LOG(DDS_LC_DISCOVERY, " (depends on "PGUIDFMT")", PGUID (privileged_pp_guid)); + lease_duration = T_NEVER; + GVLOGDISC (" (depends on "PGUIDFMT")", PGUID (privileged_pp_guid)); } } else @@ -675,60 +680,61 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time as_default = new_addrset (); as_meta = new_addrset (); - if ((datap->present & PP_DEFAULT_MULTICAST_LOCATOR) && (get_locator (&loc, &datap->default_multicast_locators, 0))) - allowmulticast_aware_add_to_addrset (as_default, &loc); - if ((datap->present & PP_METATRAFFIC_MULTICAST_LOCATOR) && (get_locator (&loc, &datap->metatraffic_multicast_locators, 0))) - allowmulticast_aware_add_to_addrset (as_meta, &loc); + if ((datap->present & PP_DEFAULT_MULTICAST_LOCATOR) && (get_locator (gv, &loc, &datap->default_multicast_locators, 0))) + allowmulticast_aware_add_to_addrset (gv, gv->config.allowMulticast, as_default, &loc); + if ((datap->present & PP_METATRAFFIC_MULTICAST_LOCATOR) && (get_locator (gv, &loc, &datap->metatraffic_multicast_locators, 0))) + allowmulticast_aware_add_to_addrset (gv, gv->config.allowMulticast, as_meta, &loc); /* If no multicast locators or multicast TTL > 1, assume IP (multicast) routing can be relied upon to reach the remote participant, else only accept nodes with an advertised unicast address in the same subnet to protect against multicasts being received over an unexpected interface (which sometimes appears to occur) */ if (addrset_empty_mc (as_default) && addrset_empty_mc (as_meta)) uc_same_subnet = 0; - else if (config.multicast_ttl > 1) + else if (gv->config.multicast_ttl > 1) uc_same_subnet = 0; else { uc_same_subnet = 1; - DDS_LOG(DDS_LC_DISCOVERY, " subnet-filter"); + GVLOGDISC (" subnet-filter"); } /* If unicast locators not present, then try to obtain from connection */ - if (!config.tcp_use_peeraddr_for_unicast && (datap->present & PP_DEFAULT_UNICAST_LOCATOR) && (get_locator (&loc, &datap->default_unicast_locators, uc_same_subnet))) - add_to_addrset (as_default, &loc); + if (!gv->config.tcp_use_peeraddr_for_unicast && (datap->present & PP_DEFAULT_UNICAST_LOCATOR) && (get_locator (gv, &loc, &datap->default_unicast_locators, uc_same_subnet))) + add_to_addrset (gv, as_default, &loc); else { - DDS_LOG(DDS_LC_DISCOVERY, " (srclocD)"); - add_to_addrset (as_default, &rst->srcloc); + GVLOGDISC (" (srclocD)"); + add_to_addrset (gv, as_default, &rst->srcloc); } - if (!config.tcp_use_peeraddr_for_unicast && (datap->present & PP_METATRAFFIC_UNICAST_LOCATOR) && (get_locator (&loc, &datap->metatraffic_unicast_locators, uc_same_subnet))) - add_to_addrset (as_meta, &loc); + if (!gv->config.tcp_use_peeraddr_for_unicast && (datap->present & PP_METATRAFFIC_UNICAST_LOCATOR) && (get_locator (gv, &loc, &datap->metatraffic_unicast_locators, uc_same_subnet))) + add_to_addrset (gv, as_meta, &loc); else { - DDS_LOG(DDS_LC_DISCOVERY, " (srclocM)"); - add_to_addrset (as_meta, &rst->srcloc); + GVLOGDISC (" (srclocM)"); + add_to_addrset (gv, as_meta, &rst->srcloc); } - nn_log_addrset(DDS_LC_DISCOVERY, " (data", as_default); - nn_log_addrset(DDS_LC_DISCOVERY, " meta", as_meta); - DDS_LOG(DDS_LC_DISCOVERY, ")"); + nn_log_addrset (gv, DDS_LC_DISCOVERY, " (data", as_default); + nn_log_addrset (gv, DDS_LC_DISCOVERY, " meta", as_meta); + GVLOGDISC (")"); } if (addrset_empty_uc (as_default) || addrset_empty_uc (as_meta)) { - DDS_LOG(DDS_LC_DISCOVERY, " (no unicast address"); + GVLOGDISC (" (no unicast address"); unref_addrset (as_default); unref_addrset (as_meta); return 1; } - DDS_LOG(DDS_LC_DISCOVERY, " QOS={"); - nn_log_xqos(DDS_LC_DISCOVERY, &datap->qos); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + GVLOGDISC (" QOS={"); + nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, &datap->qos); + GVLOGDISC ("}\n"); - maybe_add_pp_as_meta_to_as_disc (as_meta); + maybe_add_pp_as_meta_to_as_disc (gv, as_meta); new_proxy_participant ( + gv, &datap->participant_guid, builtin_endpoint_set, prismtech_builtin_endpoint_set, @@ -736,10 +742,11 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time as_default, as_meta, datap, - nn_from_ddsi_duration (lease_duration), + lease_duration, rst->vendor, custom_flags, - timestamp + timestamp, + seq ); /* Force transmission of SPDP messages - we're not very careful @@ -750,12 +757,12 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time (rst->dst_guid_prefix.u[0] != 0 || rst->dst_guid_prefix.u[1] != 0 || rst->dst_guid_prefix.u[2] != 0); if (!have_dst) { - DDS_LOG(DDS_LC_DISCOVERY, "broadcasted SPDP packet -> answering"); - respond_to_spdp (&datap->participant_guid); + GVLOGDISC ("broadcasted SPDP packet -> answering"); + respond_to_spdp (gv, &datap->participant_guid); } else { - DDS_LOG(DDS_LC_DISCOVERY, "directed SPDP packet -> not responding\n"); + GVLOGDISC ("directed SPDP packet -> not responding\n"); } } @@ -763,29 +770,31 @@ static int handle_SPDP_alive (const struct receiver_state *rst, nn_wctime_t time { /* If we just discovered DDSI2, make sure any existing participants served by it are made dependent on it */ - make_participants_dependent_on_ddsi2 (&datap->participant_guid, timestamp); + make_participants_dependent_on_ddsi2 (gv, &datap->participant_guid, timestamp); } else if (privileged_pp_guid.prefix.u[0] || privileged_pp_guid.prefix.u[1] || privileged_pp_guid.prefix.u[2]) { /* If we just created a participant dependent on DDSI2, make sure DDSI2 still exists. There is a risk of racing the lease expiry of DDSI2. */ - if (ephash_lookup_proxy_participant_guid (&privileged_pp_guid) == NULL) + if (ephash_lookup_proxy_participant_guid (gv->guid_hash, &privileged_pp_guid) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", PGUID (privileged_pp_guid), PGUID (datap->participant_guid)); - delete_proxy_participant_by_guid (&datap->participant_guid, timestamp, 1); + GVLOGDISC ("make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", + PGUID (privileged_pp_guid), PGUID (datap->participant_guid)); + delete_proxy_participant_by_guid (gv, &datap->participant_guid, timestamp, 1); } } return 1; } -static void handle_SPDP (const struct receiver_state *rst, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) +static void handle_SPDP (const struct receiver_state *rst, seqno_t seq, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, uint32_t len) { + struct q_globals * const gv = rst->gv; const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - DDS_TRACE("SPDP ST%x", statusinfo); + RSTTRACE("SPDP ST%x", statusinfo); if (data == NULL) { - DDS_TRACE(" no payload?\n"); + RSTTRACE(" no payload?\n"); return; } else @@ -793,23 +802,26 @@ static void handle_SPDP (const struct receiver_state *rst, nn_wctime_t timestamp nn_plist_t decoded_data; nn_plist_src_t src; int interesting = 0; - int plist_ret; + dds_return_t plist_ret; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = data->identifier; src.buf = (unsigned char *) data + 4; src.bufsz = len - 4; + src.strict = NN_STRICT_P (gv->config); + src.factory = gv->m_factory; + src.logconfig = &gv->logconfig; if ((plist_ret = nn_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING("SPDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); + if (plist_ret != DDS_RETCODE_UNSUPPORTED) + GVWARNING ("SPDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); return; } switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { case 0: - interesting = handle_SPDP_alive (rst, timestamp, &decoded_data); + interesting = handle_SPDP_alive (rst, seq, timestamp, &decoded_data); break; case NN_STATUSINFO_DISPOSE: @@ -820,13 +832,18 @@ static void handle_SPDP (const struct receiver_state *rst, nn_wctime_t timestamp } nn_plist_fini (&decoded_data); - DDS_LOG(interesting ? DDS_LC_DISCOVERY : DDS_LC_TRACE, "\n"); + GVLOG (interesting ? DDS_LC_DISCOVERY : DDS_LC_TRACE, "\n"); } } -static void add_locator_to_ps (const nn_locator_t *loc, void *arg) +struct add_locator_to_ps_arg { + struct q_globals *gv; + nn_plist_t *ps; +}; + +static void add_locator_to_ps (const nn_locator_t *loc, void *varg) { - nn_plist_t *ps = (nn_plist_t *) arg; + struct add_locator_to_ps_arg *arg = varg; struct nn_locators_one *elem = ddsrt_malloc (sizeof (struct nn_locators_one)); struct nn_locators *locs; unsigned present_flag; @@ -834,19 +851,19 @@ static void add_locator_to_ps (const nn_locator_t *loc, void *arg) elem->loc = *loc; elem->next = NULL; - if (ddsi_is_mcaddr (loc)) { - locs = &ps->multicast_locators; + if (ddsi_is_mcaddr (arg->gv, loc)) { + locs = &arg->ps->multicast_locators; present_flag = PP_MULTICAST_LOCATOR; } else { - locs = &ps->unicast_locators; + locs = &arg->ps->unicast_locators; present_flag = PP_UNICAST_LOCATOR; } - if (!(ps->present & present_flag)) + if (!(arg->ps->present & present_flag)) { locs->n = 0; locs->first = locs->last = NULL; - ps->present |= present_flag; + arg->ps->present |= present_flag; } locs->n++; if (locs->first) @@ -866,9 +883,10 @@ static int sedp_write_endpoint ( struct writer *wr, int alive, const nn_guid_t *epguid, const struct entity_common *common, const struct endpoint_common *epcommon, - const nn_xqos_t *xqos, struct addrset *as) + const dds_qos_t *xqos, struct addrset *as) { - const nn_xqos_t *defqos = is_writer_entityid (epguid->entityid) ? &gv.default_xqos_wr : &gv.default_xqos_rd; + struct q_globals * const gv = wr->e.gv; + const dds_qos_t *defqos = is_writer_entityid (epguid->entityid) ? &gv->default_xqos_wr : &gv->default_xqos_rd; struct nn_xmsg *mpayload; uint64_t qosdiff; nn_plist_t ps; @@ -913,7 +931,7 @@ static int sedp_write_endpoint the default. */ if (!is_writer_entityid (epguid->entityid)) { - const struct reader *rd = ephash_lookup_reader_guid (epguid); + const struct reader *rd = ephash_lookup_reader_guid (gv->guid_hash, epguid); assert (rd); if (rd->favours_ssm) { @@ -924,12 +942,15 @@ static int sedp_write_endpoint #endif qosdiff = nn_xqos_delta (xqos, defqos, ~(uint64_t)0); - if (config.explicitly_publish_qos_set_to_default) + if (gv->config.explicitly_publish_qos_set_to_default) qosdiff |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; if (as) { - addrset_forall (as, add_locator_to_ps, &ps); + struct add_locator_to_ps_arg arg; + arg.gv = gv; + arg.ps = &ps; + addrset_forall (as, add_locator_to_ps, &arg); } } @@ -937,13 +958,13 @@ static int sedp_write_endpoint the QoS and other settings. So the header fields aren't really important, except that they need to be set to reasonable things or it'll crash */ - mpayload = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); if (xqos) nn_xqos_addtomsg (mpayload, xqos, qosdiff); nn_xmsg_addpar_sentinel (mpayload); nn_plist_fini (&ps); - DDS_LOG(DDS_LC_DISCOVERY, "sedp: write for "PGUIDFMT" via "PGUIDFMT"\n", PGUID (*epguid), PGUID (wr->e.guid)); + GVLOGDISC ("sedp: write for "PGUIDFMT" via "PGUIDFMT"\n", PGUID (*epguid), PGUID (wr->e.guid)); ret = write_mpayload (wr, alive, PID_ENDPOINT_GUID, mpayload); nn_xmsg_free (mpayload); return ret; @@ -953,7 +974,7 @@ static struct writer *get_sedp_writer (const struct participant *pp, unsigned en { struct writer *sedp_wr = get_builtin_writer (pp, entityid); if (sedp_wr == NULL) - DDS_FATAL("sedp_write_writer: no SEDP builtin writer %x for "PGUIDFMT"\n", entityid, PGUID (pp->e.guid)); + DDS_FATAL ("sedp_write_writer: no SEDP builtin writer %x for "PGUIDFMT"\n", entityid, PGUID (pp->e.guid)); return sedp_wr; } @@ -1007,19 +1028,19 @@ int sedp_dispose_unregister_reader (struct reader *rd) return 0; } -static const char *durability_to_string (nn_durability_kind_t k) +static const char *durability_to_string (dds_durability_kind_t k) { switch (k) { - case NN_VOLATILE_DURABILITY_QOS: return "volatile"; - case NN_TRANSIENT_LOCAL_DURABILITY_QOS: return "transient-local"; - case NN_TRANSIENT_DURABILITY_QOS: return "transient"; - case NN_PERSISTENT_DURABILITY_QOS: return "persistent"; + case DDS_DURABILITY_VOLATILE: return "volatile"; + case DDS_DURABILITY_TRANSIENT_LOCAL: return "transient-local"; + case DDS_DURABILITY_TRANSIENT: return "transient"; + case DDS_DURABILITY_PERSISTENT: return "persistent"; } return "undefined-durability"; } -static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp) +static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const nn_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq) { nn_guid_t privguid; nn_plist_t pp_plist; @@ -1036,14 +1057,14 @@ static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppg { nn_vendorid_t actual_vendorid; /* Some endpoint that we discovered through the DS, but then it must have at least some locators */ - DDS_TRACE(" from-DS %"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32, PGUID (privguid)); + GVTRACE (" from-DS %"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32, PGUID (privguid)); /* avoid "no address" case, so we never create the proxy participant for nothing (FIXME: rework some of this) */ if (!(datap->present & (PP_UNICAST_LOCATOR | PP_MULTICAST_LOCATOR))) { - DDS_TRACE(" data locator absent\n"); + GVTRACE (" data locator absent\n"); goto err; } - DDS_TRACE(" new-proxypp "PGUIDFMT"\n", PGUID (*ppguid)); + GVTRACE (" new-proxypp "PGUIDFMT"\n", PGUID (*ppguid)); /* We need to handle any source of entities, but we really want to try to keep the GIDs (and certainly the systemId component) unchanged for OSPL. The new proxy participant will take the GID from the GUID if it is from a "modern" OSPL that advertises it includes all GIDs in @@ -1056,7 +1077,7 @@ static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppg doing anything about (1). That means we fall back to the legacy mode of locally generating GIDs but leaving the system id unchanged if the remote is OSPL. */ actual_vendorid = (datap->present & PP_VENDORID) ? datap->vendorid : vendorid; - new_proxy_participant(ppguid, 0, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, T_NEVER, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp); + new_proxy_participant(gv, ppguid, 0, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, T_NEVER, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq); } else if (ppguid->prefix.u[0] == src_guid_prefix->u[0] && vendor_is_eclipse_or_opensplice (vendorid)) { @@ -1064,19 +1085,19 @@ static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppg readers or writers, only if remote ddsi2 is provably running with a minimal built-in endpoint set */ struct proxy_participant *privpp; - if ((privpp = ephash_lookup_proxy_participant_guid (&privguid)) == NULL) { - DDS_TRACE(" unknown-src-proxypp?\n"); + if ((privpp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &privguid)) == NULL) { + GVTRACE (" unknown-src-proxypp?\n"); goto err; } else if (!privpp->is_ddsi2_pp) { - DDS_TRACE(" src-proxypp-not-ddsi2?\n"); + GVTRACE (" src-proxypp-not-ddsi2?\n"); goto err; } else if (!privpp->minimal_bes_mode) { - DDS_TRACE(" src-ddsi2-not-minimal-bes-mode?\n"); + GVTRACE (" src-ddsi2-not-minimal-bes-mode?\n"); goto err; } else { struct addrset *as_default, *as_meta; nn_plist_t tmp_plist; - DDS_TRACE(" from-ddsi2 "PGUIDFMT, PGUID (privguid)); + GVTRACE (" from-ddsi2 "PGUIDFMT, PGUID (privguid)); nn_plist_init_empty (&pp_plist); ddsrt_mutex_lock (&privpp->e.lock); @@ -1086,27 +1107,28 @@ static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppg tmp_plist = *privpp->plist; tmp_plist.present = PP_PARTICIPANT_GUID | PP_PRISMTECH_PARTICIPANT_VERSION_INFO; tmp_plist.participant_guid = *ppguid; - nn_plist_mergein_missing (&pp_plist, &tmp_plist); + nn_plist_mergein_missing (&pp_plist, &tmp_plist, ~(uint64_t)0, ~(uint64_t)0); ddsrt_mutex_unlock (&privpp->e.lock); pp_plist.prismtech_participant_version_info.flags &= ~NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2; - new_proxy_participant (ppguid, 0, 0, &privguid, as_default, as_meta, &pp_plist, T_NEVER, vendorid, CF_IMPLICITLY_CREATED_PROXYPP | CF_PROXYPP_NO_SPDP, timestamp); + new_proxy_participant (gv, ppguid, 0, 0, &privguid, as_default, as_meta, &pp_plist, T_NEVER, vendorid, CF_IMPLICITLY_CREATED_PROXYPP | CF_PROXYPP_NO_SPDP, timestamp, seq); } } err: nn_plist_fini (&pp_plist); - return ephash_lookup_proxy_participant_guid (ppguid); + return ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid); } -static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp) +static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp) { -#define E(msg, lbl) do { DDS_LOG(DDS_LC_DISCOVERY, msg); goto lbl; } while (0) +#define E(msg, lbl) do { GVLOGDISC (msg); goto lbl; } while (0) + struct q_globals * const gv = rst->gv; struct proxy_participant *pp; struct proxy_writer * pwr = NULL; struct proxy_reader * prd = NULL; nn_guid_t ppguid; - nn_xqos_t *xqos; + dds_qos_t *xqos; int reliable; struct addrset *as; int is_writer; @@ -1118,14 +1140,14 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat if (!(datap->present & PP_ENDPOINT_GUID)) E (" no guid?\n", err); - DDS_LOG(DDS_LC_DISCOVERY, " "PGUIDFMT, PGUID (datap->endpoint_guid)); + GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid)); ppguid.prefix = datap->endpoint_guid.prefix; ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if (is_deleted_participant_guid (&ppguid, DPG_REMOTE)) + if (is_deleted_participant_guid (gv->deleted_participants, &ppguid, DPG_REMOTE)) E (" local dead pp?\n", err); - if (ephash_lookup_participant_guid (&ppguid) != NULL) + if (ephash_lookup_participant_guid (gv->guid_hash, &ppguid) != NULL) E (" local pp?\n", err); if (is_builtin_entityid (datap->endpoint_guid.entityid, vendorid)) @@ -1135,23 +1157,23 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat if (!(datap->qos.present & QP_TYPE_NAME)) E (" no typename?\n", err); - if ((pp = ephash_lookup_proxy_participant_guid (&ppguid)) == NULL) + if ((pp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &ppguid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, " unknown-proxypp"); - if ((pp = implicitly_create_proxypp (&ppguid, datap, src_guid_prefix, vendorid, timestamp)) == NULL) + GVLOGDISC (" unknown-proxypp"); + if ((pp = implicitly_create_proxypp (gv, &ppguid, datap, src_guid_prefix, vendorid, timestamp, 0)) == NULL) E ("?\n", err); /* Repeat regular SEDP trace for convenience */ - DDS_LOG(DDS_LC_DISCOVERY, "SEDP ST0 "PGUIDFMT" (cont)", PGUID (datap->endpoint_guid)); + GVLOGDISC ("SEDP ST0 "PGUIDFMT" (cont)", PGUID (datap->endpoint_guid)); } xqos = &datap->qos; is_writer = is_writer_entityid (datap->endpoint_guid.entityid); if (!is_writer) - nn_xqos_mergein_missing (xqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (xqos, &gv->default_xqos_rd, ~(uint64_t)0); else if (vendor_is_eclipse_or_prismtech(vendorid)) - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (xqos, &gv->default_xqos_wr, ~(uint64_t)0); else - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr_nad); + nn_xqos_mergein_missing (xqos, &gv->default_xqos_wr_nad, ~(uint64_t)0); /* After copy + merge, should have at least the ones present in the input. Also verify reliability and durability are present, @@ -1159,16 +1181,16 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat assert ((xqos->present & datap->qos.present) == datap->qos.present); assert (xqos->present & QP_RELIABILITY); assert (xqos->present & QP_DURABILITY); - reliable = (xqos->reliability.kind == NN_RELIABLE_RELIABILITY_QOS); + reliable = (xqos->reliability.kind == DDS_RELIABILITY_RELIABLE); - DDS_LOG(DDS_LC_DISCOVERY, " %s %s %s: %s%s.%s/%s", - reliable ? "reliable" : "best-effort", - durability_to_string (xqos->durability.kind), - is_writer ? "writer" : "reader", - ((!(xqos->present & QP_PARTITION) || xqos->partition.n == 0 || *xqos->partition.strs[0] == '\0') - ? "(default)" : xqos->partition.strs[0]), - ((xqos->present & QP_PARTITION) && xqos->partition.n > 1) ? "+" : "", - xqos->topic_name, xqos->type_name); + GVLOGDISC (" %s %s %s: %s%s.%s/%s", + reliable ? "reliable" : "best-effort", + durability_to_string (xqos->durability.kind), + is_writer ? "writer" : "reader", + ((!(xqos->present & QP_PARTITION) || xqos->partition.n == 0 || *xqos->partition.strs[0] == '\0') + ? "(default)" : xqos->partition.strs[0]), + ((xqos->present & QP_PARTITION) && xqos->partition.n > 1) ? "+" : "", + xqos->topic_name, xqos->type_name); if (! is_writer && (datap->present & PP_EXPECTS_INLINE_QOS) && datap->expects_inline_qos) { @@ -1177,60 +1199,52 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat if (is_writer) { - pwr = ephash_lookup_proxy_writer_guid (&datap->endpoint_guid); + pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, &datap->endpoint_guid); } else { - prd = ephash_lookup_proxy_reader_guid (&datap->endpoint_guid); + prd = ephash_lookup_proxy_reader_guid (gv->guid_hash, &datap->endpoint_guid); } if (pwr || prd) { - /* Cloud load balances by updating participant endpoints */ - - if (! vendor_is_cloud (vendorid)) - { - DDS_LOG(DDS_LC_DISCOVERY, " known\n"); - goto err; - } - /* Re-bind the proxy participant to the discovery service - and do this if it is currently bound to another DS instance, because that other DS instance may have already failed and with a new one taking over, without our noticing it. */ - DDS_LOG(DDS_LC_DISCOVERY, " known-DS"); + GVLOGDISC (" known%s", vendor_is_cloud (vendorid) ? "-DS" : ""); if (vendor_is_cloud (vendorid) && pp->implicitly_created && memcmp(&pp->privileged_pp_guid.prefix, src_guid_prefix, sizeof(pp->privileged_pp_guid.prefix)) != 0) { nn_etime_t never = { T_NEVER }; - DDS_LOG(DDS_LC_DISCOVERY, " "PGUIDFMT" attach-to-DS "PGUIDFMT, PGUID(pp->e.guid), PGUIDPREFIX(*src_guid_prefix), pp->privileged_pp_guid.entityid.u); + GVLOGDISC (" "PGUIDFMT" attach-to-DS "PGUIDFMT, PGUID(pp->e.guid), PGUIDPREFIX(*src_guid_prefix), pp->privileged_pp_guid.entityid.u); ddsrt_mutex_lock (&pp->e.lock); pp->privileged_pp_guid.prefix = *src_guid_prefix; lease_set_expiry(ddsrt_atomic_ldvoidp(&pp->lease), never); ddsrt_mutex_unlock (&pp->e.lock); } - DDS_LOG(DDS_LC_DISCOVERY, "\n"); + GVLOGDISC ("\n"); } else { - DDS_LOG(DDS_LC_DISCOVERY, " NEW"); + GVLOGDISC (" NEW"); } { nn_locator_t loc; as = new_addrset (); - if (!config.tcp_use_peeraddr_for_unicast && (datap->present & PP_UNICAST_LOCATOR) && get_locator (&loc, &datap->unicast_locators, 0)) - add_to_addrset (as, &loc); - else if (config.tcp_use_peeraddr_for_unicast) + if (!gv->config.tcp_use_peeraddr_for_unicast && (datap->present & PP_UNICAST_LOCATOR) && get_locator (gv, &loc, &datap->unicast_locators, 0)) + add_to_addrset (gv, as, &loc); + else if (gv->config.tcp_use_peeraddr_for_unicast) { - DDS_LOG(DDS_LC_DISCOVERY, " (srcloc)"); - add_to_addrset (as, &rst->srcloc); + GVLOGDISC (" (srcloc)"); + add_to_addrset (gv, as, &rst->srcloc); } else { - copy_addrset_into_addrset_uc (as, pp->as_default); + copy_addrset_into_addrset_uc (gv, as, pp->as_default); } - if ((datap->present & PP_MULTICAST_LOCATOR) && get_locator (&loc, &datap->multicast_locators, 0)) - allowmulticast_aware_add_to_addrset (as, &loc); + if ((datap->present & PP_MULTICAST_LOCATOR) && get_locator (gv, &loc, &datap->multicast_locators, 0)) + allowmulticast_aware_add_to_addrset (gv, gv->config.allowMulticast, as, &loc); else - copy_addrset_into_addrset_mc (as, pp->as_default); + copy_addrset_into_addrset_mc (gv, as, pp->as_default); } if (addrset_empty (as)) { @@ -1238,22 +1252,22 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat E (" no address", err); } - nn_log_addrset(DDS_LC_DISCOVERY, " (as", as); + nn_log_addrset(gv, DDS_LC_DISCOVERY, " (as", as); #ifdef DDSI_INCLUDE_SSM ssm = 0; if (is_writer) - ssm = addrset_contains_ssm (as); + ssm = addrset_contains_ssm (gv, as); else if (datap->present & PP_READER_FAVOURS_SSM) ssm = (datap->reader_favours_ssm.state != 0); - DDS_LOG(DDS_LC_DISCOVERY, " ssm=%u", ssm); + GVLOGDISC (" ssm=%u", ssm); #endif - DDS_LOG(DDS_LC_DISCOVERY, ") QOS={"); - nn_log_xqos(DDS_LC_DISCOVERY, xqos); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + GVLOGDISC (") QOS={"); + nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, xqos); + GVLOGDISC ("}\n"); if ((datap->endpoint_guid.entityid.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_VENDOR && !vendor_is_eclipse_or_prismtech (vendorid)) { - DDS_LOG(DDS_LC_DISCOVERY, "ignoring vendor-specific endpoint "PGUIDFMT"\n", PGUID (datap->endpoint_guid)); + GVLOGDISC ("ignoring vendor-specific endpoint "PGUIDFMT"\n", PGUID (datap->endpoint_guid)); } else { @@ -1261,7 +1275,7 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat { if (pwr) { - update_proxy_writer (pwr, as); + update_proxy_writer (pwr, seq, as, xqos, timestamp); } else { @@ -1269,11 +1283,11 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat assert (!is_builtin_entityid (datap->endpoint_guid.entityid, vendorid)); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS { - struct config_channel_listelem *channel = find_channel (xqos->transport_priority); - new_proxy_writer (&ppguid, &datap->endpoint_guid, as, datap, channel->dqueue, channel->evq ? channel->evq : gv.xevents, timestamp); + struct config_channel_listelem *channel = find_channel (&gv->config, xqos->transport_priority); + new_proxy_writer (&ppguid, &datap->endpoint_guid, as, datap, channel->dqueue, channel->evq ? channel->evq : gv->xevents, timestamp); } #else - new_proxy_writer (&ppguid, &datap->endpoint_guid, as, datap, gv.user_dqueue, gv.xevents, timestamp); + new_proxy_writer (gv, &ppguid, &datap->endpoint_guid, as, datap, gv->user_dqueue, gv->xevents, timestamp, seq); #endif } } @@ -1281,14 +1295,14 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat { if (prd) { - update_proxy_reader (prd, as); + update_proxy_reader (prd, seq, as, xqos, timestamp); } else { #ifdef DDSI_INCLUDE_SSM - new_proxy_reader (&ppguid, &datap->endpoint_guid, as, datap, timestamp, ssm); + new_proxy_reader (gv, &ppguid, &datap->endpoint_guid, as, datap, timestamp, seq, ssm); #else - new_proxy_reader (&ppguid, &datap->endpoint_guid, as, datap, timestamp); + new_proxy_reader (gv, &ppguid, &datap->endpoint_guid, as, datap, timestamp, seq); #endif } } @@ -1302,62 +1316,67 @@ err: #undef E } -static void handle_SEDP_dead (nn_plist_t *datap, nn_wctime_t timestamp) +static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *datap, nn_wctime_t timestamp) { + struct q_globals * const gv = rst->gv; int res; if (!(datap->present & PP_ENDPOINT_GUID)) { - DDS_LOG(DDS_LC_DISCOVERY, " no guid?\n"); + GVLOGDISC (" no guid?\n"); return; } - DDS_LOG(DDS_LC_DISCOVERY, " "PGUIDFMT, PGUID (datap->endpoint_guid)); + GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid)); if (is_writer_entityid (datap->endpoint_guid.entityid)) { - res = delete_proxy_writer (&datap->endpoint_guid, timestamp, 0); + res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0); } else { - res = delete_proxy_reader (&datap->endpoint_guid, timestamp, 0); + res = delete_proxy_reader (gv, &datap->endpoint_guid, timestamp, 0); } - DDS_LOG(DDS_LC_DISCOVERY, " %s\n", (res < 0) ? " unknown" : " delete"); + GVLOGDISC (" %s\n", (res < 0) ? " unknown" : " delete"); } -static void handle_SEDP (const struct receiver_state *rst, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) +static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, uint32_t len) { + struct q_globals * const gv = rst->gv; const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - DDS_LOG(DDS_LC_DISCOVERY, "SEDP ST%x", statusinfo); + GVLOGDISC ("SEDP ST%x", statusinfo); if (data == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, " no payload?\n"); + GVLOGDISC (" no payload?\n"); return; } else { nn_plist_t decoded_data; nn_plist_src_t src; - int plist_ret; + dds_return_t plist_ret; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = data->identifier; src.buf = (unsigned char *) data + 4; src.bufsz = len - 4; + src.strict = NN_STRICT_P (gv->config); + src.factory = gv->m_factory; + src.logconfig = &gv->logconfig; if ((plist_ret = nn_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING("SEDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); + if (plist_ret != DDS_RETCODE_UNSUPPORTED) + GVWARNING ("SEDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); return; } switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { case 0: - handle_SEDP_alive (rst, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp); + handle_SEDP_alive (rst, seq, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp); break; case NN_STATUSINFO_DISPOSE: case NN_STATUSINFO_UNREGISTER: case (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER): - handle_SEDP_dead (&decoded_data, timestamp); + handle_SEDP_dead (rst, &decoded_data, timestamp); break; } @@ -1387,14 +1406,14 @@ int sedp_write_topic (struct participant *pp, const struct nn_plist *datap) sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER); - mpayload = nn_xmsg_new (gv.xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); - delta = nn_xqos_delta (&datap->qos, &gv.default_xqos_tp, ~(uint64_t)0); - if (config.explicitly_publish_qos_set_to_default) + mpayload = nn_xmsg_new (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); + delta = nn_xqos_delta (&datap->qos, &sedp_wr->e.gv->default_xqos_tp, ~(uint64_t)0); + if (sedp_wr->e.gv->config.explicitly_publish_qos_set_to_default) delta |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; nn_plist_addtomsg (mpayload, datap, ~(uint64_t)0, delta); nn_xmsg_addpar_sentinel (mpayload); - DDS_TRACE("sedp: write topic %s via "PGUIDFMT"\n", datap->qos.topic_name, PGUID (sedp_wr->e.guid)); + ETRACE (pp, "sedp: write topic %s via "PGUIDFMT"\n", datap->qos.topic_name, PGUID (sedp_wr->e.guid)); ret = write_mpayload (sedp_wr, 1, PID_TOPIC_NAME, mpayload); nn_xmsg_free (mpayload); return ret; @@ -1425,7 +1444,7 @@ int sedp_write_cm_participant (struct participant *pp, int alive) the QoS and other settings. So the header fields aren't really important, except that they need to be set to reasonable things or it'll crash */ - mpayload = nn_xmsg_new (gv.xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); nn_plist_init_empty (&ps); ps.present = PP_PARTICIPANT_GUID; ps.participant_guid = pp->e.guid; @@ -1435,44 +1454,47 @@ int sedp_write_cm_participant (struct participant *pp, int alive) { nn_plist_addtomsg (mpayload, pp->plist, PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | - PP_PRISMTECH_WATCHDOG_SCHEDULING | PP_PRISMTECH_LISTENER_SCHEDULING | - PP_PRISMTECH_SERVICE_TYPE | PP_ENTITY_NAME, + PP_ENTITY_NAME, QP_PRISMTECH_ENTITY_FACTORY); } nn_xmsg_addpar_sentinel (mpayload); - DDS_TRACE("sedp: write CMParticipant ST%x for "PGUIDFMT" via "PGUIDFMT"\n", + ETRACE (pp, "sedp: write CMParticipant ST%x for "PGUIDFMT" via "PGUIDFMT"\n", alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER, PGUID (pp->e.guid), PGUID (sedp_wr->e.guid)); ret = write_mpayload (sedp_wr, alive, PID_PARTICIPANT_GUID, mpayload); nn_xmsg_free (mpayload); return ret; } -static void handle_SEDP_CM (const struct receiver_state *rst, nn_entityid_t wr_entity_id, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) +static void handle_SEDP_CM (const struct receiver_state *rst, nn_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len) { + struct q_globals * const gv = rst->gv; const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - DDS_LOG(DDS_LC_DISCOVERY, "SEDP_CM ST%x", statusinfo); + GVLOGDISC ("SEDP_CM ST%x", statusinfo); assert (wr_entity_id.u == NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER); (void) wr_entity_id; if (data == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, " no payload?\n"); + GVLOGDISC (" no payload?\n"); return; } else { nn_plist_t decoded_data; nn_plist_src_t src; - int plist_ret; + dds_return_t plist_ret; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = data->identifier; src.buf = (unsigned char *) data + 4; src.bufsz = len - 4; + src.strict = NN_STRICT_P (gv->config); + src.factory = gv->m_factory; + src.logconfig = &gv->logconfig; if ((plist_ret = nn_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING("SEDP_CM (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); + if (plist_ret != DDS_RETCODE_UNSUPPORTED) + GVWARNING ("SEDP_CM (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); return; } @@ -1481,178 +1503,19 @@ static void handle_SEDP_CM (const struct receiver_state *rst, nn_entityid_t wr_e { struct proxy_participant *proxypp; if (!(decoded_data.present & PP_PARTICIPANT_GUID)) - DDS_WARNING("SEDP_CM (vendor %u.%u): missing participant GUID\n", src.vendorid.id[0], src.vendorid.id[1]); + GVWARNING ("SEDP_CM (vendor %u.%u): missing participant GUID\n", src.vendorid.id[0], src.vendorid.id[1]); else { - if ((proxypp = ephash_lookup_proxy_participant_guid (&decoded_data.participant_guid)) == NULL) - proxypp = implicitly_create_proxypp (&decoded_data.participant_guid, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp); + if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &decoded_data.participant_guid)) == NULL) + proxypp = implicitly_create_proxypp (gv, &decoded_data.participant_guid, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp, 0); if (proxypp != NULL) - update_proxy_participant_plist (proxypp, &decoded_data, UPD_PROXYPP_CM, timestamp); + update_proxy_participant_plist (proxypp, 0, &decoded_data, UPD_PROXYPP_CM, timestamp); } } nn_plist_fini (&decoded_data); } - DDS_LOG(DDS_LC_DISCOVERY, "\n"); -} - -static struct participant *group_guid_to_participant (const nn_guid_t *group_guid) -{ - nn_guid_t ppguid; - ppguid.prefix = group_guid->prefix; - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - return ephash_lookup_participant_guid (&ppguid); -} - -int sedp_write_cm_publisher (const struct nn_plist *datap, int alive) -{ - struct participant *pp; - struct writer *sedp_wr; - struct nn_xmsg *mpayload; - uint64_t delta; - int ret; - - if ((pp = group_guid_to_participant (&datap->group_guid)) == NULL) - { - DDS_TRACE("sedp: write CMPublisher alive:%d for "PGUIDFMT" dropped: no participant\n", - alive, PGUID (datap->group_guid)); - return 0; - } - sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER); - - /* The message is only a temporary thing, used only for encoding - the QoS and other settings. So the header fields aren't really - important, except that they need to be set to reasonable things - or it'll crash */ - mpayload = nn_xmsg_new (gv.xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); - if (!alive) - delta = 0; - else - { - delta = nn_xqos_delta (&datap->qos, &gv.default_xqos_pub, ~(uint64_t)0); - if (!config.explicitly_publish_qos_set_to_default) - delta |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; - } - nn_plist_addtomsg (mpayload, datap, ~(uint64_t)0, delta); - nn_xmsg_addpar_sentinel (mpayload); - ret = write_mpayload (sedp_wr, alive, PID_GROUP_GUID ,mpayload); - nn_xmsg_free (mpayload); - return ret; -} - -int sedp_write_cm_subscriber (const struct nn_plist *datap, int alive) -{ - struct participant *pp; - struct writer *sedp_wr; - struct nn_xmsg *mpayload; - uint64_t delta; - int ret; - - if ((pp = group_guid_to_participant (&datap->group_guid)) == NULL) - { - DDS_LOG(DDS_LC_DISCOVERY, "sedp: write CMSubscriber alive:%d for "PGUIDFMT" dropped: no participant\n", - alive, PGUID (datap->group_guid)); - return 0; - } - sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER); - - /* The message is only a temporary thing, used only for encoding - the QoS and other settings. So the header fields aren't really - important, except that they need to be set to reasonable things - or it'll crash */ - mpayload = nn_xmsg_new (gv.xmsgpool, &sedp_wr->e.guid.prefix, 0, NN_XMSG_KIND_DATA); - if (!alive) - delta = 0; - else - { - delta = nn_xqos_delta (&datap->qos, &gv.default_xqos_sub, ~(uint64_t)0); - if (!config.explicitly_publish_qos_set_to_default) - delta |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; - } - nn_plist_addtomsg (mpayload, datap, ~(uint64_t)0, delta); - nn_xmsg_addpar_sentinel (mpayload); - ret = write_mpayload (sedp_wr, alive, PID_GROUP_GUID, mpayload); - nn_xmsg_free (mpayload); - return ret; -} - -static void handle_SEDP_GROUP_alive (nn_plist_t *datap /* note: potentially modifies datap */, nn_wctime_t timestamp) -{ -#define E(msg, lbl) do { DDS_LOG(DDS_LC_DISCOVERY, msg); goto lbl; } while (0) - nn_guid_t ppguid; - - if (!(datap->present & PP_GROUP_GUID)) - E (" no guid?\n", err); - DDS_LOG(DDS_LC_DISCOVERY, " %"PRIx32"%"PRIx32"%"PRIx32"%"PRIx32, PGUID (datap->group_guid)); - - ppguid.prefix = datap->group_guid.prefix; - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if (ephash_lookup_proxy_participant_guid (&ppguid) == NULL) - E (" unknown proxy pp?\n", err); - - DDS_LOG(DDS_LC_DISCOVERY, " alive\n"); - - { - char *name = (datap->present & PP_ENTITY_NAME) ? datap->entity_name : ""; - new_proxy_group (&datap->group_guid, name, &datap->qos, timestamp); - } -err: - return; -#undef E -} - -static void handle_SEDP_GROUP_dead (nn_plist_t *datap, nn_wctime_t timestamp) -{ - if (!(datap->present & PP_GROUP_GUID)) - { - DDS_LOG(DDS_LC_DISCOVERY, " no guid?\n"); - return; - } - DDS_LOG(DDS_LC_DISCOVERY, " "PGUIDFMT"\n", PGUID (datap->group_guid)); - delete_proxy_group (&datap->group_guid, timestamp, 0); -} - -static void handle_SEDP_GROUP (const struct receiver_state *rst, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) -{ - const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - DDS_LOG(DDS_LC_DISCOVERY, "SEDP_GROUP ST%x", statusinfo); - if (data == NULL) - { - DDS_LOG(DDS_LC_DISCOVERY, " no payload?\n"); - return; - } - else - { - nn_plist_t decoded_data; - nn_plist_src_t src; - int plist_ret; - src.protocol_version = rst->protocol_version; - src.vendorid = rst->vendor; - src.encoding = data->identifier; - src.buf = (unsigned char *) data + 4; - src.bufsz = len - 4; - if ((plist_ret = nn_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) - { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING("SEDP_GROUP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); - return; - } - - switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) - { - case 0: - handle_SEDP_GROUP_alive (&decoded_data, timestamp); - break; - - case NN_STATUSINFO_DISPOSE: - case NN_STATUSINFO_UNREGISTER: - case (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER): - handle_SEDP_GROUP_dead (&decoded_data, timestamp); - break; - } - - nn_plist_fini (&decoded_data); - } + GVLOGDISC ("\n"); } /****************************************************************************** @@ -1691,6 +1554,7 @@ static int defragment (unsigned char **datap, const struct nn_rdata *fragchain, int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const nn_guid_t *rdguid), UNUSED_ARG (void *qarg)) { + struct q_globals * const gv = sampleinfo->rst->gv; struct proxy_writer *pwr; struct { struct CDRHeader cdr; @@ -1748,17 +1612,20 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str { nn_plist_src_t src; size_t qos_offset = NN_RDATA_SUBMSG_OFF (fragchain) + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->octetsToInlineQos) + msg->octetsToInlineQos; - int plist_ret; + dds_return_t plist_ret; src.protocol_version = sampleinfo->rst->protocol_version; src.vendorid = sampleinfo->rst->vendor; src.encoding = (msg->smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; src.buf = NN_RMSG_PAYLOADOFF (fragchain->rmsg, qos_offset); src.bufsz = NN_RDATA_PAYLOAD_OFF (fragchain) - qos_offset; + src.strict = NN_STRICT_P (gv->config); + src.factory = gv->m_factory; + src.logconfig = &gv->logconfig; if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH, 0, &src)) < 0) { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", - src.vendorid.id[0], src.vendorid.id[1], PGUID (srcguid), sampleinfo->seq); + if (plist_ret != DDS_RETCODE_UNSUPPORTED) + GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", + src.vendorid.id[0], src.vendorid.id[1], PGUID (srcguid), sampleinfo->seq); goto done_upd_deliv; } /* Complex qos bit also gets set when statusinfo bits other than @@ -1781,10 +1648,9 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str { if (datasz == 0 || !(data_smhdr_flags & DATA_FLAG_DATAFLAG)) { - DDS_WARNING("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": " - "built-in data but no payload\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); + GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": built-in data but no payload\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); goto done_upd_deliv; } } @@ -1795,14 +1661,13 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str hasn't been checked fully yet. */ if (!(data_smhdr_flags & DATA_FLAG_KEYFLAG)) { - DDS_WARNING("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": " - "dispose/unregister of built-in data but payload not just key\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); + GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": dispose/unregister of built-in data but payload not just key\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); goto done_upd_deliv; } } - else if ((qos.present & PP_KEYHASH) && !NN_STRICT_P) + else if ((qos.present & PP_KEYHASH) && !NN_STRICT_P(gv->config)) { /* For SPDP/SEDP, fake a parameter list with just a keyhash. For PMD, just use the keyhash directly. Too hard to fix everything @@ -1837,9 +1702,9 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str pid = PID_ENDPOINT_GUID; break; default: - DDS_LOG(DDS_LC_DISCOVERY, "data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": mapping keyhash to ENDPOINT_GUID", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); + GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": mapping keyhash to ENDPOINT_GUID", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); pid = PID_ENDPOINT_GUID; break; } @@ -1854,22 +1719,24 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str } else { - DDS_WARNING("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": " - "dispose/unregister with no content\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); + GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": dispose/unregister with no content\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); goto done_upd_deliv; } - timestamp = valid_ddsi_timestamp(sampleinfo->timestamp) ? nn_wctime_from_ddsi_time(sampleinfo->timestamp): now(); + if (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v) + timestamp = sampleinfo->timestamp; + else + timestamp = now (); switch (srcguid.entityid.u) { case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - handle_SPDP (sampleinfo->rst, timestamp, statusinfo, datap, datasz); + handle_SPDP (sampleinfo->rst, sampleinfo->seq, timestamp, statusinfo, datap, datasz); break; case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: - handle_SEDP (sampleinfo->rst, timestamp, statusinfo, datap, datasz); + handle_SEDP (sampleinfo->rst, sampleinfo->seq, timestamp, statusinfo, datap, datasz); break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: handle_PMD (sampleinfo->rst, timestamp, statusinfo, datap, datasz); @@ -1877,14 +1744,10 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: handle_SEDP_CM (sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz); break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - handle_SEDP_GROUP (sampleinfo->rst, timestamp, statusinfo, datap, datasz); - break; default: - DDS_LOG (DDS_LC_DISCOVERY, "data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": not handled\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); + GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": not handled\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); break; } diff --git a/src/core/ddsi/src/q_debmon.c b/src/core/ddsi/src/q_debmon.c index 35ed218..9012f7b 100644 --- a/src/core/ddsi/src/q_debmon.c +++ b/src/core/ddsi/src/q_debmon.c @@ -33,7 +33,6 @@ #include "dds/ddsi/q_ddsi_discovery.h" #include "dds/ddsi/q_protocol.h" /* NN_ENTITYID_... */ #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_debmon.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_tran.h" @@ -53,6 +52,7 @@ struct debug_monitor { ddsi_tran_listener_t servsock; ddsrt_mutex_t lock; ddsrt_cond_t cond; + struct q_globals *gv; struct plugin *plugins; int stop; }; @@ -86,7 +86,7 @@ static void print_address (const nn_locator_t *n, void *varg) { struct print_address_arg *arg = varg; char buf[DDSI_LOCSTRLEN]; - arg->count += cpf (arg->conn, " %s", ddsi_locator_to_string (buf, sizeof(buf), n)); + arg->count += cpf (arg->conn, " %s", ddsi_locator_to_string (arg->conn->m_base.gv, buf, sizeof(buf), n)); } static int print_addrset (ddsi_tran_conn_t conn, const char *prefix, struct addrset *as, const char *suffix) @@ -108,15 +108,14 @@ static int print_addrset_if_notempty (ddsi_tran_conn_t conn, const char *prefix, } static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, - const struct nn_xqos *xqos, const struct ddsi_sertopic *topic) + const struct dds_qos *xqos, const struct ddsi_sertopic *topic) { int x = 0; x += cpf (conn, " %s %x:%x:%x:%x ", label, PGUID (e->guid)); if (xqos->present & QP_PARTITION) { - unsigned i; if (xqos->partition.n > 1) cpf (conn, "{"); - for (i = 0; i < xqos->partition.n; i++) + for (uint32_t i = 0; i < xqos->partition.n; i++) x += cpf (conn, "%s%s", i == 0 ? "" : ",", xqos->partition.strs[i]); if (xqos->partition.n > 1) cpf (conn, "}"); x += cpf (conn, ".%s/%s", @@ -127,7 +126,7 @@ static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, return x; } -static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct nn_xqos *xqos, const struct ddsi_sertopic *topic) +static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct dds_qos *xqos, const struct ddsi_sertopic *topic) { DDSRT_UNUSED_ARG (c); return print_any_endpoint_common (conn, label, e, xqos, topic); @@ -142,13 +141,13 @@ static int print_proxy_endpoint_common (ddsi_tran_conn_t conn, const char *label } -static int print_participants (struct thread_state1 * const ts1, ddsi_tran_conn_t conn) +static int print_participants (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn) { struct ephash_enum_participant e; struct participant *p; int x = 0; - thread_state_awake (ts1); - ephash_enum_participant_init (&e); + thread_state_awake_fixed_domain (ts1); + ephash_enum_participant_init (&e, gv->guid_hash); while ((p = ephash_enum_participant_next (&e)) != NULL) { ddsrt_mutex_lock (&p->e.lock); @@ -158,7 +157,7 @@ static int print_participants (struct thread_state1 * const ts1, ddsi_tran_conn_ { struct ephash_enum_reader er; struct reader *r; - ephash_enum_reader_init (&er); + ephash_enum_reader_init (&er, gv->guid_hash); while ((r = ephash_enum_reader_next (&er)) != NULL) { ddsrt_avl_iter_t writ; @@ -180,7 +179,7 @@ static int print_participants (struct thread_state1 * const ts1, ddsi_tran_conn_ { struct ephash_enum_writer ew; struct writer *w; - ephash_enum_writer_init (&ew); + ephash_enum_writer_init (&ew, gv->guid_hash); while ((w = ephash_enum_writer_next (&ew)) != NULL) { ddsrt_avl_iter_t rdit; @@ -227,13 +226,13 @@ static int print_participants (struct thread_state1 * const ts1, ddsi_tran_conn_ return x; } -static int print_proxy_participants (struct thread_state1 * const ts1, ddsi_tran_conn_t conn) +static int print_proxy_participants (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn) { struct ephash_enum_proxy_participant e; struct proxy_participant *p; int x = 0; - thread_state_awake (ts1); - ephash_enum_proxy_participant_init (&e); + thread_state_awake_fixed_domain (ts1); + ephash_enum_proxy_participant_init (&e, gv->guid_hash); while ((p = ephash_enum_proxy_participant_next (&e)) != NULL) { ddsrt_mutex_lock (&p->e.lock); @@ -245,7 +244,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, ddsi_tran { struct ephash_enum_proxy_reader er; struct proxy_reader *r; - ephash_enum_proxy_reader_init (&er); + ephash_enum_proxy_reader_init (&er, gv->guid_hash); while ((r = ephash_enum_proxy_reader_next (&er)) != NULL) { ddsrt_avl_iter_t writ; @@ -264,7 +263,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, ddsi_tran { struct ephash_enum_proxy_writer ew; struct proxy_writer *w; - ephash_enum_proxy_writer_init (&ew); + ephash_enum_proxy_writer_init (&ew, gv->guid_hash); while ((w = ephash_enum_proxy_writer_next (&ew)) != NULL) { ddsrt_avl_iter_t rdit; @@ -286,7 +285,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, ddsi_tran x += cpf (conn, " tl-catchup end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq); break; case PRMSS_OUT_OF_SYNC: - x += cpf (conn, " out-of-sync end_of_tl_seq %lld end_of_out_of_sync_seq %lld\n", m->u.not_in_sync.end_of_tl_seq, m->u.not_in_sync.end_of_out_of_sync_seq); + x += cpf (conn, " out-of-sync end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq); break; } } @@ -305,9 +304,9 @@ static void debmon_handle_connection (struct debug_monitor *dm, ddsi_tran_conn_t struct thread_state1 * const ts1 = lookup_thread_state (); struct plugin *p; int r = 0; - r += print_participants (ts1, conn); + r += print_participants (ts1, dm->gv, conn); if (r == 0) - r += print_proxy_participants (ts1, conn); + r += print_proxy_participants (ts1, dm->gv, conn); /* Note: can only add plugins (at the tail) */ ddsrt_mutex_lock (&dm->lock); @@ -346,25 +345,26 @@ static uint32_t debmon_main (void *vdm) return 0; } -struct debug_monitor *new_debug_monitor (int port) +struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port) { struct debug_monitor *dm; - if (config.monitor_port < 0) + if (gv->config.monitor_port < 0) return NULL; - if (ddsi_tcp_init () < 0) + if (ddsi_tcp_init (gv) < 0) return NULL; dm = ddsrt_malloc (sizeof (*dm)); + dm->gv = gv; dm->plugins = NULL; - if ((dm->tran_factory = ddsi_factory_find ("tcp")) == NULL) - dm->tran_factory = ddsi_factory_find ("tcp6"); + if ((dm->tran_factory = ddsi_factory_find (gv, "tcp")) == NULL) + dm->tran_factory = ddsi_factory_find (gv, "tcp6"); dm->servsock = ddsi_factory_create_listener (dm->tran_factory, port, NULL); if (dm->servsock == NULL) { - DDS_WARNING("debmon: can't create socket\n"); + GVWARNING ("debmon: can't create socket\n"); goto err_servsock; } @@ -372,7 +372,7 @@ struct debug_monitor *new_debug_monitor (int port) nn_locator_t loc; char buf[DDSI_LOCSTRLEN]; (void) ddsi_listener_locator(dm->servsock, &loc); - DDS_LOG(DDS_LC_CONFIG, "debmon at %s\n", ddsi_locator_to_string (buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "debmon at %s\n", ddsi_locator_to_string (gv, buf, sizeof(buf), &loc)); } ddsrt_mutex_init (&dm->lock); @@ -380,7 +380,7 @@ struct debug_monitor *new_debug_monitor (int port) if (ddsi_listener_listen (dm->servsock) < 0) goto err_listen; dm->stop = 0; - create_thread(&dm->servts, "debmon", debmon_main, dm); + create_thread (&dm->servts, gv, "debmon", debmon_main, dm); return dm; err_listen: diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 53c0bc6..06afbbf 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -38,10 +38,11 @@ #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_protocol.h" /* NN_ENTITYID_... */ #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/ddsi_serdata_default.h" #include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/q_receive.h" +#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */ +#include "dds/ddsi/q_rhc.h" #include "dds/ddsi/sysdeps.h" #include "dds__whc.h" @@ -55,8 +56,11 @@ struct deleted_participant { nn_mtime_t t_prune; }; -static ddsrt_mutex_t deleted_participants_lock; -static ddsrt_avl_tree_t deleted_participants; +struct deleted_participants_admin { + ddsrt_mutex_t deleted_participants_lock; + ddsrt_avl_tree_t deleted_participants; + int64_t delay; +}; static int compare_guid (const void *va, const void *vb); static void augment_wr_prd_match (void *vnode, const void *vleft, const void *vright); @@ -88,11 +92,10 @@ static const unsigned prismtech_builtin_writers_besmask = NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; -static dds_retcode_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg); -static dds_retcode_t new_reader_guid (struct reader **rd_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct rhc *rhc, status_cb_t status_cb, void *status_cbarg); +static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg); +static dds_return_t new_reader_guid (struct reader **rd_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc *rhc, status_cb_t status_cb, void *status_cbarg); static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity); static void unref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity); -static void delete_proxy_group_locked (struct proxy_group *pgroup, nn_wctime_t timestamp, int isimplicit); static int gcreq_participant (struct participant *pp); static int gcreq_writer (struct writer *wr); @@ -101,6 +104,11 @@ static int gcreq_proxy_participant (struct proxy_participant *proxypp); static int gcreq_proxy_writer (struct proxy_writer *pwr); static int gcreq_proxy_reader (struct proxy_reader *prd); +extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid); +extern inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic); +extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid); +extern inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive); + static int compare_guid (const void *va, const void *vb) { return memcmp (va, vb, sizeof (nn_guid_t)); @@ -137,6 +145,21 @@ int is_reader_entityid (nn_entityid_t id) } } +int is_keyed_endpoint_entityid (nn_entityid_t id) +{ + switch (id.u & NN_ENTITYID_KIND_MASK) + { + case NN_ENTITYID_KIND_READER_WITH_KEY: + case NN_ENTITYID_KIND_WRITER_WITH_KEY: + return 1; + case NN_ENTITYID_KIND_READER_NO_KEY: + case NN_ENTITYID_KIND_WRITER_NO_KEY: + return 0; + default: + return 0; + } +} + int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid) { if ((id.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN) @@ -163,17 +186,19 @@ bool is_local_orphan_endpoint (const struct entity_common *e) is_builtin_endpoint (e->guid.entityid, NN_VENDORID_ECLIPSE)); } -static void entity_common_init (struct entity_common *e, const struct nn_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal) +static void entity_common_init (struct entity_common *e, struct q_globals *gv, const struct nn_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal) { e->guid = *guid; e->kind = kind; e->tupdate = tcreate; e->name = ddsrt_strdup (name ? name : ""); e->onlylocal = onlylocal; + e->gv = gv; ddsrt_mutex_init (&e->lock); - if (ddsi_plugin.builtintopic_is_visible (guid->entityid, onlylocal, vendorid)) + ddsrt_mutex_init (&e->qos_lock); + if (builtintopic_is_visible (gv->builtin_topic_interface, guid, vendorid)) { - e->tk = ddsi_plugin.builtintopic_get_tkmap_entry (guid); + e->tk = builtintopic_get_tkmap_entry (gv->builtin_topic_interface, guid); e->iid = e->tk->m_iid; } else @@ -186,12 +211,13 @@ static void entity_common_init (struct entity_common *e, const struct nn_guid *g static void entity_common_fini (struct entity_common *e) { if (e->tk) - ddsi_tkmap_instance_unref (e->tk); + ddsi_tkmap_instance_unref (e->gv->m_tkmap, e->tk); ddsrt_free (e->name); + ddsrt_mutex_destroy (&e->qos_lock); ddsrt_mutex_destroy (&e->lock); } -void local_reader_ary_init (struct local_reader_ary *x) +static void local_reader_ary_init (struct local_reader_ary *x) { ddsrt_mutex_init (&x->rdary_lock); x->valid = 1; @@ -201,13 +227,13 @@ void local_reader_ary_init (struct local_reader_ary *x) x->rdary[0] = NULL; } -void local_reader_ary_fini (struct local_reader_ary *x) +static void local_reader_ary_fini (struct local_reader_ary *x) { ddsrt_free (x->rdary); ddsrt_mutex_destroy (&x->rdary_lock); } -void local_reader_ary_insert (struct local_reader_ary *x, struct reader *rd) +static void local_reader_ary_insert (struct local_reader_ary *x, struct reader *rd) { ddsrt_mutex_lock (&x->rdary_lock); x->n_readers++; @@ -217,9 +243,9 @@ void local_reader_ary_insert (struct local_reader_ary *x, struct reader *rd) ddsrt_mutex_unlock (&x->rdary_lock); } -void local_reader_ary_remove (struct local_reader_ary *x, struct reader *rd) +static void local_reader_ary_remove (struct local_reader_ary *x, struct reader *rd) { - unsigned i; + uint32_t i; ddsrt_mutex_lock (&x->rdary_lock); for (i = 0; i < x->n_readers; i++) { @@ -235,7 +261,15 @@ void local_reader_ary_remove (struct local_reader_ary *x, struct reader *rd) ddsrt_mutex_unlock (&x->rdary_lock); } -void local_reader_ary_setinvalid (struct local_reader_ary *x) +void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok) +{ + ddsrt_mutex_lock (&x->rdary_lock); + if (x->valid) + x->fastpath_ok = fastpath_ok; + ddsrt_mutex_unlock (&x->rdary_lock); +} + +static void local_reader_ary_setinvalid (struct local_reader_ary *x) { ddsrt_mutex_lock (&x->rdary_lock); x->valid = 0; @@ -264,111 +298,126 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e) /* DELETED PARTICIPANTS --------------------------------------------- */ -int deleted_participants_admin_init (void) +struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay) { - ddsrt_mutex_init (&deleted_participants_lock); - ddsrt_avl_init (&deleted_participants_treedef, &deleted_participants); - return 0; + struct deleted_participants_admin *admin = ddsrt_malloc (sizeof (*admin)); + ddsrt_mutex_init (&admin->deleted_participants_lock); + ddsrt_avl_init (&deleted_participants_treedef, &admin->deleted_participants); + admin->delay = delay; + return admin; } -void deleted_participants_admin_fini (void) +void deleted_participants_admin_free (struct deleted_participants_admin *admin) { - ddsrt_avl_free (&deleted_participants_treedef, &deleted_participants, ddsrt_free); - ddsrt_mutex_destroy (&deleted_participants_lock); + ddsrt_avl_free (&deleted_participants_treedef, &admin->deleted_participants, ddsrt_free); + ddsrt_mutex_destroy (&admin->deleted_participants_lock); + ddsrt_free (admin); } -static void prune_deleted_participant_guids_unlocked (nn_mtime_t tnow) +static void prune_deleted_participant_guids_unlocked (struct deleted_participants_admin *admin, nn_mtime_t tnow) { /* Could do a better job of finding prunable ones efficiently under all circumstances, but I expect the tree to be very small at all times, so a full scan is fine, too ... */ struct deleted_participant *dpp; - dpp = ddsrt_avl_find_min (&deleted_participants_treedef, &deleted_participants); + dpp = ddsrt_avl_find_min (&deleted_participants_treedef, &admin->deleted_participants); while (dpp) { - struct deleted_participant *dpp1 = ddsrt_avl_find_succ (&deleted_participants_treedef, &deleted_participants, dpp); + struct deleted_participant *dpp1 = ddsrt_avl_find_succ (&deleted_participants_treedef, &admin->deleted_participants, dpp); if (dpp->t_prune.v < tnow.v) { - ddsrt_avl_delete (&deleted_participants_treedef, &deleted_participants, dpp); + ddsrt_avl_delete (&deleted_participants_treedef, &admin->deleted_participants, dpp); ddsrt_free (dpp); } dpp = dpp1; } } -static void prune_deleted_participant_guids (nn_mtime_t tnow) +static void prune_deleted_participant_guids (struct deleted_participants_admin *admin, nn_mtime_t tnow) { - ddsrt_mutex_lock (&deleted_participants_lock); - prune_deleted_participant_guids_unlocked (tnow); - ddsrt_mutex_unlock (&deleted_participants_lock); + ddsrt_mutex_lock (&admin->deleted_participants_lock); + prune_deleted_participant_guids_unlocked (admin, tnow); + ddsrt_mutex_unlock (&admin->deleted_participants_lock); } -static void remember_deleted_participant_guid (const struct nn_guid *guid) +static void remember_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid) { struct deleted_participant *n; ddsrt_avl_ipath_t path; - ddsrt_mutex_lock (&deleted_participants_lock); - if (ddsrt_avl_lookup_ipath (&deleted_participants_treedef, &deleted_participants, guid, &path) == NULL) + ddsrt_mutex_lock (&admin->deleted_participants_lock); + if (ddsrt_avl_lookup_ipath (&deleted_participants_treedef, &admin->deleted_participants, guid, &path) == NULL) { if ((n = ddsrt_malloc (sizeof (*n))) != NULL) { n->guid = *guid; n->t_prune.v = T_NEVER; n->for_what = DPG_LOCAL | DPG_REMOTE; - ddsrt_avl_insert_ipath (&deleted_participants_treedef, &deleted_participants, n, &path); + ddsrt_avl_insert_ipath (&deleted_participants_treedef, &admin->deleted_participants, n, &path); } } - ddsrt_mutex_unlock (&deleted_participants_lock); + ddsrt_mutex_unlock (&admin->deleted_participants_lock); } -int is_deleted_participant_guid (const struct nn_guid *guid, unsigned for_what) +int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what) { struct deleted_participant *n; int known; - ddsrt_mutex_lock (&deleted_participants_lock); - prune_deleted_participant_guids_unlocked (now_mt()); - if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &deleted_participants, guid)) == NULL) + ddsrt_mutex_lock (&admin->deleted_participants_lock); + prune_deleted_participant_guids_unlocked (admin, now_mt ()); + if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &admin->deleted_participants, guid)) == NULL) known = 0; else known = ((n->for_what & for_what) != 0); - ddsrt_mutex_unlock (&deleted_participants_lock); + ddsrt_mutex_unlock (&admin->deleted_participants_lock); return known; } -static void remove_deleted_participant_guid (const struct nn_guid *guid, unsigned for_what) +static void remove_deleted_participant_guid (ddsrt_log_cfg_t *logcfg, struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what) { struct deleted_participant *n; - DDS_LOG(DDS_LC_DISCOVERY, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what); - ddsrt_mutex_lock (&deleted_participants_lock); - if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &deleted_participants, guid)) != NULL) - { - if (config.prune_deleted_ppant.enforce_delay) - { - n->t_prune = add_duration_to_mtime (now_mt (), config.prune_deleted_ppant.delay); - } - else - { - n->for_what &= ~for_what; - if (n->for_what != 0) - { - /* For local participants (remove called with LOCAL, leaving - REMOTE blacklisted, and has to do with network briding) */ - n->t_prune = add_duration_to_mtime (now_mt (), config.prune_deleted_ppant.delay); - } - else - { - ddsrt_avl_delete (&deleted_participants_treedef, &deleted_participants, n); - ddsrt_free (n); - } - } - } - ddsrt_mutex_unlock (&deleted_participants_lock); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what); + ddsrt_mutex_lock (&admin->deleted_participants_lock); + if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &admin->deleted_participants, guid)) != NULL) + n->t_prune = add_duration_to_mtime (now_mt (), admin->delay); + ddsrt_mutex_unlock (&admin->deleted_participants_lock); } /* PARTICIPANT ------------------------------------------------------ */ -int pp_allocate_entityid(nn_entityid_t *id, unsigned kind, struct participant *pp) +static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, const dds_qos_t *xqos, nn_wctime_t timestamp) +{ + uint64_t mask; + + mask = nn_xqos_delta (ent_qos, xqos, QP_CHANGEABLE_MASK & ~(QP_RXO_MASK | QP_PARTITION)) & xqos->present; +#if 0 + int a = (ent_qos->present & QP_TOPIC_DATA) ? (int) ent_qos->topic_data.length : 6; + int b = (xqos->present & QP_TOPIC_DATA) ? (int) xqos->topic_data.length : 6; + char *astr = (ent_qos->present & QP_TOPIC_DATA) ? (char *) ent_qos->topic_data.value : "(null)"; + char *bstr = (xqos->present & QP_TOPIC_DATA) ? (char *) xqos->topic_data.value : "(null)"; + printf ("%d: "PGUIDFMT" ent_qos %d \"%*.*s\" xqos %d \"%*.*s\" => mask %d\n", + (int) getpid (), PGUID (e->guid), + !!(ent_qos->present & QP_TOPIC_DATA), a, a, astr, + !!(xqos->present & QP_TOPIC_DATA), b, b, bstr, + !!(mask & QP_TOPIC_DATA)); +#endif + EELOGDISC (e, "update_qos_locked "PGUIDFMT" delta=%"PRIu64" QOS={", PGUID(e->guid), mask); + nn_log_xqos (DDS_LC_DISCOVERY, &e->gv->logconfig, xqos); + EELOGDISC (e, "}\n"); + + if (mask == 0) + /* no change, or an as-yet unsupported one */ + return false; + + ddsrt_mutex_lock (&e->qos_lock); + nn_xqos_fini_mask (ent_qos, mask); + nn_xqos_mergein_missing (ent_qos, xqos, mask); + ddsrt_mutex_unlock (&e->qos_lock); + builtintopic_write (e->gv->builtin_topic_interface, e, timestamp, true); + return true; +} + +static dds_return_t pp_allocate_entityid(nn_entityid_t *id, uint32_t kind, struct participant *pp) { uint32_t id1; int ret = 0; @@ -380,21 +429,21 @@ int pp_allocate_entityid(nn_entityid_t *id, unsigned kind, struct participant *p } else { - DDS_ERROR("pp_allocate_entityid("PGUIDFMT"): all ids in use\n", PGUID(pp->e.guid)); - ret = Q_ERR_OUT_OF_IDS; + DDS_CERROR (&pp->e.gv->logconfig, "pp_allocate_entityid("PGUIDFMT"): all ids in use\n", PGUID(pp->e.guid)); + ret = DDS_RETCODE_OUT_OF_RESOURCES; } ddsrt_mutex_unlock (&pp->e.lock); return ret; } -void pp_release_entityid(struct participant *pp, nn_entityid_t id) +static void pp_release_entityid(struct participant *pp, nn_entityid_t id) { ddsrt_mutex_lock (&pp->e.lock); inverse_uint32_set_free(&pp->avail_entityids.x, id.u / NN_ENTITYID_ALLOCSTEP); ddsrt_mutex_unlock (&pp->e.lock); } -int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plist_t *plist) +dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) { struct participant *pp; nn_guid_t subguid, group_guid; @@ -404,64 +453,64 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis /* privileged participant MUST have builtin readers and writers */ assert (!(flags & RTPS_PF_PRIVILEGED_PP) || (flags & (RTPS_PF_NO_BUILTIN_READERS | RTPS_PF_NO_BUILTIN_WRITERS)) == 0); - prune_deleted_participant_guids (now_mt ()); + prune_deleted_participant_guids (gv->deleted_participants, now_mt ()); /* FIXME: FULL LOCKING AROUND NEW_XXX FUNCTIONS, JUST SO EXISTENCE TESTS ARE PRECISE */ /* Participant may not exist yet, but this test is imprecise: if it used to exist, but is currently being deleted and we're trying to recreate it. */ - if (ephash_lookup_participant_guid (ppguid) != NULL) - return Q_ERR_ENTITY_EXISTS; + if (ephash_lookup_participant_guid (gv->guid_hash, ppguid) != NULL) + return DDS_RETCODE_PRECONDITION_NOT_MET; - if (config.max_participants == 0) + if (gv->config.max_participants == 0) { - ddsrt_mutex_lock (&gv.participant_set_lock); - ++gv.nparticipants; - ddsrt_mutex_unlock (&gv.participant_set_lock); + ddsrt_mutex_lock (&gv->participant_set_lock); + ++gv->nparticipants; + ddsrt_mutex_unlock (&gv->participant_set_lock); } else { - ddsrt_mutex_lock (&gv.participant_set_lock); - if (gv.nparticipants < config.max_participants) + ddsrt_mutex_lock (&gv->participant_set_lock); + if (gv->nparticipants < gv->config.max_participants) { - ++gv.nparticipants; - ddsrt_mutex_unlock (&gv.participant_set_lock); + ++gv->nparticipants; + ddsrt_mutex_unlock (&gv->participant_set_lock); } else { - ddsrt_mutex_unlock (&gv.participant_set_lock); - DDS_ERROR("new_participant("PGUIDFMT", %x) failed: max participants reached\n", PGUID (*ppguid), flags); - return Q_ERR_OUT_OF_IDS; + ddsrt_mutex_unlock (&gv->participant_set_lock); + GVERROR ("new_participant("PGUIDFMT", %x) failed: max participants reached\n", PGUID (*ppguid), flags); + return DDS_RETCODE_OUT_OF_RESOURCES; } } - DDS_LOG(DDS_LC_DISCOVERY, "new_participant("PGUIDFMT", %x)\n", PGUID (*ppguid), flags); + GVLOGDISC ("new_participant("PGUIDFMT", %x)\n", PGUID (*ppguid), flags); pp = ddsrt_malloc (sizeof (*pp)); - entity_common_init (&pp->e, ppguid, "", EK_PARTICIPANT, now (), NN_VENDORID_ECLIPSE, ((flags & RTPS_PF_ONLY_LOCAL) != 0)); + entity_common_init (&pp->e, gv, ppguid, "", EK_PARTICIPANT, now (), NN_VENDORID_ECLIPSE, ((flags & RTPS_PF_ONLY_LOCAL) != 0)); pp->user_refc = 1; pp->builtin_refc = 0; pp->builtins_deleted = 0; pp->is_ddsi2_pp = (flags & (RTPS_PF_PRIVILEGED_PP | RTPS_PF_IS_DDSI2_PP)) ? 1 : 0; ddsrt_mutex_init (&pp->refc_lock); inverse_uint32_set_init(&pp->avail_entityids.x, 1, UINT32_MAX / NN_ENTITYID_ALLOCSTEP); - pp->lease_duration = config.lease_duration; + pp->lease_duration = gv->config.lease_duration; pp->plist = ddsrt_malloc (sizeof (*pp->plist)); nn_plist_copy (pp->plist, plist); - nn_plist_mergein_missing (pp->plist, &gv.default_plist_pp); + nn_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0); - if (dds_get_log_mask() & DDS_LC_DISCOVERY) + if (gv->logconfig.c.mask & DDS_LC_DISCOVERY) { - DDS_LOG(DDS_LC_DISCOVERY, "PARTICIPANT "PGUIDFMT" QOS={", PGUID (pp->e.guid)); - nn_log_xqos(DDS_LC_DISCOVERY, &pp->plist->qos); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + GVLOGDISC ("PARTICIPANT "PGUIDFMT" QOS={", PGUID (pp->e.guid)); + nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, &pp->plist->qos); + GVLOGDISC ("}\n"); } - if (config.many_sockets_mode == MSM_MANY_UNICAST) + if (gv->config.many_sockets_mode == MSM_MANY_UNICAST) { - pp->m_conn = ddsi_factory_create_conn (gv.m_factory, 0, NULL); + pp->m_conn = ddsi_factory_create_conn (gv->m_factory, 0, NULL); ddsi_conn_locator (pp->m_conn, &pp->m_locator); } else @@ -488,54 +537,54 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) { subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.spdp_endpoint_xqos, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ { - struct writer *wr = ephash_lookup_writer_guid (&subguid); + struct writer *wr = ephash_lookup_writer_guid (gv->guid_hash, &subguid); assert (wr != NULL); ddsrt_mutex_lock (&wr->e.lock); unref_addrset (wr->as); unref_addrset (wr->as_group); - wr->as = ref_addrset (gv.as_disc); - wr->as_group = ref_addrset (gv.as_disc_group); + wr->as = ref_addrset (gv->as_disc); + wr->as_group = ref_addrset (gv->as_disc_group); ddsrt_mutex_unlock (&wr->e.lock); } pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER; } /* Make it globally visible, else the endpoint matching won't work. */ - ephash_insert_participant_guid (pp); + ephash_insert_participant_guid (gv->guid_hash, pp); /* SEDP writers: */ if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) { subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; } - if (config.do_topic_discovery) + if (gv->config.do_topic_discovery) { /* TODO: make this one configurable, we don't want all participants to publish all topics (or even just those that they use themselves) */ subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER; } @@ -543,7 +592,7 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) { subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_wr, whc_new(1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), LAST_WR_PARAMS); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; } @@ -551,31 +600,31 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis if (!(flags & RTPS_PF_NO_BUILTIN_READERS)) { subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.spdp_endpoint_xqos, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, NULL, NULL, NULL); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR; subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER; subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv.builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER; } @@ -588,38 +637,38 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis pointing to it. Except when the participant is only locally available. */ if (!(flags & RTPS_PF_ONLY_LOCAL)) { - ddsrt_mutex_lock (&gv.privileged_pp_lock); + ddsrt_mutex_lock (&gv->privileged_pp_lock); if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask || (pp->prismtech_bes & prismtech_builtin_writers_besmask) != prismtech_builtin_writers_besmask) { /* Simply crash when the privileged participant doesn't exist when it is needed. Its existence is a precondition, and this is not a public API */ - assert (gv.privileged_pp != NULL); - ref_participant (gv.privileged_pp, &pp->e.guid); + assert (gv->privileged_pp != NULL); + ref_participant (gv->privileged_pp, &pp->e.guid); } if (flags & RTPS_PF_PRIVILEGED_PP) { /* Crash when two privileged participants are created -- this is not a public API. */ - assert (gv.privileged_pp == NULL); - gv.privileged_pp = pp; + assert (gv->privileged_pp == NULL); + gv->privileged_pp = pp; } - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_unlock (&gv->privileged_pp_lock); } /* Make it globally visible, then signal receive threads if necessary. Must do in this order, or the receive thread won't find the new participant */ - if (config.many_sockets_mode == MSM_MANY_UNICAST) + if (gv->config.many_sockets_mode == MSM_MANY_UNICAST) { ddsrt_atomic_fence (); - ddsrt_atomic_inc32 (&gv.participant_set_generation); - trigger_recv_threads (); + ddsrt_atomic_inc32 (&gv->participant_set_generation); + trigger_recv_threads (gv); } - ddsi_plugin.builtintopic_write (&pp->e, now(), true); + builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), true); /* SPDP periodic broadcast uses the retransmit path, so the initial publication must be done differently. Must be later than making @@ -635,7 +684,7 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis fire before the calls return. If the initial sample wasn't accepted, all is lost, but we continue nonetheless, even though the participant won't be able to discover or be discovered. */ - pp->spdp_xevent = qxev_spdp (add_duration_to_mtime (now_mt (), 100 * T_MILLISECOND), &pp->e.guid, NULL); + pp->spdp_xevent = qxev_spdp (gv->xevents, add_duration_to_mtime (now_mt (), 100 * T_MILLISECOND), &pp->e.guid, NULL); } /* Also write the CM data - this one being transient local, we only @@ -645,38 +694,46 @@ int new_participant_guid (const nn_guid_t *ppguid, unsigned flags, const nn_plis { nn_mtime_t tsched; tsched.v = (pp->lease_duration == T_NEVER) ? T_NEVER : 0; - pp->pmd_update_xevent = qxev_pmd_update (tsched, &pp->e.guid); + pp->pmd_update_xevent = qxev_pmd_update (gv->xevents, tsched, &pp->e.guid); } return 0; } -int new_participant (nn_guid_t *p_ppguid, unsigned flags, const nn_plist_t *plist) +dds_return_t new_participant (nn_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) { nn_guid_t ppguid; - ddsrt_mutex_lock (&gv.privileged_pp_lock); - ppguid = gv.next_ppguid; - if (gv.next_ppguid.prefix.u[2]++ == ~0u) + ddsrt_mutex_lock (&gv->privileged_pp_lock); + ppguid = gv->next_ppguid; + if (gv->next_ppguid.prefix.u[2]++ == ~0u) { - ddsrt_mutex_unlock (&gv.privileged_pp_lock); - return Q_ERR_OUT_OF_IDS; + ddsrt_mutex_unlock (&gv->privileged_pp_lock); + return DDS_RETCODE_OUT_OF_RESOURCES; } - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_unlock (&gv->privileged_pp_lock); *p_ppguid = ppguid; - return new_participant_guid (p_ppguid, flags, plist); + return new_participant_guid (p_ppguid, gv, flags, plist); } -static void delete_builtin_endpoint (const struct nn_guid *ppguid, unsigned entityid) +void update_participant_plist (struct participant *pp, const nn_plist_t *plist) +{ + ddsrt_mutex_lock (&pp->e.lock); + if (update_qos_locked (&pp->e, &pp->plist->qos, &plist->qos, now ())) + spdp_write (pp); + ddsrt_mutex_unlock (&pp->e.lock); +} + +static void delete_builtin_endpoint (struct q_globals *gv, const struct nn_guid *ppguid, unsigned entityid) { nn_guid_t guid; guid.prefix = ppguid->prefix; guid.entityid.u = entityid; assert (is_builtin_entityid (to_entityid (entityid), NN_VENDORID_ECLIPSE)); if (is_writer_entityid (to_entityid (entityid))) - delete_writer_nolinger (&guid); + delete_writer_nolinger (gv, &guid); else - (void)delete_reader (&guid); + (void)delete_reader (gv, &guid); } static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity) @@ -692,8 +749,8 @@ static struct participant *ref_participant (struct participant *pp, const struct stguid = *guid_of_refing_entity; else memset (&stguid, 0, sizeof (stguid)); - DDS_LOG(DDS_LC_DISCOVERY, "ref_participant("PGUIDFMT" @ %p <- "PGUIDFMT" @ %p) user %"PRId32" builtin %"PRId32"\n", - PGUID (pp->e.guid), (void*)pp, PGUID (stguid), (void*)guid_of_refing_entity, pp->user_refc, pp->builtin_refc); + ELOGDISC (pp, "ref_participant("PGUIDFMT" @ %p <- "PGUIDFMT" @ %p) user %"PRId32" builtin %"PRId32"\n", + PGUID (pp->e.guid), (void*)pp, PGUID (stguid), (void*)guid_of_refing_entity, pp->user_refc, pp->builtin_refc); ddsrt_mutex_unlock (&pp->refc_lock); return pp; } @@ -733,8 +790,8 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui stguid = *guid_of_refing_entity; else memset (&stguid, 0, sizeof (stguid)); - DDS_LOG(DDS_LC_DISCOVERY, "unref_participant("PGUIDFMT" @ %p <- "PGUIDFMT" @ %p) user %"PRId32" builtin %"PRId32"\n", - PGUID (pp->e.guid), (void*)pp, PGUID (stguid), (void*)guid_of_refing_entity, pp->user_refc, pp->builtin_refc); + ELOGDISC (pp, "unref_participant("PGUIDFMT" @ %p <- "PGUIDFMT" @ %p) user %"PRId32" builtin %"PRId32"\n", + PGUID (pp->e.guid), (void*)pp, PGUID (stguid), (void*)guid_of_refing_entity, pp->user_refc, pp->builtin_refc); if (pp->user_refc == 0 && (pp->bes != 0 || pp->prismtech_bes != 0) && !pp->builtins_deleted) { @@ -776,13 +833,13 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui sedp_write_cm_participant (pp, 0); /* If this happens to be the privileged_pp, clear it */ - ddsrt_mutex_lock (&gv.privileged_pp_lock); - if (pp == gv.privileged_pp) - gv.privileged_pp = NULL; - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); + if (pp == pp->e.gv->privileged_pp) + pp->e.gv->privileged_pp = NULL; + ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock); for (i = 0; i < (int) (sizeof (builtin_endpoints_tab) / sizeof (builtin_endpoints_tab[0])); i++) - delete_builtin_endpoint (&pp->e.guid, builtin_endpoints_tab[i]); + delete_builtin_endpoint (pp->e.gv, &pp->e.guid, builtin_endpoints_tab[i]); } else if (pp->user_refc == 0 && pp->builtin_refc == 0) { @@ -805,23 +862,23 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui the unref_participant, because we may trigger a clean-up of it. */ struct participant *ppp; - ddsrt_mutex_lock (&gv.privileged_pp_lock); - ppp = gv.privileged_pp; - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); + ppp = pp->e.gv->privileged_pp; + ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock); assert (ppp != NULL); unref_participant (ppp, &pp->e.guid); } } - ddsrt_mutex_lock (&gv.participant_set_lock); - assert (gv.nparticipants > 0); - if (--gv.nparticipants == 0) - ddsrt_cond_broadcast (&gv.participant_set_cond); - ddsrt_mutex_unlock (&gv.participant_set_lock); - if (config.many_sockets_mode == MSM_MANY_UNICAST) + ddsrt_mutex_lock (&pp->e.gv->participant_set_lock); + assert (pp->e.gv->nparticipants > 0); + if (--pp->e.gv->nparticipants == 0) + ddsrt_cond_broadcast (&pp->e.gv->participant_set_cond); + ddsrt_mutex_unlock (&pp->e.gv->participant_set_lock); + if (pp->e.gv->config.many_sockets_mode == MSM_MANY_UNICAST) { ddsrt_atomic_fence_rel (); - ddsrt_atomic_inc32 (&gv.participant_set_generation); + ddsrt_atomic_inc32 (&pp->e.gv->participant_set_generation); /* Deleting the socket will usually suffice to wake up the receiver threads, but in general, no one cares if it takes a @@ -832,7 +889,7 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui ddsrt_free (pp->plist); ddsrt_mutex_destroy (&pp->refc_lock); entity_common_fini (&pp->e); - remove_deleted_participant_guid (&pp->e.guid, DPG_LOCAL); + remove_deleted_participant_guid (&pp->e.gv->logconfig, pp->e.gv->deleted_participants, &pp->e.guid, DPG_LOCAL); inverse_uint32_set_fini(&pp->avail_entityids.x); ddsrt_free (pp); } @@ -845,19 +902,19 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui static void gc_delete_participant (struct gcreq *gcreq) { struct participant *pp = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_participant(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pp->e.guid)); + ELOGDISC (pp, "gc_delete_participant(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pp->e.guid)); gcreq_free (gcreq); unref_participant (pp, NULL); } -int delete_participant (const struct nn_guid *ppguid) +dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid) { struct participant *pp; - if ((pp = ephash_lookup_participant_guid (ppguid)) == NULL) - return Q_ERR_UNKNOWN_ENTITY; - ddsi_plugin.builtintopic_write (&pp->e, now(), false); - remember_deleted_participant_guid (&pp->e.guid); - ephash_remove_participant_guid (pp); + if ((pp = ephash_lookup_participant_guid (gv->guid_hash, ppguid)) == NULL) + return DDS_RETCODE_BAD_PARAMETER; + builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), false); + remember_deleted_participant_guid (gv->deleted_participants, &pp->e.guid); + ephash_remove_participant_guid (gv->guid_hash, pp); gcreq_participant (pp); return 0; } @@ -921,14 +978,14 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity who deletes it early! Lock's not really needed but provides the memory barriers that guarantee visibility of the correct value of privileged_pp. */ - ddsrt_mutex_lock (&gv.privileged_pp_lock); - assert (gv.privileged_pp != NULL); - bwr_guid.prefix = gv.privileged_pp->e.guid.prefix; - ddsrt_mutex_unlock (&gv.privileged_pp_lock); + ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); + assert (pp->e.gv->privileged_pp != NULL); + bwr_guid.prefix = pp->e.gv->privileged_pp->e.guid.prefix; + ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock); bwr_guid.entityid.u = entityid; } - return ephash_lookup_writer_guid (&bwr_guid); + return ephash_lookup_writer_guid (pp->e.gv->guid_hash, &bwr_guid); } /* WRITER/READER/PROXY-WRITER/PROXY-READER CONNECTION --------------- @@ -970,20 +1027,21 @@ static int rebuild_compare_locs(const void *va, const void *vb) static struct addrset *rebuild_make_all_addrs (int *nreaders, struct writer *wr) { struct addrset *all_addrs = new_addrset(); + struct ephash *gh = wr->e.gv->guid_hash; struct wr_prd_match *m; ddsrt_avl_iter_t it; #ifdef DDSI_INCLUDE_SSM if (wr->supports_ssm && wr->ssm_as) - copy_addrset_into_addrset_mc (all_addrs, wr->ssm_as); + copy_addrset_into_addrset_mc (wr->e.gv, all_addrs, wr->ssm_as); #endif *nreaders = 0; for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &wr->readers, &it); m; m = ddsrt_avl_iter_next (&it)) { struct proxy_reader *prd; - if ((prd = ephash_lookup_proxy_reader_guid (&m->prd_guid)) == NULL) + if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) == NULL) continue; (*nreaders)++; - copy_addrset_into_addrset(all_addrs, prd->c.as); + copy_addrset_into_addrset(wr->e.gv, all_addrs, prd->c.as); } if (addrset_empty(all_addrs) || *nreaders == 0) { @@ -996,7 +1054,7 @@ static struct addrset *rebuild_make_all_addrs (int *nreaders, struct writer *wr) } } -static void rebuild_make_locs(int *p_nlocs, nn_locator_t **p_locs, struct addrset *all_addrs) +static void rebuild_make_locs(const struct ddsrt_log_cfg *logcfg, int *p_nlocs, nn_locator_t **p_locs, struct addrset *all_addrs) { struct rebuild_flatten_locs_arg flarg; int nlocs; @@ -1021,7 +1079,7 @@ static void rebuild_make_locs(int *p_nlocs, nn_locator_t **p_locs, struct addrse j++; } nlocs = i+1; - DDS_LOG(DDS_LC_DISCOVERY, "reduced nlocs=%d\n", nlocs); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "reduced nlocs=%d\n", nlocs); *p_nlocs = nlocs; *p_locs = locs; } @@ -1029,6 +1087,7 @@ static void rebuild_make_locs(int *p_nlocs, nn_locator_t **p_locs, struct addrse static void rebuild_make_covered(int8_t **covered, const struct writer *wr, int *nreaders, int nlocs, const nn_locator_t *locs) { struct rebuild_flatten_locs_arg flarg; + struct ephash *gh = wr->e.gv->guid_hash; struct wr_prd_match *m; ddsrt_avl_iter_t it; int rdidx, i, j; @@ -1044,7 +1103,7 @@ static void rebuild_make_covered(int8_t **covered, const struct writer *wr, int { struct proxy_reader *prd; struct addrset *ass[] = { NULL, NULL, NULL }; - if ((prd = ephash_lookup_proxy_reader_guid (&m->prd_guid)) == NULL) + if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) == NULL) continue; ass[0] = prd->c.as; #ifdef DDSI_INCLUDE_SSM @@ -1092,45 +1151,47 @@ static void rebuild_make_locs_nrds(int **locs_nrds, int nreaders, int nlocs, con if (covered[j * nlocs + i] >= 0) n++; -/* The compiler doesn't realize that ln is large enough. */ -DDSRT_WARNING_MSVC_OFF(6386); + /* The compiler doesn't realize that ln is large enough. */ + DDSRT_WARNING_MSVC_OFF(6386); ln[i] = n; -DDSRT_WARNING_MSVC_ON(6386); + DDSRT_WARNING_MSVC_ON(6386); } *locs_nrds = ln; } -static void rebuild_trace_covered(int nreaders, int nlocs, const nn_locator_t *locs, const int *locs_nrds, const int8_t *covered) +static void rebuild_trace_covered(const struct q_globals *gv, int nreaders, int nlocs, const nn_locator_t *locs, const int *locs_nrds, const int8_t *covered) { int i, j; for (i = 0; i < nlocs; i++) { char buf[DDSI_LOCATORSTRLEN]; - ddsi_locator_to_string(buf, sizeof(buf), &locs[i]); - DDS_LOG(DDS_LC_DISCOVERY, " loc %2d = %-20s %2d {", i, buf, locs_nrds[i]); + ddsi_locator_to_string(gv, buf, sizeof(buf), &locs[i]); + GVLOGDISC (" loc %2d = %-30s %2d {", i, buf, locs_nrds[i]); for (j = 0; j < nreaders; j++) if (covered[j * nlocs + i] >= 0) - DDS_LOG(DDS_LC_DISCOVERY, " %d", covered[j * nlocs + i]); + GVLOGDISC (" %d", covered[j * nlocs + i]); else - DDS_LOG(DDS_LC_DISCOVERY, " ."); - DDS_LOG(DDS_LC_DISCOVERY, " }\n"); + GVLOGDISC (" ."); + GVLOGDISC (" }\n"); } } -static int rebuild_select(int nlocs, const nn_locator_t *locs, const int *locs_nrds) +static int rebuild_select(const struct q_globals *gv, int nlocs, const nn_locator_t *locs, const int *locs_nrds, bool prefer_multicast) { int i, j; if (nlocs == 0) return -1; for (j = 0, i = 1; i < nlocs; i++) { - if (locs_nrds[i] > locs_nrds[j]) + if (prefer_multicast && locs_nrds[i] > 0 && ddsi_is_mcaddr(gv, &locs[i]) && !ddsi_is_mcaddr(gv, &locs[j])) + j = i; /* obviously first step must be to try and avoid unicast if configuration says so */ + else if (locs_nrds[i] > locs_nrds[j]) j = i; /* better coverage */ else if (locs_nrds[i] == locs_nrds[j]) { - if (locs_nrds[i] == 1 && !ddsi_is_mcaddr(&locs[i])) + if (locs_nrds[i] == 1 && !ddsi_is_mcaddr(gv, &locs[i])) j = i; /* prefer unicast for single nodes */ #if DDSI_INCLUDE_SSM - else if (ddsi_is_ssm_mcaddr(&locs[i])) + else if (ddsi_is_ssm_mcaddr(gv, &locs[i])) j = i; /* "reader favours SSM": all else being equal, use SSM */ #endif } @@ -1138,14 +1199,14 @@ static int rebuild_select(int nlocs, const nn_locator_t *locs, const int *locs_n return (locs_nrds[j] > 0) ? j : -1; } -static void rebuild_add(struct addrset *newas, int locidx, int nreaders, int nlocs, const nn_locator_t *locs, const int8_t *covered) +static void rebuild_add(const struct q_globals *gv, struct addrset *newas, int locidx, int nreaders, int nlocs, const nn_locator_t *locs, const int8_t *covered) { char str[DDSI_LOCATORSTRLEN]; if (locs[locidx].kind != NN_LOCATOR_KIND_UDPv4MCGEN) { - ddsi_locator_to_string(str, sizeof(str), &locs[locidx]); - DDS_LOG(DDS_LC_DISCOVERY, " simple %s\n", str); - add_to_addrset(newas, &locs[locidx]); + ddsi_locator_to_string(gv, str, sizeof(str), &locs[locidx]); + GVLOGDISC (" simple %s\n", str); + add_to_addrset(gv, newas, &locs[locidx]); } else /* convert MC gen to the correct multicast address */ { @@ -1162,9 +1223,9 @@ static void rebuild_add(struct addrset *newas, int locidx, int nreaders, int nlo iph |= 1u << covered[i * nlocs + locidx]; ipn = htonl(iph); memcpy(l.address + 12, &ipn, 4); - ddsi_locator_to_string(str, sizeof(str), &l); - DDS_LOG(DDS_LC_DISCOVERY, " mcgen %s\n", str); - add_to_addrset(newas, &l); + ddsi_locator_to_string(gv, str, sizeof(str), &l); + GVLOGDISC (" mcgen %s\n", str); + add_to_addrset(gv, newas, &l); } } @@ -1188,6 +1249,7 @@ static void rebuild_drop(int locidx, int nreaders, int nlocs, int *locs_nrds, in static void rebuild_writer_addrset_setcover(struct addrset *newas, struct writer *wr) { + bool prefer_multicast = wr->e.gv->config.prefer_multicast; struct addrset *all_addrs; int nreaders, nlocs; nn_locator_t *locs; @@ -1196,19 +1258,19 @@ static void rebuild_writer_addrset_setcover(struct addrset *newas, struct writer int best; if ((all_addrs = rebuild_make_all_addrs(&nreaders, wr)) == NULL) return; - nn_log_addrset(DDS_LC_DISCOVERY, "setcover: all_addrs", all_addrs); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); - rebuild_make_locs(&nlocs, &locs, all_addrs); + nn_log_addrset(wr->e.gv, DDS_LC_DISCOVERY, "setcover: all_addrs", all_addrs); + ELOGDISC (wr, "\n"); + rebuild_make_locs(&wr->e.gv->logconfig, &nlocs, &locs, all_addrs); unref_addrset(all_addrs); rebuild_make_covered(&covered, wr, &nreaders, nlocs, locs); if (nreaders == 0) goto done; rebuild_make_locs_nrds(&locs_nrds, nreaders, nlocs, covered); - while ((best = rebuild_select(nlocs, locs, locs_nrds)) >= 0) + while ((best = rebuild_select(wr->e.gv, nlocs, locs, locs_nrds, prefer_multicast)) >= 0) { - rebuild_trace_covered(nreaders, nlocs, locs, locs_nrds, covered); - DDS_LOG(DDS_LC_DISCOVERY, " best = %d\n", best); - rebuild_add(newas, best, nreaders, nlocs, locs, covered); + rebuild_trace_covered(wr->e.gv, nreaders, nlocs, locs, locs_nrds, covered); + ELOGDISC (wr, " best = %d\n", best); + rebuild_add(wr->e.gv, newas, best, nreaders, nlocs, locs, covered); rebuild_drop(best, nreaders, nlocs, locs_nrds, covered); assert (locs_nrds[best] == 0); } @@ -1235,19 +1297,18 @@ static void rebuild_writer_addrset (struct writer *wr) wr->as = newas; unref_addrset (oldas); - DDS_LOG(DDS_LC_DISCOVERY, "rebuild_writer_addrset("PGUIDFMT"):", PGUID (wr->e.guid)); - nn_log_addrset(DDS_LC_DISCOVERY, "", wr->as); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); + ELOGDISC (wr, "rebuild_writer_addrset("PGUIDFMT"):", PGUID (wr->e.guid)); + nn_log_addrset(wr->e.gv, DDS_LC_DISCOVERY, "", wr->as); + ELOGDISC (wr, "\n"); } -void rebuild_or_clear_writer_addrsets(int rebuild) +void rebuild_or_clear_writer_addrsets (struct q_globals *gv, int rebuild) { struct ephash_enum_writer est; struct writer *wr; struct addrset *empty = rebuild ? NULL : new_addrset(); - DDS_LOG(DDS_LC_DISCOVERY, "rebuild_or_delete_writer_addrsets(%d)\n", rebuild); - ephash_enum_writer_init (&est); - ddsrt_rwlock_read (&gv.qoslock); + GVLOGDISC ("rebuild_or_delete_writer_addrsets(%d)\n", rebuild); + ephash_enum_writer_init (&est, gv->guid_hash); while ((wr = ephash_enum_writer_next (&est)) != NULL) { ddsrt_mutex_lock (&wr->e.lock); @@ -1265,16 +1326,15 @@ void rebuild_or_clear_writer_addrsets(int rebuild) empty one. */ unref_addrset(wr->as); if (rebuild) - wr->as = ref_addrset(gv.as_disc); + wr->as = ref_addrset(gv->as_disc); else wr->as = ref_addrset(empty); } ddsrt_mutex_unlock (&wr->e.lock); } - ddsrt_rwlock_unlock (&gv.qoslock); ephash_enum_writer_fini (&est); unref_addrset(empty); - DDS_LOG(DDS_LC_DISCOVERY, "rebuild_or_delete_writer_addrsets(%d) done\n", rebuild); + GVLOGDISC ("rebuild_or_delete_writer_addrsets(%d) done\n", rebuild); } static void free_wr_prd_match (struct wr_prd_match *m) @@ -1286,18 +1346,20 @@ static void free_wr_prd_match (struct wr_prd_match *m) } } -static void free_rd_pwr_match (struct rd_pwr_match *m) +static void free_rd_pwr_match (struct q_globals *gv, struct rd_pwr_match *m) { if (m) { #ifdef DDSI_INCLUDE_SSM if (!is_unspec_locator (&m->ssm_mc_loc)) { - assert (ddsi_is_mcaddr (&m->ssm_mc_loc)); + assert (ddsi_is_mcaddr (gv, &m->ssm_mc_loc)); assert (!is_unspec_locator (&m->ssm_src_loc)); - if (ddsi_leave_mc (gv.data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc) < 0) - DDS_WARNING("failed to leave network partition ssm group\n"); + if (ddsi_leave_mc (gv, gv->mship, gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc) < 0) + GVWARNING ("failed to leave network partition ssm group\n"); } +#else + (void) gv; #endif ddsrt_free (m); } @@ -1329,10 +1391,10 @@ static void free_wr_rd_match (struct wr_rd_match *m) if (m) ddsrt_free (m); } -static void writer_drop_connection (const struct nn_guid * wr_guid, const struct proxy_reader * prd) +static void writer_drop_connection (const struct nn_guid *wr_guid, const struct proxy_reader *prd) { struct writer *wr; - if ((wr = ephash_lookup_writer_guid (wr_guid)) != NULL) + if ((wr = ephash_lookup_writer_guid (prd->e.gv->guid_hash, wr_guid)) != NULL) { struct whc_node *deferred_free_list = NULL; struct wr_prd_match *m; @@ -1363,7 +1425,7 @@ static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct { /* Only called by gc_delete_reader, so we actually have a reader pointer */ struct writer *wr; - if ((wr = ephash_lookup_writer_guid (wr_guid)) != NULL) + if ((wr = ephash_lookup_writer_guid (rd->e.gv->guid_hash, wr_guid)) != NULL) { struct wr_rd_match *m; @@ -1386,23 +1448,23 @@ static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct } } -static void reader_drop_connection (const struct nn_guid *rd_guid, const struct proxy_writer * pwr) +static void reader_drop_connection (const struct nn_guid *rd_guid, const struct proxy_writer *pwr) { struct reader *rd; - if ((rd = ephash_lookup_reader_guid (rd_guid)) != NULL) + if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL) { struct rd_pwr_match *m; ddsrt_mutex_lock (&rd->e.lock); if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL) ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m); ddsrt_mutex_unlock (&rd->e.lock); - free_rd_pwr_match (m); + free_rd_pwr_match (pwr->e.gv, m); if (rd->rhc) { struct proxy_writer_info pwr_info; make_proxy_writer_info(&pwr_info, &pwr->e, pwr->c.xqos); - (ddsi_plugin.rhc_plugin.rhc_unregister_wr_fn) (rd->rhc, &pwr_info); + rhc_unregister_wr (rd->rhc, &pwr_info); } if (rd->status_cb) { @@ -1420,10 +1482,10 @@ static void reader_drop_connection (const struct nn_guid *rd_guid, const struct } } -static void reader_drop_local_connection (const struct nn_guid *rd_guid, const struct writer * wr) +static void reader_drop_local_connection (const struct nn_guid *rd_guid, const struct writer *wr) { struct reader *rd; - if ((rd = ephash_lookup_reader_guid (rd_guid)) != NULL) + if ((rd = ephash_lookup_reader_guid (wr->e.gv->guid_hash, rd_guid)) != NULL) { struct rd_wr_match *m; ddsrt_mutex_lock (&rd->e.lock); @@ -1437,7 +1499,7 @@ static void reader_drop_local_connection (const struct nn_guid *rd_guid, const s /* FIXME: */ struct proxy_writer_info pwr_info; make_proxy_writer_info(&pwr_info, &wr->e, wr->xqos); - (ddsi_plugin.rhc_plugin.rhc_unregister_wr_fn) (rd->rhc, &pwr_info); + rhc_unregister_wr (rd->rhc, &pwr_info); } if (rd->status_cb) { @@ -1455,25 +1517,25 @@ static void reader_drop_local_connection (const struct nn_guid *rd_guid, const s } } -static void update_reader_init_acknack_count (const struct nn_guid *rd_guid, nn_count_t count) +static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, const struct ephash *guid_hash, const struct nn_guid *rd_guid, nn_count_t count) { struct reader *rd; /* Update the initial acknack sequence number for the reader. See also reader_add_connection(). */ - DDS_LOG(DDS_LC_DISCOVERY, "update_reader_init_acknack_count ("PGUIDFMT", %"PRId32"): ", PGUID (*rd_guid), count); - if ((rd = ephash_lookup_reader_guid (rd_guid)) != NULL) + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "update_reader_init_acknack_count ("PGUIDFMT", %"PRId32"): ", PGUID (*rd_guid), count); + if ((rd = ephash_lookup_reader_guid (guid_hash, rd_guid)) != NULL) { ddsrt_mutex_lock (&rd->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "%"PRId32" -> ", rd->init_acknack_count); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "%"PRId32" -> ", rd->init_acknack_count); if (count > rd->init_acknack_count) rd->init_acknack_count = count; - DDS_LOG(DDS_LC_DISCOVERY, "%"PRId32"\n", count); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "%"PRId32"\n", count); ddsrt_mutex_unlock (&rd->e.lock); } else { - DDS_LOG(DDS_LC_DISCOVERY, "reader no longer exists\n"); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "reader no longer exists\n"); } } @@ -1481,7 +1543,7 @@ static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct { /* Only called by gc_delete_reader, so we actually have a reader pointer */ struct proxy_writer *pwr; - if ((pwr = ephash_lookup_proxy_writer_guid (pwr_guid)) != NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (rd->e.gv->guid_hash, pwr_guid)) != NULL) { struct pwr_rd_match *m; @@ -1490,25 +1552,32 @@ static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct { ddsrt_avl_delete (&pwr_readers_treedef, &pwr->readers, m); if (m->in_sync != PRMSS_SYNC) - pwr->n_readers_out_of_sync--; + { + if (--pwr->n_readers_out_of_sync == 0) + local_reader_ary_setfastpath_ok (&pwr->rdary, true); + } if (rd->reliable) pwr->n_reliable_readers--; + /* If no reliable readers left, there is no reason to believe the heartbeats will keep + coming and therefore reset have_seen_heartbeat so the next reader to be created + doesn't get initialised based on stale data */ + if (pwr->n_reliable_readers == 0) + pwr->have_seen_heartbeat = 0; local_reader_ary_remove (&pwr->rdary, rd); } ddsrt_mutex_unlock (&pwr->e.lock); if (m != NULL) { - update_reader_init_acknack_count (&rd->e.guid, m->count); + update_reader_init_acknack_count (&rd->e.gv->logconfig, rd->e.gv->guid_hash, &rd->e.guid, m->count); } free_pwr_rd_match (m); } } -static void proxy_reader_drop_connection - (const struct nn_guid *prd_guid, struct writer * wr) +static void proxy_reader_drop_connection (const struct nn_guid *prd_guid, struct writer *wr) { struct proxy_reader *prd; - if ((prd = ephash_lookup_proxy_reader_guid (prd_guid)) != NULL) + if ((prd = ephash_lookup_proxy_reader_guid (wr->e.gv->guid_hash, prd_guid)) != NULL) { struct prd_wr_match *m; ddsrt_mutex_lock (&prd->e.lock); @@ -1528,8 +1597,8 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) ddsrt_avl_ipath_t path; int pretend_everything_acked; m->prd_guid = prd->e.guid; - m->is_reliable = (prd->c.xqos->reliability.kind > NN_BEST_EFFORT_RELIABILITY_QOS); - m->assumed_in_sync = (config.retransmit_merging == REXMIT_MERGE_ALWAYS); + m->is_reliable = (prd->c.xqos->reliability.kind > DDS_RELIABILITY_BEST_EFFORT); + m->assumed_in_sync = (wr->e.gv->config.retransmit_merging == REXMIT_MERGE_ALWAYS); m->has_replied_to_hb = !m->is_reliable; m->all_have_replied_to_hb = 0; m->non_responsive_count = 0; @@ -1538,8 +1607,8 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) ddsrt_mutex_lock (&prd->e.lock); if (prd->deleting) { - DDS_LOG(DDS_LC_DISCOVERY, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - prd is being deleted\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + ELOGDISC (wr, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - prd is being deleted\n", + PGUID (wr->e.guid), PGUID (prd->e.guid)); pretend_everything_acked = 1; } else if (!m->is_reliable) @@ -1566,14 +1635,16 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) m->seq = wr->seq; if (ddsrt_avl_lookup_ipath (&wr_readers_treedef, &wr->readers, &prd->e.guid, &path)) { - DDS_LOG(DDS_LC_DISCOVERY, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); + ELOGDISC (wr, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n", + PGUID (wr->e.guid), PGUID (prd->e.guid)); ddsrt_mutex_unlock (&wr->e.lock); nn_lat_estim_fini (&m->hb_to_ack_latency); ddsrt_free (m); } else { - DDS_LOG(DDS_LC_DISCOVERY, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - ack seq %"PRId64"\n", PGUID (wr->e.guid), PGUID (prd->e.guid), m->seq); + ELOGDISC (wr, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - ack seq %"PRId64"\n", + PGUID (wr->e.guid), PGUID (prd->e.guid), m->seq); ddsrt_avl_insert_ipath (&wr_readers_treedef, &wr->readers, m, &path); rebuild_writer_addrset (wr); wr->num_reliable_readers += m->is_reliable; @@ -1623,13 +1694,15 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd) ddsrt_mutex_lock (&wr->e.lock); if (ddsrt_avl_lookup_ipath (&wr_local_readers_treedef, &wr->local_readers, &rd->e.guid, &path)) { - DDS_LOG(DDS_LC_DISCOVERY, " writer_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", PGUID (wr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (wr, " writer_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", + PGUID (wr->e.guid), PGUID (rd->e.guid)); ddsrt_mutex_unlock (&wr->e.lock); ddsrt_free (m); return; } - DDS_LOG(DDS_LC_DISCOVERY, " writer_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT")", PGUID (wr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (wr, " writer_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT")", + PGUID (wr->e.guid), PGUID (rd->e.guid)); m->rd_guid = rd->e.guid; ddsrt_avl_insert_ipath (&wr_local_readers_treedef, &wr->local_readers, m, &path); local_reader_ary_insert (&wr->rdary, rd); @@ -1638,8 +1711,9 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd) historical data for best-effort data over the wire, so also not locally). FIXME: should limit ourselves to what it is available because of durability history, not writer history */ - if (rd->xqos->reliability.kind > NN_BEST_EFFORT_RELIABILITY_QOS && rd->xqos->durability.kind > NN_VOLATILE_DURABILITY_QOS) + if (rd->xqos->reliability.kind > DDS_RELIABILITY_BEST_EFFORT && rd->xqos->durability.kind > DDS_DURABILITY_VOLATILE) { + struct ddsi_tkmap *tkmap = rd->e.gv->m_tkmap; struct whc_sample_iter it; struct whc_borrowed_sample sample; whc_sample_iter_init(wr->whc, &it); @@ -1648,16 +1722,16 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd) struct proxy_writer_info pwr_info; struct ddsi_serdata *payload = sample.serdata; /* FIXME: whc has tk reference in its index nodes, which is what we really should be iterating over anyway, and so we don't really have to look them up anymore */ - struct ddsi_tkmap_instance *tk = ddsi_tkmap_lookup_instance_ref(payload); - make_proxy_writer_info(&pwr_info, &wr->e, wr->xqos); - (void)(ddsi_plugin.rhc_plugin.rhc_store_fn) (rd->rhc, &pwr_info, payload, tk); - ddsi_tkmap_instance_unref(tk); + struct ddsi_tkmap_instance *tk = ddsi_tkmap_lookup_instance_ref (tkmap, payload); + make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos); + (void) rhc_store (rd->rhc, &pwr_info, payload, tk); + ddsi_tkmap_instance_unref (tkmap, tk); } } ddsrt_mutex_unlock (&wr->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); + ELOGDISC (wr, "\n"); if (wr->status_cb) { @@ -1684,20 +1758,21 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, writer will always see monotonically increasing sequence numbers from one particular reader. This is then used for the pwr_rd_match initialization */ - DDS_LOG(DDS_LC_DISCOVERY, " reader "PGUIDFMT" init_acknack_count = %"PRId32"\n", PGUID (rd->e.guid), rd->init_acknack_count); + ELOGDISC (rd, " reader "PGUIDFMT" init_acknack_count = %"PRId32"\n", + PGUID (rd->e.guid), rd->init_acknack_count); *init_count = rd->init_acknack_count; if (ddsrt_avl_lookup_ipath (&rd_writers_treedef, &rd->writers, &pwr->e.guid, &path)) { - DDS_LOG(DDS_LC_DISCOVERY, " reader_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", - PGUID (pwr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (rd, " reader_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", + PGUID (pwr->e.guid), PGUID (rd->e.guid)); ddsrt_mutex_unlock (&rd->e.lock); ddsrt_free (m); } else { - DDS_LOG(DDS_LC_DISCOVERY, " reader_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT")\n", - PGUID (pwr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (rd, " reader_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT")\n", + PGUID (pwr->e.guid), PGUID (rd->e.guid)); ddsrt_avl_insert_ipath (&rd_writers_treedef, &rd->writers, m, &path); ddsrt_mutex_unlock (&rd->e.lock); @@ -1708,12 +1783,12 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, any_ssm must succeed. */ if (!addrset_any_uc (pwr->c.as, &m->ssm_src_loc)) assert (0); - if (!addrset_any_ssm (pwr->c.as, &m->ssm_mc_loc)) + if (!addrset_any_ssm (rd->e.gv, pwr->c.as, &m->ssm_mc_loc)) assert (0); /* FIXME: for now, assume that the ports match for datasock_mc -- 't would be better to dynamically create and destroy sockets on an as needed basis. */ - ddsi_join_mc (gv.data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc); + ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc); } else { @@ -1744,13 +1819,15 @@ static void reader_add_local_connection (struct reader *rd, struct writer *wr) if (ddsrt_avl_lookup_ipath (&rd_local_writers_treedef, &rd->local_writers, &wr->e.guid, &path)) { - DDS_LOG(DDS_LC_DISCOVERY, " reader_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", PGUID (wr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (rd, " reader_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", + PGUID (wr->e.guid), PGUID (rd->e.guid)); ddsrt_mutex_unlock (&rd->e.lock); ddsrt_free (m); } else { - DDS_LOG(DDS_LC_DISCOVERY, " reader_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT")\n", PGUID (wr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (rd, " reader_add_local_connection(wr "PGUIDFMT" rd "PGUIDFMT")\n", + PGUID (wr->e.guid), PGUID (rd->e.guid)); ddsrt_avl_insert_ipath (&rd_local_writers_treedef, &rd->local_writers, m, &path); ddsrt_mutex_unlock (&rd->e.lock); @@ -1773,7 +1850,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader { struct pwr_rd_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; - seqno_t last_deliv_seq; ddsrt_mutex_lock (&pwr->e.lock); if (ddsrt_avl_lookup_ipath (&pwr_readers_treedef, &pwr->readers, &rd->e.guid, &path)) @@ -1787,12 +1863,11 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader pwr->ddsi2direct_cbarg = rd->ddsi2direct_cbarg; } - DDS_LOG(DDS_LC_DISCOVERY, " proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT")", - PGUID (pwr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (pwr, " proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT")", + PGUID (pwr->e.guid), PGUID (rd->e.guid)); m->rd_guid = rd->e.guid; m->tcreate = now_mt (); - /* We track the last heartbeat count value per reader--proxy-writer pair, so that we can correctly handle directed heartbeats. The only reason to bother is to prevent a directed heartbeat (with @@ -1811,34 +1886,61 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader /* These can change as a consequence of handling data and/or discovery activities. The safe way of dealing with them is to lock the proxy writer */ - last_deliv_seq = nn_reorder_next_seq (pwr->reorder) - 1; - if (!rd->handle_as_transient_local) + if (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) && !ddsrt_avl_is_empty (&pwr->readers)) { + /* builtins really don't care about multiple copies or anything */ m->in_sync = PRMSS_SYNC; } - else if (!config.conservative_builtin_reader_startup && is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) && !ddsrt_avl_is_empty (&pwr->readers)) + else if (!pwr->have_seen_heartbeat) { - /* builtins really don't care about multiple copies */ + /* Proxy writer hasn't seen a heartbeat yet: means we have no + clue from what sequence number to start accepting data, nor + where historical data ends and live data begins. + + A transient-local reader should always get all historical + data, and so can always start-out as "out-of-sync". Cyclone + refuses to retransmit already ACK'd samples to a Cyclone + reader, so if the other side is Cyclone, we can always start + from sequence number 1. + + For non-Cyclone, if the reader is volatile, we have to just + start from the most recent sample, even though that means + the first samples written after matching the reader may be + lost. The alternative not only gets too much historical data + but may also result in "sample lost" notifications because the + writer is (may not be) retaining samples on behalf of this + reader for the oldest samples and so this reader may end up + with a partial set of old-ish samples. Even when both are + using KEEP_ALL and the connection doesn't fail ... */ + if (rd->handle_as_transient_local) + m->in_sync = PRMSS_OUT_OF_SYNC; + else if (vendor_is_eclipse (pwr->c.vendor)) + m->in_sync = PRMSS_OUT_OF_SYNC; + else + m->in_sync = PRMSS_SYNC; + m->u.not_in_sync.end_of_tl_seq = MAX_SEQ_NUMBER; + } + else if (!rd->handle_as_transient_local) + { + /* volatile reader, writer has seen a heartbeat: it's in sync + (there is a risk of it getting some historical data: that + happens to be cached in the writer's reorder admin at this + point) */ m->in_sync = PRMSS_SYNC; } else { - /* normal transient-local, reader is behind proxy writer */ + /* transient-local reader; range of sequence numbers is already + known */ m->in_sync = PRMSS_OUT_OF_SYNC; - if (last_deliv_seq == 0) - { - m->u.not_in_sync.end_of_out_of_sync_seq = MAX_SEQ_NUMBER; - m->u.not_in_sync.end_of_tl_seq = MAX_SEQ_NUMBER; - } - else - { - m->u.not_in_sync.end_of_tl_seq = pwr->last_seq; - m->u.not_in_sync.end_of_out_of_sync_seq = last_deliv_seq; - } - DDS_LOG(DDS_LC_DISCOVERY, " - out-of-sync %"PRId64, m->u.not_in_sync.end_of_out_of_sync_seq); + m->u.not_in_sync.end_of_tl_seq = pwr->last_seq; } if (m->in_sync != PRMSS_SYNC) + { + ELOGDISC (pwr, " - out-of-sync"); pwr->n_readers_out_of_sync++; + local_reader_ary_setfastpath_ok (&pwr->rdary, false); + } m->count = init_count; /* Spec says we may send a pre-emptive AckNack (8.4.2.3.4), hence we schedule it for the configured delay * T_MILLISECOND. From then @@ -1848,16 +1950,16 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader difference in practice.) */ if (rd->reliable) { - m->acknack_xevent = qxev_acknack (pwr->evq, add_duration_to_mtime (tnow, config.preemptive_ack_delay), &pwr->e.guid, &rd->e.guid); + m->acknack_xevent = qxev_acknack (pwr->evq, add_duration_to_mtime (tnow, pwr->e.gv->config.preemptive_ack_delay), &pwr->e.guid, &rd->e.guid); m->u.not_in_sync.reorder = - nn_reorder_new (NN_REORDER_MODE_NORMAL, config.secondary_reorder_maxsamples); + nn_reorder_new (&pwr->e.gv->logconfig, NN_REORDER_MODE_NORMAL, pwr->e.gv->config.secondary_reorder_maxsamples, pwr->e.gv->config.late_ack_mode); pwr->n_reliable_readers++; } else { m->acknack_xevent = NULL; m->u.not_in_sync.reorder = - nn_reorder_new (NN_REORDER_MODE_MONOTONICALLY_INCREASING, config.secondary_reorder_maxsamples); + nn_reorder_new (&pwr->e.gv->logconfig, NN_REORDER_MODE_MONOTONICALLY_INCREASING, pwr->e.gv->config.secondary_reorder_maxsamples, pwr->e.gv->config.late_ack_mode); } ddsrt_avl_insert_ipath (&pwr_readers_treedef, &pwr->readers, m, &path); @@ -1865,7 +1967,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader ddsrt_mutex_unlock (&pwr->e.lock); qxev_pwr_entityid (pwr, &rd->e.guid.prefix); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); + ELOGDISC (pwr, "\n"); if (rd->status_cb) { @@ -1880,8 +1982,8 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader already_matched: assert (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor) ? (pwr->c.topic == NULL) : (pwr->c.topic != NULL)); - DDS_LOG(DDS_LC_DISCOVERY, " proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", - PGUID (pwr->e.guid), PGUID (rd->e.guid)); + ELOGDISC (pwr, " proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n", + PGUID (pwr->e.guid), PGUID (rd->e.guid)); ddsrt_mutex_unlock (&pwr->e.lock); ddsrt_free (m); return; @@ -1898,15 +2000,15 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer prd->c.topic = ddsi_sertopic_ref (wr->topic); if (ddsrt_avl_lookup_ipath (&prd_writers_treedef, &prd->writers, &wr->e.guid, &path)) { - DDS_LOG(DDS_LC_DISCOVERY, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + ELOGDISC (prd, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n", + PGUID (wr->e.guid), PGUID (prd->e.guid)); ddsrt_mutex_unlock (&prd->e.lock); ddsrt_free (m); } else { - DDS_LOG(DDS_LC_DISCOVERY, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT")\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + ELOGDISC (prd, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT")\n", + PGUID (wr->e.guid), PGUID (prd->e.guid)); ddsrt_avl_insert_ipath (&prd_writers_treedef, &prd->writers, m, &path); ddsrt_mutex_unlock (&prd->e.lock); qxev_prd_entityid (prd, &wr->e.guid.prefix); @@ -1979,60 +2081,64 @@ static nn_entityid_t builtin_entityid_match (nn_entityid_t x) return res; } -static void writer_qos_mismatch (struct writer * wr, uint32_t reason) +static void writer_qos_mismatch (struct writer * wr, dds_qos_policy_id_t reason) { /* When the reason is DDS_INVALID_QOS_POLICY_ID, it means that we compared * readers/writers from different topics: ignore that. */ - if (reason != DDS_INVALID_QOS_POLICY_ID) + if (reason != DDS_INVALID_QOS_POLICY_ID && wr->status_cb) { - if (wr->topic->status_cb) { - /* Handle INCONSISTENT_TOPIC on topic */ - (wr->topic->status_cb) (wr->topic->status_cb_entity); - } - if (wr->status_cb) - { - status_cb_data_t data; - data.raw_status_id = (int) DDS_OFFERED_INCOMPATIBLE_QOS_STATUS_ID; - data.extra = reason; - (wr->status_cb) (wr->status_cb_entity, &data); - } + status_cb_data_t data; + data.raw_status_id = (int) DDS_OFFERED_INCOMPATIBLE_QOS_STATUS_ID; + data.extra = reason; + (wr->status_cb) (wr->status_cb_entity, &data); } } -static void reader_qos_mismatch (struct reader * rd, uint32_t reason) +static void reader_qos_mismatch (struct reader * rd, dds_qos_policy_id_t reason) { /* When the reason is DDS_INVALID_QOS_POLICY_ID, it means that we compared * readers/writers from different topics: ignore that. */ - if (reason != DDS_INVALID_QOS_POLICY_ID) + if (reason != DDS_INVALID_QOS_POLICY_ID && rd->status_cb) { - if (rd->topic->status_cb) - { - /* Handle INCONSISTENT_TOPIC on topic */ - (rd->topic->status_cb) (rd->topic->status_cb_entity); - } - if (rd->status_cb) - { - status_cb_data_t data; - data.raw_status_id = (int) DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS_ID; - data.extra = reason; - (rd->status_cb) (rd->status_cb_entity, &data); - } + status_cb_data_t data; + data.raw_status_id = (int) DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS_ID; + data.extra = reason; + (rd->status_cb) (rd->status_cb_entity, &data); } } +static bool topickind_qos_match_p_lock (struct entity_common *rd, const dds_qos_t *rdqos, struct entity_common *wr, const dds_qos_t *wrqos, dds_qos_policy_id_t *reason) +{ + assert (is_reader_entityid (rd->guid.entityid)); + assert (is_writer_entityid (wr->guid.entityid)); + if (is_keyed_endpoint_entityid (rd->guid.entityid) != is_keyed_endpoint_entityid (wr->guid.entityid)) + { + *reason = DDS_INVALID_QOS_POLICY_ID; + return false; + } + ddsrt_mutex_t * const locks[] = { &rd->qos_lock, &wr->qos_lock, &rd->qos_lock }; + const int shift = (uintptr_t) rd > (uintptr_t) wr; + for (int i = 0; i < 2; i++) + ddsrt_mutex_lock (locks[i + shift]); + bool ret = qos_match_p (rdqos, wrqos, reason); + for (int i = 0; i < 2; i++) + ddsrt_mutex_unlock (locks[i + shift]); + return ret; +} + static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow) { const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); const int isb1 = (is_builtin_entityid (prd->e.guid.entityid, prd->c.vendor) != 0); - int32_t reason; + dds_qos_policy_id_t reason; DDSRT_UNUSED_ARG(tnow); if (isb0 != isb1) return; if (wr->e.onlylocal) return; - if (!isb0 && (reason = qos_match_p (prd->c.xqos, wr->xqos)) >= 0) + if (!isb0 && !topickind_qos_match_p_lock (&prd->e, prd->c.xqos, &wr->e, wr->xqos, &reason)) { - writer_qos_mismatch (wr, (uint32_t)reason); + writer_qos_mismatch (wr, reason); return; } proxy_reader_add_connection (prd, wr); @@ -2043,41 +2149,41 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r { const int isb0 = (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor) != 0); const int isb1 = (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); - int32_t reason; + dds_qos_policy_id_t reason; nn_count_t init_count; if (isb0 != isb1) return; if (rd->e.onlylocal) return; - if (!isb0 && (reason = qos_match_p (rd->xqos, pwr->c.xqos)) >= 0) + if (!isb0 && !topickind_qos_match_p_lock (&rd->e, rd->xqos, &pwr->e, pwr->c.xqos, &reason)) { - reader_qos_mismatch (rd, (uint32_t)reason); + reader_qos_mismatch (rd, reason); return; } reader_add_connection (rd, pwr, &init_count); proxy_writer_add_connection (pwr, rd, tnow, init_count); } -static bool ignore_local_p (const nn_guid_t *guid1, const nn_guid_t *guid2, const struct nn_xqos *xqos1, const struct nn_xqos *xqos2) +static bool ignore_local_p (const nn_guid_t *guid1, const nn_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2) { assert (xqos1->present & QP_CYCLONE_IGNORELOCAL); assert (xqos2->present & QP_CYCLONE_IGNORELOCAL); switch (xqos1->ignorelocal.value) { - case NN_NONE_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_NONE: break; - case NN_PARTICIPANT_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_PARTICIPANT: return memcmp (&guid1->prefix, &guid2->prefix, sizeof (guid1->prefix)) == 0; - case NN_PROCESS_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_PROCESS: return true; } switch (xqos2->ignorelocal.value) { - case NN_NONE_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_NONE: break; - case NN_PARTICIPANT_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_PARTICIPANT: return memcmp (&guid1->prefix, &guid2->prefix, sizeof (guid1->prefix)) == 0; - case NN_PROCESS_IGNORELOCAL_QOS: + case DDS_IGNORELOCAL_PROCESS: return true; } return false; @@ -2085,16 +2191,16 @@ static bool ignore_local_p (const nn_guid_t *guid1, const nn_guid_t *guid2, cons static void connect_writer_with_reader (struct writer *wr, struct reader *rd, nn_mtime_t tnow) { - int32_t reason; + dds_qos_policy_id_t reason; (void)tnow; if (!is_local_orphan_endpoint (&wr->e) && (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) || is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE))) return; if (ignore_local_p (&wr->e.guid, &rd->e.guid, wr->xqos, rd->xqos)) return; - if ((reason = qos_match_p (rd->xqos, wr->xqos)) >= 0) + if (!topickind_qos_match_p_lock (&rd->e, rd->xqos, &wr->e, wr->xqos, &reason)) { - writer_qos_mismatch (wr, (uint32_t)reason); - reader_qos_mismatch (rd, (uint32_t)reason); + writer_qos_mismatch (wr, reason); + reader_qos_mismatch (rd, reason); return; } reader_add_local_connection (rd, wr); @@ -2254,25 +2360,24 @@ static void generic_do_local_match_connect (struct entity_common *e, struct enti static void generic_do_match (struct entity_common *e, nn_mtime_t tnow) { + struct ephash * const guid_hash = e->gv->guid_hash; struct ephash_enum est; struct entity_common *em; enum entity_kind mkind = generic_do_match_mkind(e->kind); if (!is_builtin_entityid (e->guid.entityid, NN_VENDORID_ECLIPSE)) { - DDS_LOG(DDS_LC_DISCOVERY, "match_%s_with_%ss(%s "PGUIDFMT") scanning all %ss\n", - generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), - generic_do_match_kindabbrev (e->kind), PGUID (e->guid), - generic_do_match_kindstr(mkind)); + EELOGDISC (e, "match_%s_with_%ss(%s "PGUIDFMT") scanning all %ss\n", + generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), + generic_do_match_kindabbrev (e->kind), PGUID (e->guid), + generic_do_match_kindstr(mkind)); /* Note: we visit at least all proxies that existed when we called init (with the -- possible -- exception of ones that were deleted between our calling init and our reaching it while enumerating), but we may visit a single proxy reader multiple times. */ - ephash_enum_init (&est, mkind); - ddsrt_rwlock_read (&gv.qoslock); + ephash_enum_init (&est, guid_hash, mkind); while ((em = ephash_enum_next (&est)) != NULL) generic_do_match_connect(e, em, tnow); - ddsrt_rwlock_unlock (&gv.qoslock); ephash_enum_fini (&est); } else @@ -2280,21 +2385,21 @@ static void generic_do_match (struct entity_common *e, nn_mtime_t tnow) /* Built-ins have fixed QoS */ nn_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid); enum entity_kind pkind = generic_do_match_isproxy (e) ? EK_PARTICIPANT : EK_PROXY_PARTICIPANT; - DDS_LOG(DDS_LC_DISCOVERY, "match_%s_with_%ss(%s "PGUIDFMT") scanning %sparticipants tgt=%"PRIx32"\n", - generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), - generic_do_match_kindabbrev (e->kind), PGUID (e->guid), - generic_do_match_isproxy (e) ? "" : "proxy ", - tgt_ent.u); + EELOGDISC (e, "match_%s_with_%ss(%s "PGUIDFMT") scanning %sparticipants tgt=%"PRIx32"\n", + generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), + generic_do_match_kindabbrev (e->kind), PGUID (e->guid), + generic_do_match_isproxy (e) ? "" : "proxy ", + tgt_ent.u); if (tgt_ent.u != NN_ENTITYID_UNKNOWN) { struct entity_common *ep; - ephash_enum_init (&est, pkind); + ephash_enum_init (&est, guid_hash, pkind); while ((ep = ephash_enum_next (&est)) != NULL) { nn_guid_t tgt_guid; tgt_guid.prefix = ep->guid.prefix; tgt_guid.entityid = tgt_ent; - if ((em = ephash_lookup_guid (&tgt_guid, mkind)) != NULL) + if ((em = ephash_lookup_guid (guid_hash, &tgt_guid, mkind)) != NULL) generic_do_match_connect(e, em, tnow); } ephash_enum_fini (&est); @@ -2310,21 +2415,19 @@ static void generic_do_local_match (struct entity_common *e, nn_mtime_t tnow) if (is_builtin_entityid (e->guid.entityid, NN_VENDORID_ECLIPSE) && !is_local_orphan_endpoint (e)) /* never a need for local matches on discovery endpoints */ return; - mkind = generic_do_local_match_mkind(e->kind); - DDS_LOG(DDS_LC_DISCOVERY, "match_%s_with_%ss(%s "PGUIDFMT") scanning all %ss\n", - generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), - generic_do_match_kindabbrev (e->kind), PGUID (e->guid), - generic_do_match_kindstr(mkind)); + mkind = generic_do_local_match_mkind (e->kind); + EELOGDISC (e, "match_%s_with_%ss(%s "PGUIDFMT") scanning all %ss\n", + generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind), + generic_do_match_kindabbrev (e->kind), PGUID (e->guid), + generic_do_match_kindstr(mkind)); /* Note: we visit at least all proxies that existed when we called init (with the -- possible -- exception of ones that were deleted between our calling init and our reaching it while enumerating), but we may visit a single proxy reader multiple times. */ - ephash_enum_init (&est, mkind); - ddsrt_rwlock_read (&gv.qoslock); + ephash_enum_init (&est, e->gv->guid_hash, mkind); while ((em = ephash_enum_next (&est)) != NULL) - generic_do_local_match_connect(e, em, tnow); - ddsrt_rwlock_unlock (&gv.qoslock); + generic_do_local_match_connect (e, em, tnow); ephash_enum_fini (&est); } @@ -2360,7 +2463,7 @@ static void match_proxy_reader_with_writers (struct proxy_reader *prd, nn_mtime_ /* ENDPOINT --------------------------------------------------------- */ -static void new_reader_writer_common (const struct nn_guid *guid, const struct ddsi_sertopic * topic, const struct nn_xqos *xqos) +static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct nn_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos) { const char *partition = "(default)"; const char *partition_suffix = ""; @@ -2378,17 +2481,17 @@ static void new_reader_writer_common (const struct nn_guid *guid, const struct d if (xqos->partition.n > 1) partition_suffix = "+"; } - DDS_LOG(DDS_LC_DISCOVERY, "new_%s(guid "PGUIDFMT", %s%s.%s/%s)\n", - is_writer_entityid (guid->entityid) ? "writer" : "reader", - PGUID (*guid), - partition, partition_suffix, - topic ? topic->name : "(null)", - topic ? topic->type_name : "(null)"); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "new_%s(guid "PGUIDFMT", %s%s.%s/%s)\n", + is_writer_entityid (guid->entityid) ? "writer" : "reader", + PGUID (*guid), + partition, partition_suffix, + topic ? topic->name : "(null)", + topic ? topic->type_name : "(null)"); } -static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, enum entity_kind kind, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp) +static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, bool onlylocal) { - entity_common_init (e, guid, NULL, kind, now (), NN_VENDORID_ECLIPSE, pp->e.onlylocal); + entity_common_init (e, gv, guid, NULL, kind, now (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal); c->pp = ref_participant (pp, &e->guid); if (group_guid) c->group_guid = *group_guid; @@ -2410,7 +2513,7 @@ static void endpoint_common_fini (struct entity_common *e, struct endpoint_commo entity_common_fini (e); } -static int set_topic_type_name (nn_xqos_t *xqos, const struct ddsi_sertopic * topic) +static int set_topic_type_name (dds_qos_t *xqos, const struct ddsi_sertopic * topic) { if (!(xqos->present & QP_TYPE_NAME) && topic) { @@ -2428,14 +2531,14 @@ static int set_topic_type_name (nn_xqos_t *xqos, const struct ddsi_sertopic * to /* WRITER ----------------------------------------------------------- */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -static uint32_t get_partitionid_from_mapping (const char *partition, const char *topic) +static uint32_t get_partitionid_from_mapping (const struct ddsrt_log_cfg *logcfg, const struct config *config, const char *partition, const char *topic) { struct config_partitionmapping_listelem *pm; - if ((pm = find_partitionmapping (partition, topic)) == NULL) + if ((pm = find_partitionmapping (config, partition, topic)) == NULL) return 0; else { - DDS_LOG(DDS_LC_DISCOVERY, "matched writer for topic \"%s\" in partition \"%s\" to networkPartition \"%s\"\n", topic, partition, pm->networkPartition); + DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "matched writer for topic \"%s\" in partition \"%s\" to networkPartition \"%s\"\n", topic, partition, pm->networkPartition); return pm->partition->partitionId; } } @@ -2579,7 +2682,7 @@ void writer_set_retransmitting (struct writer *wr) { assert (!wr->retransmitting); wr->retransmitting = 1; - if (config.whc_adaptive && wr->whc_high > wr->whc_low) + if (wr->e.gv->config.whc_adaptive && wr->whc_high > wr->whc_low) { uint32_t m = 8 * wr->whc_high / 10; wr->whc_high = (m > wr->whc_low) ? m : wr->whc_low; @@ -2607,13 +2710,13 @@ unsigned remove_acked_messages (struct writer *wr, struct whc_state *whcst, stru writer_clear_retransmitting (wr); if (wr->state == WRST_LINGERING && whcst->unacked_bytes == 0) { - DDS_LOG(DDS_LC_DISCOVERY, "remove_acked_messages: deleting lingering writer "PGUIDFMT"\n", PGUID (wr->e.guid)); + ELOGDISC (wr, "remove_acked_messages: deleting lingering writer "PGUIDFMT"\n", PGUID (wr->e.guid)); delete_writer_nolinger_locked (wr); } return n; } -static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc *whc, status_cb_t status_cb, void * status_entity) +static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void * status_entity) { ddsrt_cond_init (&wr->throttle_cond); wr->seq = 0; @@ -2642,41 +2745,38 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->xqos = ddsrt_malloc (sizeof (*wr->xqos)); nn_xqos_copy (wr->xqos, xqos); - nn_xqos_mergein_missing (wr->xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (wr->xqos, &wr->e.gv->default_xqos_wr, ~(uint64_t)0); assert (wr->xqos->aliased == 0); set_topic_type_name (wr->xqos, topic); - DDS_LOG(DDS_LC_DISCOVERY, "WRITER "PGUIDFMT" QOS={", PGUID (wr->e.guid)); - nn_log_xqos (DDS_LC_DISCOVERY, wr->xqos); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + ELOGDISC (wr, "WRITER "PGUIDFMT" QOS={", PGUID (wr->e.guid)); + nn_log_xqos (DDS_LC_DISCOVERY, &wr->e.gv->logconfig, wr->xqos); + ELOGDISC (wr, "}\n"); assert (wr->xqos->present & QP_RELIABILITY); - wr->reliable = (wr->xqos->reliability.kind != NN_BEST_EFFORT_RELIABILITY_QOS); + wr->reliable = (wr->xqos->reliability.kind != DDS_RELIABILITY_BEST_EFFORT); assert (wr->xqos->present & QP_DURABILITY); if (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) { - assert (wr->xqos->history.kind == NN_KEEP_LAST_HISTORY_QOS); - assert (wr->xqos->durability.kind == NN_TRANSIENT_LOCAL_DURABILITY_QOS); + assert (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST); + assert (wr->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); } - wr->handle_as_transient_local = (wr->xqos->durability.kind == NN_TRANSIENT_LOCAL_DURABILITY_QOS); + wr->handle_as_transient_local = (wr->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); wr->include_keyhash = - config.generate_keyhash && + wr->e.gv->config.generate_keyhash && ((wr->e.guid.entityid.u & NN_ENTITYID_KIND_MASK) == NN_ENTITYID_KIND_WRITER_WITH_KEY); wr->topic = ddsi_sertopic_ref (topic); wr->as = new_addrset (); wr->as_group = NULL; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS - { - unsigned i; - /* This is an open issue how to encrypt mesages send for various - partitions that match multiple network partitions. From a safety - point of view a wierd configuration. Here we chose the first one - that we find */ - wr->partition_id = 0; - for (i = 0; i < wr->xqos->partition.n && wr->partition_id == 0; i++) - wr->partition_id = get_partitionid_from_mapping (wr->xqos->partition.strs[i], wr->xqos->topic_name); - } + /* This is an open issue how to encrypt mesages send for various + partitions that match multiple network partitions. From a safety + point of view a wierd configuration. Here we chose the first one + that we find */ + wr->partition_id = 0; + for (uint32_t i = 0; i < wr->xqos->partition.n && wr->partition_id == 0; i++) + wr->partition_id = get_partitionid_from_mapping (&wr->e.gv->logconfig, &wr->e.gv->config, wr->xqos->partition.strs[i], wr->xqos->topic_name); #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ #ifdef DDSI_INCLUDE_SSM @@ -2686,33 +2786,33 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se to advertise. */ wr->supports_ssm = 0; wr->ssm_as = NULL; - if (config.allowMulticast & AMC_SSM) + if (wr->e.gv->config.allowMulticast & AMC_SSM) { nn_locator_t loc; int have_loc = 0; if (wr->partition_id == 0) { - if (ddsi_is_ssm_mcaddr (&gv.loc_default_mc)) + if (ddsi_is_ssm_mcaddr (wr->e.gv, &wr->e.gv->loc_default_mc)) { - loc = gv.loc_default_mc; + loc = wr->e.gv->loc_default_mc; have_loc = 1; } } else { - const struct config_networkpartition_listelem *np = find_networkpartition_by_id (wr->partition_id); + const struct config_networkpartition_listelem *np = find_networkpartition_by_id (&wr->e.gv->config, wr->partition_id); assert (np); - if (addrset_any_ssm (np->as, &loc)) + if (addrset_any_ssm (wr->e.gv, np->as, &loc)) have_loc = 1; } if (have_loc) { wr->supports_ssm = 1; wr->ssm_as = new_addrset (); - add_to_addrset (wr->ssm_as, &loc); - DDS_LOG(DDS_LC_DISCOVERY, "writer "PGUIDFMT": ssm=%d", PGUID (wr->e.guid), wr->supports_ssm); - nn_log_addrset (DDS_LC_DISCOVERY, "", wr->ssm_as); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); + add_to_addrset (wr->e.gv, wr->ssm_as, &loc); + ELOGDISC (wr, "writer "PGUIDFMT": ssm=%d", PGUID (wr->e.guid), wr->supports_ssm); + nn_log_addrset (wr->e.gv, DDS_LC_DISCOVERY, "", wr->ssm_as); + ELOGDISC (wr, "\n"); } } #endif @@ -2722,15 +2822,15 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se #ifdef DDSI_INCLUDE_NETWORK_CHANNELS if (!is_builtin_entityid (wr->e.guid.entityid, ownvendorid)) { - struct config_channel_listelem *channel = find_channel (wr->xqos->transport_priority); - DDS_LOG(DDS_LC_DISCOVERY, "writer "PGUIDFMT": transport priority %d => channel '%s' priority %d\n", - PGUID (wr->e.guid), wr->xqos->transport_priority.value, channel->name, channel->priority); - wr->evq = channel->evq ? channel->evq : gv.xevents; + struct config_channel_listelem *channel = find_channel (&wr->e.gv->config, wr->xqos->transport_priority); + ELOGDISC (wr, "writer "PGUIDFMT": transport priority %d => channel '%s' priority %d\n", + PGUID (wr->e.guid), wr->xqos->transport_priority.value, channel->name, channel->priority); + wr->evq = channel->evq ? channel->evq : wr->e.gv->xevents; } else #endif { - wr->evq = gv.xevents; + wr->evq = wr->e.gv->xevents; } /* heartbeat event will be deleted when the handler can't find a @@ -2748,15 +2848,15 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->heartbeat_xevent = NULL; } assert (wr->xqos->present & QP_LIVELINESS); - if (wr->xqos->liveliness.kind != NN_AUTOMATIC_LIVELINESS_QOS || - nn_from_ddsi_duration (wr->xqos->liveliness.lease_duration) != T_NEVER) + if (wr->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || wr->xqos->liveliness.lease_duration != T_NEVER) { - DDS_LOG(DDS_LC_DISCOVERY, "writer "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n", PGUID (wr->e.guid), (int) wr->xqos->liveliness.kind, nn_from_ddsi_duration (wr->xqos->liveliness.lease_duration)); + ELOGDISC (wr, "writer "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n", + PGUID (wr->e.guid), (int) wr->xqos->liveliness.kind, wr->xqos->liveliness.lease_duration); } wr->lease_duration = T_NEVER; /* FIXME */ wr->whc = whc; - if (wr->xqos->history.kind == NN_KEEP_LAST_HISTORY_QOS) + if (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST) { /* hdepth > 0 => "aggressive keep last", and in that case: why bother blocking for a slow receiver when the entire point of @@ -2766,8 +2866,8 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se } else { - wr->whc_low = config.whc_lowwater_mark; - wr->whc_high = config.whc_init_highwater_mark.value; + wr->whc_low = wr->e.gv->config.whc_lowwater_mark; + wr->whc_high = wr->e.gv->config.whc_init_highwater_mark.value; } assert (!is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE) || (wr->whc_low == wr->whc_high && wr->whc_low == INT32_MAX)); @@ -2778,16 +2878,16 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se local_reader_ary_init (&wr->rdary); } -static dds_retcode_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity) +static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity) { struct writer *wr; nn_mtime_t tnow = now_mt (); assert (is_writer_entityid (guid->entityid)); - assert (ephash_lookup_writer_guid (guid) == NULL); + assert (ephash_lookup_writer_guid (pp->e.gv->guid_hash, guid) == NULL); assert (memcmp (&guid->prefix, &pp->e.guid.prefix, sizeof (guid->prefix)) == 0); - new_reader_writer_common (guid, topic, xqos); + new_reader_writer_common (&pp->e.gv->logconfig, guid, topic, xqos); wr = ddsrt_malloc (sizeof (*wr)); if (wr_out) *wr_out = wr; @@ -2796,7 +2896,8 @@ static dds_retcode_t new_writer_guid (struct writer **wr_out, const struct nn_gu delete_participant won't interfere with our ability to address the participant */ - endpoint_common_init (&wr->e, &wr->c, EK_WRITER, guid, group_guid, pp); + const bool onlylocal = topic && builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); + endpoint_common_init (&wr->e, &wr->c, pp->e.gv, EK_WRITER, guid, group_guid, pp, onlylocal); new_writer_guid_common_init(wr, topic, xqos, whc, status_cb, status_entity); /* guid_hash needed for protocol handling, so add it before we send @@ -2805,8 +2906,8 @@ static dds_retcode_t new_writer_guid (struct writer **wr_out, const struct nn_gu neither of two endpoints being created in parallel can discover the other. */ ddsrt_mutex_lock (&wr->e.lock); - ephash_insert_writer_guid (wr); - ddsi_plugin.builtintopic_write (&wr->e, now(), true); + ephash_insert_writer_guid (pp->e.gv->guid_hash, wr); + builtintopic_write (wr->e.gv->builtin_topic_interface, &wr->e, now(), true); ddsrt_mutex_unlock (&wr->e.lock); /* once it exists, match it with proxy writers and broadcast @@ -2825,54 +2926,66 @@ static dds_retcode_t new_writer_guid (struct writer **wr_out, const struct nn_gu resched_xevent_if_earlier (pp->pmd_update_xevent, tsched); } - return DDS_RETCODE_OK; + return 0; } -dds_retcode_t new_writer (struct writer **wr_out, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) +dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) { struct participant *pp; + dds_return_t rc; + uint32_t kind; - if ((pp = ephash_lookup_participant_guid (ppguid)) == NULL) + if ((pp = ephash_lookup_participant_guid (gv->guid_hash, ppguid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_NOT_FOUND; + GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); + return DDS_RETCODE_BAD_PARAMETER; } + /* participant can't be freed while we're mucking around cos we are awake and do not touch the thread's vtime (ephash_lookup already verifies we're awake) */ wrguid->prefix = pp->e.guid.prefix; - if (pp_allocate_entityid (&wrguid->entityid, NN_ENTITYID_KIND_WRITER_WITH_KEY, pp) < 0) - return DDS_RETCODE_OUT_OF_RESOURCES; + kind = topic->topickind_no_key ? NN_ENTITYID_KIND_WRITER_NO_KEY : NN_ENTITYID_KIND_WRITER_WITH_KEY; + if ((rc = pp_allocate_entityid (&wrguid->entityid, kind, pp)) < 0) + return rc; return new_writer_guid (wr_out, wrguid, group_guid, pp, topic, xqos, whc, status_cb, status_cb_arg); } -struct local_orphan_writer *new_local_orphan_writer (nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct nn_xqos *xqos, struct whc *whc) +struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc) { nn_guid_t guid; struct local_orphan_writer *lowr; struct writer *wr; nn_mtime_t tnow = now_mt (); - DDS_LOG(DDS_LC_DISCOVERY, "new_local_orphan_writer(%s/%s)\n", topic->name, topic->type_name); + GVLOGDISC ("new_local_orphan_writer(%s/%s)\n", topic->name, topic->type_name); lowr = ddsrt_malloc (sizeof (*lowr)); wr = &lowr->wr; memset (&guid.prefix, 0, sizeof (guid.prefix)); guid.entityid = entityid; - entity_common_init (&wr->e, &guid, NULL, EK_WRITER, now (), NN_VENDORID_ECLIPSE, true); + entity_common_init (&wr->e, gv, &guid, NULL, EK_WRITER, now (), NN_VENDORID_ECLIPSE, true); wr->c.pp = NULL; memset (&wr->c.group_guid, 0, sizeof (wr->c.group_guid)); new_writer_guid_common_init (wr, topic, xqos, whc, 0, NULL); - ephash_insert_writer_guid (wr); - ddsi_plugin.builtintopic_write (&wr->e, now(), true); + ephash_insert_writer_guid (gv->guid_hash, wr); + builtintopic_write (gv->builtin_topic_interface, &wr->e, now(), true); match_writer_with_local_readers (wr, tnow); return lowr; } +void update_writer_qos (struct writer *wr, const dds_qos_t *xqos) +{ + ddsrt_mutex_lock (&wr->e.lock); + if (update_qos_locked (&wr->e, wr->xqos, xqos, now ())) + sedp_write_writer (wr); + ddsrt_mutex_unlock (&wr->e.lock); +} + static void gc_delete_writer (struct gcreq *gcreq) { struct writer *wr = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (wr->e.guid)); + ELOGDISC (wr, "gc_delete_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (wr->e.guid)); gcreq_free (gcreq); /* We now allow GC while blocked on a full WHC, but we still don't allow deleting a writer while blocked on it. The writer's state must be DELETING by the time we get here, and that means the transmit path is no longer blocked. It doesn't imply that the write thread is no longer in throttle_writer(), just that if it is, it will soon return from there. Therefore, block until it isn't throttling anymore. We can safely lock the writer, as we're on the separate GC thread. */ @@ -2931,7 +3044,7 @@ static void gc_delete_writer (struct gcreq *gcreq) static void gc_delete_writer_throttlewait (struct gcreq *gcreq) { struct writer *wr = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_writer_throttlewait(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (wr->e.guid)); + ELOGDISC (wr, "gc_delete_writer_throttlewait(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (wr->e.guid)); /* We now allow GC while blocked on a full WHC, but we still don't allow deleting a writer while blocked on it. The writer's state must be DELETING by the time we get here, and that means the transmit path is no longer blocked. It doesn't imply that the write thread is no longer in throttle_writer(), just that if it is, it will soon return from there. Therefore, block until it isn't throttling anymore. We can safely lock the writer, as we're on the separate GC thread. */ assert (wr->state == WRST_DELETING); ddsrt_mutex_lock (&wr->e.lock); @@ -2944,7 +3057,7 @@ static void gc_delete_writer_throttlewait (struct gcreq *gcreq) static void writer_set_state (struct writer *wr, enum writer_state newstate) { ASSERT_MUTEX_HELD (&wr->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "writer_set_state("PGUIDFMT") state transition %d -> %d\n", PGUID (wr->e.guid), wr->state, newstate); + ELOGDISC (wr, "writer_set_state("PGUIDFMT") state transition %d -> %d\n", PGUID (wr->e.guid), wr->state, newstate); assert (newstate > wr->state); if (wr->state == WRST_OPERATIONAL) { @@ -2959,19 +3072,19 @@ static void writer_set_state (struct writer *wr, enum writer_state newstate) wr->state = newstate; } -int delete_writer_nolinger_locked (struct writer *wr) +dds_return_t delete_writer_nolinger_locked (struct writer *wr) { - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid)); + ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid)); ASSERT_MUTEX_HELD (&wr->e.lock); - ddsi_plugin.builtintopic_write (&wr->e, now(), false); + builtintopic_write (wr->e.gv->builtin_topic_interface, &wr->e, now(), false); local_reader_ary_setinvalid (&wr->rdary); - ephash_remove_writer_guid (wr); + ephash_remove_writer_guid (wr->e.gv->guid_hash, wr); writer_set_state (wr, WRST_DELETING); gcreq_writer (wr); return 0; } -int delete_writer_nolinger (const struct nn_guid *guid) +dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid) { struct writer *wr; /* We take no care to ensure application writers are not deleted @@ -2981,12 +3094,12 @@ int delete_writer_nolinger (const struct nn_guid *guid) DDSI participants. But it would be somewhat more elegant to do it differently. */ assert (is_writer_entityid (guid->entityid)); - if ((wr = ephash_lookup_writer_guid (guid)) == NULL) + if ((wr = ephash_lookup_writer_guid (gv->guid_hash, guid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer_nolinger(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); - return Q_ERR_UNKNOWN_ENTITY; + GVLOGDISC ("delete_writer_nolinger(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); + return DDS_RETCODE_BAD_PARAMETER; } - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (*guid)); + GVLOGDISC ("delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (*guid)); ddsrt_mutex_lock (&wr->e.lock); delete_writer_nolinger_locked (wr); ddsrt_mutex_unlock (&wr->e.lock); @@ -3000,16 +3113,16 @@ void delete_local_orphan_writer (struct local_orphan_writer *lowr) ddsrt_mutex_unlock (&lowr->wr.e.lock); } -int delete_writer (const struct nn_guid *guid) +dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid) { struct writer *wr; struct whc_state whcst; - if ((wr = ephash_lookup_writer_guid (guid)) == NULL) + if ((wr = ephash_lookup_writer_guid (gv->guid_hash, guid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); - return Q_ERR_UNKNOWN_ENTITY; + GVLOGDISC ("delete_writer(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); + return DDS_RETCODE_BAD_PARAMETER; } - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer(guid "PGUIDFMT") ...\n", PGUID (*guid)); + GVLOGDISC ("delete_writer(guid "PGUIDFMT") ...\n", PGUID (*guid)); ddsrt_mutex_lock (&wr->e.lock); /* If no unack'ed data, don't waste time or resources (expected to @@ -3019,7 +3132,7 @@ int delete_writer (const struct nn_guid *guid) whc_get_state(wr->whc, &whcst); if (whcst.unacked_bytes == 0) { - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer(guid "PGUIDFMT") - no unack'ed samples\n", PGUID (*guid)); + GVLOGDISC ("delete_writer(guid "PGUIDFMT") - no unack'ed samples\n", PGUID (*guid)); delete_writer_nolinger_locked (wr); ddsrt_mutex_unlock (&wr->e.lock); } @@ -3029,55 +3142,48 @@ int delete_writer (const struct nn_guid *guid) int32_t tsec, tusec; writer_set_state (wr, WRST_LINGERING); ddsrt_mutex_unlock (&wr->e.lock); - tsched = add_duration_to_mtime (now_mt (), config.writer_linger_duration); + tsched = add_duration_to_mtime (now_mt (), wr->e.gv->config.writer_linger_duration); mtime_to_sec_usec (&tsec, &tusec, tsched); - DDS_LOG(DDS_LC_DISCOVERY, "delete_writer(guid "PGUIDFMT") - unack'ed samples, will delete when ack'd or at t = %"PRId32".%06"PRId32"\n", - PGUID (*guid), tsec, tusec); - qxev_delete_writer (tsched, &wr->e.guid); + GVLOGDISC ("delete_writer(guid "PGUIDFMT") - unack'ed samples, will delete when ack'd or at t = %"PRId32".%06"PRId32"\n", + PGUID (*guid), tsec, tusec); + qxev_delete_writer (gv->xevents, tsched, &wr->e.guid); } return 0; } -uint64_t writer_instance_id (const struct nn_guid *guid) -{ - struct entity_common *e; - e = (struct entity_common*)ephash_lookup_writer_guid(guid); - if (e) { - return e->iid; - } - e = (struct entity_common*)ephash_lookup_proxy_writer_guid(guid); - if (e) { - return e->iid; - } - return 0; -} - /* READER ----------------------------------------------------------- */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -static struct addrset * get_as_from_mapping (const char *partition, const char *topic) +static struct addrset *get_as_from_mapping (const struct q_globals *gv, const char *partition, const char *topic) { struct config_partitionmapping_listelem *pm; struct addrset *as = new_addrset (); - if ((pm = find_partitionmapping (partition, topic)) != NULL) + if ((pm = find_partitionmapping (&gv->config, partition, topic)) != NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "matched reader for topic \"%s\" in partition \"%s\" to networkPartition \"%s\"\n", topic, partition, pm->networkPartition); + GVLOGDISC ("matched reader for topic \"%s\" in partition \"%s\" to networkPartition \"%s\"\n", + topic, partition, pm->networkPartition); assert (pm->partition->as); - copy_addrset_into_addrset (as, pm->partition->as); + copy_addrset_into_addrset (gv, as, pm->partition->as); } return as; } -static void join_mcast_helper (const nn_locator_t *n, void * varg) +struct join_leave_mcast_helper_arg { + ddsi_tran_conn_t conn; + struct q_globals *gv; +}; + +static void join_mcast_helper (const nn_locator_t *n, void *varg) { - ddsi_tran_conn_t conn = (ddsi_tran_conn_t) varg; - if (ddsi_is_mcaddr (n)) + struct join_leave_mcast_helper_arg *arg = varg; + struct q_globals *gv = arg->gv; + if (ddsi_is_mcaddr (gv, n)) { if (n->kind != NN_LOCATOR_KIND_UDPv4MCGEN) { - if (ddsi_join_mc (conn, NULL, n) < 0) + if (ddsi_join_mc (gv, arg->gv->mship, arg->conn, NULL, n) < 0) { - DDS_LOG(DDS_LC_WARNING, "failed to join network partition multicast group\n"); + GVWARNING ("failed to join network partition multicast group\n"); } } else /* join all addresses that include this node */ @@ -3086,12 +3192,11 @@ static void join_mcast_helper (const nn_locator_t *n, void * varg) nn_locator_t l = *n; nn_udpv4mcgen_address_t l1; uint32_t iph; - unsigned i; memcpy(&l1, l.address, sizeof(l1)); l.kind = NN_LOCATOR_KIND_UDPv4; memset(l.address, 0, 12); iph = ntohl(l1.ipv4.s_addr); - for (i = 1; i < (1u << l1.count); i++) + for (uint32_t i = 1; i < ((uint32_t)1 << l1.count); i++) { uint32_t ipn, iph1 = iph; if (i & (1u << l1.idx)) @@ -3099,9 +3204,9 @@ static void join_mcast_helper (const nn_locator_t *n, void * varg) iph1 |= (i << l1.base); ipn = htonl(iph1); memcpy(l.address + 12, &ipn, 4); - if (ddsi_join_mc (conn, NULL, &l) < 0) + if (ddsi_join_mc (gv, gv->mship, arg->conn, NULL, &l) < 0) { - DDS_LOG(DDS_LC_WARNING, "failed to join network partition multicast group\n"); + GVWARNING ("failed to join network partition multicast group\n"); } } } @@ -3110,16 +3215,17 @@ static void join_mcast_helper (const nn_locator_t *n, void * varg) } } -static void leave_mcast_helper (const nn_locator_t *n, void * varg) +static void leave_mcast_helper (const nn_locator_t *n, void *varg) { - ddsi_tran_conn_t conn = (ddsi_tran_conn_t) varg; - if (ddsi_is_mcaddr (n)) + struct join_leave_mcast_helper_arg *arg = varg; + struct q_globals *gv = arg->gv; + if (ddsi_is_mcaddr (gv, n)) { if (n->kind != NN_LOCATOR_KIND_UDPv4MCGEN) { - if (ddsi_leave_mc (conn, NULL, n) < 0) + if (ddsi_leave_mc (gv, gv->mship, arg->conn, NULL, n) < 0) { - DDS_LOG(DDS_LC_WARNING, "failed to leave network partition multicast group\n"); + GVWARNING ("failed to leave network partition multicast group\n"); } } else /* join all addresses that include this node */ @@ -3128,12 +3234,11 @@ static void leave_mcast_helper (const nn_locator_t *n, void * varg) nn_locator_t l = *n; nn_udpv4mcgen_address_t l1; uint32_t iph; - unsigned i; memcpy(&l1, l.address, sizeof(l1)); l.kind = NN_LOCATOR_KIND_UDPv4; memset(l.address, 0, 12); iph = ntohl(l1.ipv4.s_addr); - for (i = 1; i < (1u << l1.count); i++) + for (uint32_t i = 1; i < ((uint32_t)1 << l1.count); i++) { uint32_t ipn, iph1 = iph; if (i & (1u << l1.idx)) @@ -3141,9 +3246,9 @@ static void leave_mcast_helper (const nn_locator_t *n, void * varg) iph1 |= (i << l1.base); ipn = htonl(iph1); memcpy(l.address + 12, &ipn, 4); - if (ddsi_leave_mc (conn, NULL, &l) < 0) + if (ddsi_leave_mc (gv, arg->gv->mship, arg->conn, NULL, &l) < 0) { - DDS_LOG(DDS_LC_WARNING, "failed to leave network partition multicast group\n"); + GVWARNING ("failed to leave network partition multicast group\n"); } } } @@ -3153,14 +3258,14 @@ static void leave_mcast_helper (const nn_locator_t *n, void * varg) } #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ -static dds_retcode_t new_reader_guid +static dds_return_t new_reader_guid ( struct reader **rd_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, - const struct nn_xqos *xqos, + const struct dds_qos *xqos, struct rhc *rhc, status_cb_t status_cb, void * status_entity @@ -3168,37 +3273,38 @@ static dds_retcode_t new_reader_guid { /* see new_writer_guid for commenets */ - struct reader * rd; + struct reader *rd; nn_mtime_t tnow = now_mt (); assert (!is_writer_entityid (guid->entityid)); - assert (ephash_lookup_reader_guid (guid) == NULL); + assert (ephash_lookup_reader_guid (pp->e.gv->guid_hash, guid) == NULL); assert (memcmp (&guid->prefix, &pp->e.guid.prefix, sizeof (guid->prefix)) == 0); - new_reader_writer_common (guid, topic, xqos); + new_reader_writer_common (&pp->e.gv->logconfig, guid, topic, xqos); rd = ddsrt_malloc (sizeof (*rd)); if (rd_out) *rd_out = rd; - endpoint_common_init (&rd->e, &rd->c, EK_READER, guid, group_guid, pp); + const bool onlylocal = topic && builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); + endpoint_common_init (&rd->e, &rd->c, pp->e.gv, EK_READER, guid, group_guid, pp, onlylocal); /* Copy QoS, merging in defaults */ rd->xqos = ddsrt_malloc (sizeof (*rd->xqos)); nn_xqos_copy (rd->xqos, xqos); - nn_xqos_mergein_missing (rd->xqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (rd->xqos, &pp->e.gv->default_xqos_rd, ~(uint64_t)0); assert (rd->xqos->aliased == 0); set_topic_type_name (rd->xqos, topic); - if (dds_get_log_mask() & DDS_LC_DISCOVERY) + if (rd->e.gv->logconfig.c.mask & DDS_LC_DISCOVERY) { - DDS_LOG(DDS_LC_DISCOVERY, "READER "PGUIDFMT" QOS={", PGUID (rd->e.guid)); - nn_log_xqos (DDS_LC_DISCOVERY, rd->xqos); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + ELOGDISC (rd, "READER "PGUIDFMT" QOS={", PGUID (rd->e.guid)); + nn_log_xqos (DDS_LC_DISCOVERY, &rd->e.gv->logconfig, rd->xqos); + ELOGDISC (rd, "}\n"); } assert (rd->xqos->present & QP_RELIABILITY); - rd->reliable = (rd->xqos->reliability.kind != NN_BEST_EFFORT_RELIABILITY_QOS); + rd->reliable = (rd->xqos->reliability.kind != DDS_RELIABILITY_BEST_EFFORT); assert (rd->xqos->present & QP_DURABILITY); - rd->handle_as_transient_local = (rd->xqos->durability.kind == NN_TRANSIENT_LOCAL_DURABILITY_QOS); + rd->handle_as_transient_local = (rd->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); rd->topic = ddsi_sertopic_ref (topic); rd->ddsi2direct_cb = 0; rd->ddsi2direct_cbarg = 0; @@ -3216,33 +3322,31 @@ static dds_retcode_t new_reader_guid /* set rhc qos for reader */ if (rhc) { - (ddsi_plugin.rhc_plugin.rhc_set_qos_fn) (rd->rhc, rd->xqos); + rhc_set_qos (rd->rhc, rd->xqos); } assert (rd->xqos->present & QP_LIVELINESS); - if (rd->xqos->liveliness.kind != NN_AUTOMATIC_LIVELINESS_QOS || - nn_from_ddsi_duration (rd->xqos->liveliness.lease_duration) != T_NEVER) + if (rd->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || rd->xqos->liveliness.lease_duration != T_NEVER) { - DDS_LOG(DDS_LC_DISCOVERY, "reader "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n", PGUID (rd->e.guid), (int) rd->xqos->liveliness.kind, nn_from_ddsi_duration (rd->xqos->liveliness.lease_duration)); + ELOGDISC (rd, "reader "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n", + PGUID (rd->e.guid), (int) rd->xqos->liveliness.kind, rd->xqos->liveliness.lease_duration); } #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS rd->as = new_addrset (); - if (config.allowMulticast & ~AMC_SPDP) + if (pp->e.gv->config.allowMulticast & ~AMC_SPDP) { - unsigned i; - /* compile address set from the mapped network partitions */ - for (i = 0; i < rd->xqos->partition.n; i++) + for (uint32_t i = 0; i < rd->xqos->partition.n; i++) { - struct addrset *pas = get_as_from_mapping (rd->xqos->partition.strs[i], rd->xqos->topic_name); + struct addrset *pas = get_as_from_mapping (pp->e.gv, rd->xqos->partition.strs[i], rd->xqos->topic_name); if (pas) { #ifdef DDSI_INCLUDE_SSM - copy_addrset_into_addrset_no_ssm (rd->as, pas); - if (addrset_contains_ssm (pas) && config.allowMulticast & AMC_SSM) + copy_addrset_into_addrset_no_ssm (pp->e.gv, rd->as, pas); + if (addrset_contains_ssm (pp->e.gv, pas) && rd->e.gv->config.allowMulticast & AMC_SSM) rd->favours_ssm = 1; #else - copy_addrset_into_addrset (rd->as, pas); + copy_addrset_into_addrset (pp->e.gv, rd->as, pas); #endif unref_addrset (pas); } @@ -3253,12 +3357,15 @@ static dds_retcode_t new_reader_guid * - Set the correct portnumbers * - Join the socket if a multicast address */ - addrset_forall (rd->as, join_mcast_helper, gv.data_conn_mc); - if (dds_get_log_mask() & DDS_LC_DISCOVERY) + struct join_leave_mcast_helper_arg arg; + arg.conn = pp->e.gv->data_conn_mc; + arg.gv = pp->e.gv; + addrset_forall (rd->as, join_mcast_helper, &arg); + if (pp->e.gv->logconfig.c.mask & DDS_LC_DISCOVERY) { - DDS_LOG(DDS_LC_DISCOVERY, "READER "PGUIDFMT" locators={", PGUID (rd->e.guid)); - nn_log_addrset(DDS_LC_DISCOVERY, "", rd->as); - DDS_LOG(DDS_LC_DISCOVERY, "}\n"); + ELOGDISC (pp, "READER "PGUIDFMT" locators={", PGUID (rd->e.guid)); + nn_log_addrset(pp->e.gv, DDS_LC_DISCOVERY, "", rd->as); + ELOGDISC (pp, "}\n"); } } #ifdef DDSI_INCLUDE_SSM @@ -3267,14 +3374,14 @@ static dds_retcode_t new_reader_guid /* Note: SSM requires NETWORK_PARTITIONS; if network partitions do not override the default, we should check whether the default is an SSM address. */ - if (ddsi_is_ssm_mcaddr (&gv.loc_default_mc) && config.allowMulticast & AMC_SSM) + if (ddsi_is_ssm_mcaddr (pp->e.gv, &pp->e.gv->loc_default_mc) && pp->e.gv->config.allowMulticast & AMC_SSM) rd->favours_ssm = 1; } #endif } #ifdef DDSI_INCLUDE_SSM if (rd->favours_ssm) - DDS_LOG(DDS_LC_DISCOVERY, "READER "PGUIDFMT" ssm=%d\n", PGUID (rd->e.guid), rd->favours_ssm); + ELOGDISC (pp, "READER "PGUIDFMT" ssm=%d\n", PGUID (rd->e.guid), rd->favours_ssm); #endif #endif @@ -3282,39 +3389,43 @@ static dds_retcode_t new_reader_guid ddsrt_avl_init (&rd_local_writers_treedef, &rd->local_writers); ddsrt_mutex_lock (&rd->e.lock); - ephash_insert_reader_guid (rd); - ddsi_plugin.builtintopic_write (&rd->e, now(), true); + ephash_insert_reader_guid (pp->e.gv->guid_hash, rd); + builtintopic_write (pp->e.gv->builtin_topic_interface, &rd->e, now(), true); ddsrt_mutex_unlock (&rd->e.lock); match_reader_with_proxy_writers (rd, tnow); match_reader_with_local_writers (rd, tnow); sedp_write_reader (rd); - return DDS_RETCODE_OK; + return 0; } -dds_retcode_t new_reader +dds_return_t new_reader ( struct reader **rd_out, + struct q_globals *gv, struct nn_guid *rdguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, - const struct nn_xqos *xqos, + const struct dds_qos *xqos, struct rhc * rhc, status_cb_t status_cb, void * status_cbarg ) { struct participant * pp; + dds_return_t rc; + uint32_t kind; - if ((pp = ephash_lookup_participant_guid (ppguid)) == NULL) + if ((pp = ephash_lookup_participant_guid (gv->guid_hash, ppguid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_NOT_FOUND; + GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); + return DDS_RETCODE_BAD_PARAMETER; } rdguid->prefix = pp->e.guid.prefix; - if (pp_allocate_entityid (&rdguid->entityid, NN_ENTITYID_KIND_READER_WITH_KEY, pp) < 0) - return DDS_RETCODE_OUT_OF_RESOURCES; + kind = topic->topickind_no_key ? NN_ENTITYID_KIND_READER_NO_KEY : NN_ENTITYID_KIND_READER_WITH_KEY; + if ((rc = pp_allocate_entityid (&rdguid->entityid, kind, pp)) < 0) + return rc; return new_reader_guid (rd_out, rdguid, group_guid, pp, topic, xqos, rhc, status_cb, status_cbarg); } @@ -3322,7 +3433,7 @@ static void gc_delete_reader (struct gcreq *gcreq) { /* see gc_delete_writer for comments */ struct reader *rd = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_reader(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (rd->e.guid)); + ELOGDISC (rd, "gc_delete_reader(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (rd->e.guid)); gcreq_free (gcreq); while (!ddsrt_avl_is_empty (&rd->writers)) @@ -3330,7 +3441,7 @@ static void gc_delete_reader (struct gcreq *gcreq) struct rd_pwr_match *m = ddsrt_avl_root_non_empty (&rd_writers_treedef, &rd->writers); ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m); proxy_writer_drop_connection (&m->pwr_guid, rd); - free_rd_pwr_match (m); + free_rd_pwr_match (rd->e.gv, m); } while (!ddsrt_avl_is_empty (&rd->local_writers)) { @@ -3343,11 +3454,16 @@ static void gc_delete_reader (struct gcreq *gcreq) if (!is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE)) sedp_dispose_unregister_reader (rd); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS - addrset_forall (rd->as, leave_mcast_helper, gv.data_conn_mc); + { + struct join_leave_mcast_helper_arg arg; + arg.conn = rd->e.gv->data_conn_mc; + arg.gv = rd->e.gv; + addrset_forall (rd->as, leave_mcast_helper, &arg); + } #endif if (rd->rhc) { - (ddsi_plugin.rhc_plugin.rhc_free_fn) (rd->rhc); + rhc_free (rd->rhc); } if (rd->status_cb) { @@ -3365,37 +3481,30 @@ static void gc_delete_reader (struct gcreq *gcreq) ddsrt_free (rd); } -int delete_reader (const struct nn_guid *guid) +dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid) { struct reader *rd; assert (!is_writer_entityid (guid->entityid)); - if ((rd = ephash_lookup_reader_guid (guid)) == NULL) + if ((rd = ephash_lookup_reader_guid (gv->guid_hash, guid)) == NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "delete_reader_guid(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); - return Q_ERR_UNKNOWN_ENTITY; + GVLOGDISC ("delete_reader_guid(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid)); + return DDS_RETCODE_BAD_PARAMETER; } - DDS_LOG(DDS_LC_DISCOVERY, "delete_reader_guid(guid "PGUIDFMT") ...\n", PGUID (*guid)); - ddsi_plugin.builtintopic_write (&rd->e, now(), false); - ephash_remove_reader_guid (rd); + GVLOGDISC ("delete_reader_guid(guid "PGUIDFMT") ...\n", PGUID (*guid)); + builtintopic_write (rd->e.gv->builtin_topic_interface, &rd->e, now(), false); + ephash_remove_reader_guid (gv->guid_hash, rd); gcreq_reader (rd); return 0; } -uint64_t reader_instance_id (const struct nn_guid *guid) +void update_reader_qos (struct reader *rd, const dds_qos_t *xqos) { - struct entity_common *e; - e = (struct entity_common*)ephash_lookup_reader_guid(guid); - if (e) { - return e->iid; - } - e = (struct entity_common*)ephash_lookup_proxy_reader_guid(guid); - if (e) { - return e->iid; - } - return 0; + ddsrt_mutex_lock (&rd->e.lock); + if (update_qos_locked (&rd->e, rd->xqos, xqos, now ())) + sedp_write_reader (rd); + ddsrt_mutex_unlock (&rd->e.lock); } - /* PROXY-PARTICIPANT ------------------------------------------------ */ static void gc_proxy_participant_lease (struct gcreq *gcreq) { @@ -3421,7 +3530,7 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct if (proxypp->owns_lease) { const nn_etime_t never = { T_NEVER }; - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_proxy_participant_lease); + struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease); struct lease *oldlease = ddsrt_atomic_ldvoidp (&proxypp->lease); lease_renew (oldlease, never); gcreq->arg = oldlease; @@ -3434,6 +3543,7 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct void new_proxy_participant ( + struct q_globals *gv, const struct nn_guid *ppguid, unsigned bes, unsigned prismtech_bes, @@ -3441,10 +3551,11 @@ void new_proxy_participant struct addrset *as_default, struct addrset *as_meta, const nn_plist_t *plist, - int64_t tlease_dur, + dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, - nn_wctime_t timestamp + nn_wctime_t timestamp, + seqno_t seq ) { /* No locking => iff all participants use unique guids, and sedp @@ -3453,19 +3564,20 @@ void new_proxy_participant struct proxy_participant *proxypp; assert (ppguid->entityid.u == NN_ENTITYID_PARTICIPANT); - assert (ephash_lookup_proxy_participant_guid (ppguid) == NULL); + assert (ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid) == NULL); assert (privileged_pp_guid == NULL || privileged_pp_guid->entityid.u == NN_ENTITYID_PARTICIPANT); - prune_deleted_participant_guids (now_mt ()); + prune_deleted_participant_guids (gv->deleted_participants, now_mt ()); proxypp = ddsrt_malloc (sizeof (*proxypp)); - entity_common_init (&proxypp->e, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false); + entity_common_init (&proxypp->e, gv, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false); proxypp->refc = 1; proxypp->lease_expired = 0; proxypp->vendor = vendor; proxypp->bes = bes; proxypp->prismtech_bes = prismtech_bes; + proxypp->seq = seq; if (privileged_pp_guid) { proxypp->privileged_pp_guid = *privileged_pp_guid; } else { @@ -3486,7 +3598,7 @@ void new_proxy_participant { struct proxy_participant *privpp; - privpp = ephash_lookup_proxy_participant_guid (&proxypp->privileged_pp_guid); + privpp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &proxypp->privileged_pp_guid); if (privpp != NULL && privpp->is_ddsi2_pp) { ddsrt_atomic_stvoidp (&proxypp->lease, ddsrt_atomic_ldvoidp (&privpp->lease)); @@ -3496,7 +3608,7 @@ void new_proxy_participant { /* Lease duration is meaningless when the lease never expires, but when proxy participants are created implicitly because of endpoint discovery from a cloud service, we do want the lease to expire eventually when the cloud discovery service disappears and never reappears. The normal data path renews the lease, so if the lease expiry is changed after the DS disappears but data continues to flow (even if it is only a single sample) the proxy participant would immediately go back to a non-expiring lease with no further triggers for deleting it. Instead, we take tlease_dur == NEVER as a special value meaning a lease that doesn't expire now and that has a "reasonable" lease duration. That way the lease renewal in the data path is fine, and we only need to do something special in SEDP handling. */ nn_etime_t texp = add_duration_to_etime (now_et(), tlease_dur); - int64_t dur = (tlease_dur == T_NEVER) ? config.lease_duration : tlease_dur; + dds_duration_t dur = (tlease_dur == T_NEVER) ? gv->config.lease_duration : tlease_dur; ddsrt_atomic_stvoidp (&proxypp->lease, lease_new (texp, dur, &proxypp->e)); proxypp->owns_lease = 1; } @@ -3506,9 +3618,9 @@ void new_proxy_participant proxypp->as_meta = as_meta; proxypp->endpoints = NULL; proxypp->plist = nn_plist_dup (plist); + nn_xqos_mergein_missing (&proxypp->plist->qos, &gv->default_plist_pp.qos, ~(uint64_t)0); ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups); - if (custom_flags & CF_INC_KERNEL_SEQUENCE_NUMBERS) proxypp->kernel_sequence_numbers = 1; else @@ -3533,7 +3645,7 @@ void new_proxy_participant /* Proxy participant must be in the hash tables for new_proxy_{writer,reader} to work */ - ephash_insert_proxy_participant_guid (proxypp); + ephash_insert_proxy_participant_guid (gv->guid_hash, proxypp); /* Add proxy endpoints based on the advertised (& possibly augmented ...) built-in endpoint set. */ @@ -3577,8 +3689,8 @@ void new_proxy_participant coherency */ nn_plist_init_empty (&plist_wr); nn_plist_init_empty (&plist_rd); - nn_xqos_copy (&plist_wr.qos, &gv.builtin_endpoint_xqos_wr); - nn_xqos_copy (&plist_rd.qos, &gv.builtin_endpoint_xqos_rd); + nn_xqos_copy (&plist_wr.qos, &gv->builtin_endpoint_xqos_wr); + nn_xqos_copy (&plist_rd.qos, &gv->builtin_endpoint_xqos_rd); for (i = 0; i < (int) (sizeof (bestab) / sizeof (*bestab)); i++) { const struct bestab *te = &bestab[i]; @@ -3590,15 +3702,15 @@ void new_proxy_participant assert (is_builtin_entityid (guid1.entityid, proxypp->vendor)); if (is_writer_entityid (guid1.entityid)) { - new_proxy_writer (ppguid, &guid1, proxypp->as_meta, &plist_wr, gv.builtins_dqueue, gv.xevents, timestamp); + new_proxy_writer (gv, ppguid, &guid1, proxypp->as_meta, &plist_wr, gv->builtins_dqueue, gv->xevents, timestamp, 0); } else { #ifdef DDSI_INCLUDE_SSM - const int ssm = addrset_contains_ssm (proxypp->as_meta); - new_proxy_reader (ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, ssm); + const int ssm = addrset_contains_ssm (gv, proxypp->as_meta); + new_proxy_reader (gv, ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, 0, ssm); #else - new_proxy_reader (ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp); + new_proxy_reader (gv, ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, 0); #endif } } @@ -3616,56 +3728,43 @@ void new_proxy_participant if (proxypp->owns_lease) lease_register (ddsrt_atomic_ldvoidp (&proxypp->lease)); - ddsi_plugin.builtintopic_write (&proxypp->e, timestamp, true); + builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true); ddsrt_mutex_unlock (&proxypp->e.lock); } -int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp) +int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp) { - /* Currently, built-in processing is single-threaded, and it is only through this function and the proxy participant deletion (which necessarily happens when no-one else potentially references the proxy participant anymore). So at the moment, the lock is superfluous. */ - nn_plist_t *new_plist; + nn_plist_t *new_plist = ddsrt_malloc (sizeof (*new_plist)); + nn_plist_init_empty (new_plist); + nn_plist_mergein_missing (new_plist, datap, PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME, QP_USER_DATA); + nn_plist_mergein_missing (new_plist, &proxypp->e.gv->default_plist_pp, ~(uint64_t)0, ~(uint64_t)0); - new_plist = nn_plist_dup (datap); - nn_plist_mergein_missing (new_plist, proxypp->plist); - nn_plist_fini (proxypp->plist); - ddsrt_free (proxypp->plist); - proxypp->plist = new_plist; + if (seq > proxypp->seq) + proxypp->seq = seq; switch (source) { case UPD_PROXYPP_SPDP: - ddsi_plugin.builtintopic_write (&proxypp->e, timestamp, true); + update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp); + nn_plist_fini (new_plist); + ddsrt_free (new_plist); proxypp->proxypp_have_spdp = 1; break; + case UPD_PROXYPP_CM: + nn_plist_fini (proxypp->plist); + ddsrt_free (proxypp->plist); + proxypp->plist = new_plist; proxypp->proxypp_have_cm = 1; break; } - return 0; } -int update_proxy_participant_plist (struct proxy_participant *proxypp, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp) +int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp) { - nn_plist_t tmp; - - /* FIXME: find a better way of restricting which bits can get updated */ ddsrt_mutex_lock (&proxypp->e.lock); - switch (source) - { - case UPD_PROXYPP_SPDP: - update_proxy_participant_plist_locked (proxypp, datap, source, timestamp); - break; - case UPD_PROXYPP_CM: - tmp = *datap; - tmp.present &= - PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | - PP_PRISMTECH_WATCHDOG_SCHEDULING | PP_PRISMTECH_LISTENER_SCHEDULING | - PP_PRISMTECH_SERVICE_TYPE | PP_ENTITY_NAME; - tmp.qos.present &= QP_PRISMTECH_ENTITY_FACTORY; - update_proxy_participant_plist_locked (proxypp, &tmp, source, timestamp); - break; - } + update_proxy_participant_plist_locked (proxypp, seq, datap, source, timestamp); ddsrt_mutex_unlock (&proxypp->e.lock); return 0; } @@ -3708,9 +3807,7 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p { assert (proxypp->endpoints == NULL); ddsrt_mutex_unlock (&proxypp->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid)); - - + ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid)); unref_addrset (proxypp->as_default); unref_addrset (proxypp->as_meta); nn_plist_fini (proxypp->plist); @@ -3718,15 +3815,16 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p if (proxypp->owns_lease) lease_free (ddsrt_atomic_ldvoidp (&proxypp->lease)); entity_common_fini (&proxypp->e); - remove_deleted_participant_guid (&proxypp->e.guid, DPG_LOCAL | DPG_REMOTE); + remove_deleted_participant_guid (&proxypp->e.gv->logconfig, proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE); ddsrt_free (proxypp); } else if (proxypp->endpoints == NULL && proxypp->implicitly_created) { assert (refc == 1); ddsrt_mutex_unlock (&proxypp->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "unref_proxy_participant("PGUIDFMT"): refc=%u, no endpoints, implicitly created, deleting\n", PGUID (proxypp->e.guid), (unsigned) refc); - delete_proxy_participant_by_guid(&proxypp->e.guid, tnow, 1); + ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=%u, no endpoints, implicitly created, deleting\n", + PGUID (proxypp->e.guid), (unsigned) refc); + delete_proxy_participant_by_guid(proxypp->e.gv, &proxypp->e.guid, tnow, 1); /* Deletion is still (and has to be) asynchronous. A parallel endpoint creation may or may not succeed, and if it succeeds it will be deleted along with the proxy participant. So "your mileage may vary". Also, the proxy participant may be blacklisted for a little ... */ @@ -3734,14 +3832,14 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p else { ddsrt_mutex_unlock (&proxypp->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "unref_proxy_participant("PGUIDFMT"): refc=%u\n", PGUID (proxypp->e.guid), (unsigned) refc); + ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=%u\n", PGUID (proxypp->e.guid), (unsigned) refc); } } static void gc_delete_proxy_participant (struct gcreq *gcreq) { struct proxy_participant *proxypp = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_proxy_participant(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (proxypp->e.guid)); + ELOGDISC (proxypp, "gc_delete_proxy_participant(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (proxypp->e.guid)); gcreq_free (gcreq); unref_proxy_participant (proxypp, NULL); } @@ -3768,30 +3866,30 @@ static void delete_or_detach_dependent_pp (struct proxy_participant *p, struct p { /* DDSI2 minimal participant mode -- but really, anything not discovered via Cloud gets deleted */ ddsrt_mutex_unlock (&p->e.lock); - (void) delete_proxy_participant_by_guid (&p->e.guid, timestamp, isimplicit); + (void) delete_proxy_participant_by_guid (p->e.gv, &p->e.guid, timestamp, isimplicit); } else { - nn_etime_t texp = add_duration_to_etime (now_et(), config.ds_grace_period); + nn_etime_t texp = add_duration_to_etime (now_et(), p->e.gv->config.ds_grace_period); /* Clear dependency (but don't touch entity id, which must be 0x1c1) and set the lease ticking */ - DDS_LOG(DDS_LC_DISCOVERY, PGUIDFMT" detach-from-DS "PGUIDFMT"\n", PGUID(p->e.guid), PGUID(proxypp->e.guid)); + ELOGDISC (p, PGUIDFMT" detach-from-DS "PGUIDFMT"\n", PGUID(p->e.guid), PGUID(proxypp->e.guid)); memset (&p->privileged_pp_guid.prefix, 0, sizeof (p->privileged_pp_guid.prefix)); lease_set_expiry (ddsrt_atomic_ldvoidp (&p->lease), texp); ddsrt_mutex_unlock (&p->e.lock); } } -static void delete_ppt (struct proxy_participant * proxypp, nn_wctime_t timestamp, int isimplicit) +static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp, int isimplicit) { struct proxy_endpoint_common * c; int ret; /* if any proxy participants depend on this participant, delete them */ - DDS_LOG(DDS_LC_DISCOVERY, "delete_ppt("PGUIDFMT") - deleting dependent proxy participants\n", PGUID (proxypp->e.guid)); + ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting dependent proxy participants\n", PGUID (proxypp->e.guid)); { struct ephash_enum_proxy_participant est; struct proxy_participant *p; - ephash_enum_proxy_participant_init (&est); + ephash_enum_proxy_participant_init (&est, proxypp->e.gv->guid_hash); while ((p = ephash_enum_proxy_participant_next (&est)) != NULL) delete_or_detach_dependent_pp(p, proxypp, timestamp, isimplicit); ephash_enum_proxy_participant_fini (&est); @@ -3804,22 +3902,18 @@ static void delete_ppt (struct proxy_participant * proxypp, nn_wctime_t timestam if (isimplicit) proxypp->lease_expired = 1; - DDS_LOG(DDS_LC_DISCOVERY, "delete_ppt("PGUIDFMT") - deleting groups\n", PGUID (proxypp->e.guid)); - while (!ddsrt_avl_is_empty (&proxypp->groups)) - delete_proxy_group_locked (ddsrt_avl_root (&proxypp_groups_treedef, &proxypp->groups), timestamp, isimplicit); - - DDS_LOG(DDS_LC_DISCOVERY, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid)); + ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid)); c = proxypp->endpoints; while (c) { struct entity_common *e = entity_common_from_proxy_endpoint_common (c); if (is_writer_entityid (e->guid.entityid)) { - ret = delete_proxy_writer (&e->guid, timestamp, isimplicit); + ret = delete_proxy_writer (proxypp->e.gv, &e->guid, timestamp, isimplicit); } else { - ret = delete_proxy_reader (&e->guid, timestamp, isimplicit); + ret = delete_proxy_reader (proxypp->e.gv, &e->guid, timestamp, isimplicit); } (void) ret; c = c->next_ep; @@ -3839,10 +3933,10 @@ static void purge_helper (const nn_locator_t *n, void * varg) { proxy_purge_data_t data = (proxy_purge_data_t) varg; if (compare_locators (n, data->loc) == 0) - delete_proxy_participant_by_guid (&data->proxypp->e.guid, data->timestamp, 1); + delete_proxy_participant_by_guid (data->proxypp->e.gv, &data->proxypp->e.guid, data->timestamp, 1); } -void purge_proxy_participants (const nn_locator_t *loc, bool delete_from_as_disc) +void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc) { /* FIXME: check whether addr:port can't be reused for a new connection by the time we get here. */ /* NOTE: This function exists for the sole purpose of cleaning up after closing a TCP connection in ddsi_tcp_close_conn and the state of the calling thread could be anything at this point. Because of that we do the unspeakable and toggle the thread state conditionally. We can't afford to have it in "asleep", as that causes a race with the garbage collector. */ @@ -3850,165 +3944,59 @@ void purge_proxy_participants (const nn_locator_t *loc, bool delete_from_as_disc struct ephash_enum_proxy_participant est; struct proxy_purge_data data; - thread_state_awake (ts1); + thread_state_awake_fixed_domain (ts1); data.loc = loc; data.timestamp = now(); - ephash_enum_proxy_participant_init (&est); + ephash_enum_proxy_participant_init (&est, gv->guid_hash); while ((data.proxypp = ephash_enum_proxy_participant_next (&est)) != NULL) addrset_forall (data.proxypp->as_meta, purge_helper, &data); ephash_enum_proxy_participant_fini (&est); /* Shouldn't try to keep pinging clients once they're gone */ if (delete_from_as_disc) - remove_from_addrset (gv.as_disc, loc); + remove_from_addrset (gv, gv->as_disc, loc); thread_state_asleep (ts1); } -int delete_proxy_participant_by_guid (const struct nn_guid * guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit) { - struct proxy_participant * ppt; + struct proxy_participant *ppt; - DDS_LOG(DDS_LC_DISCOVERY, "delete_proxy_participant_by_guid("PGUIDFMT") ", PGUID (*guid)); - ddsrt_mutex_lock (&gv.lock); - ppt = ephash_lookup_proxy_participant_guid (guid); + GVLOGDISC ("delete_proxy_participant_by_guid("PGUIDFMT") ", PGUID (*guid)); + ddsrt_mutex_lock (&gv->lock); + ppt = ephash_lookup_proxy_participant_guid (gv->guid_hash, guid); if (ppt == NULL) { - ddsrt_mutex_unlock (&gv.lock); - DDS_LOG(DDS_LC_DISCOVERY, "- unknown\n"); - return Q_ERR_UNKNOWN_ENTITY; + ddsrt_mutex_unlock (&gv->lock); + GVLOGDISC ("- unknown\n"); + return DDS_RETCODE_BAD_PARAMETER; } - DDS_LOG(DDS_LC_DISCOVERY, "- deleting\n"); - ddsi_plugin.builtintopic_write (&ppt->e, timestamp, false); - remember_deleted_participant_guid (&ppt->e.guid); - ephash_remove_proxy_participant_guid (ppt); - ddsrt_mutex_unlock (&gv.lock); + GVLOGDISC ("- deleting\n"); + builtintopic_write (gv->builtin_topic_interface, &ppt->e, timestamp, false); + remember_deleted_participant_guid (gv->deleted_participants, &ppt->e.guid); + ephash_remove_proxy_participant_guid (gv->guid_hash, ppt); + ddsrt_mutex_unlock (&gv->lock); delete_ppt (ppt, timestamp, isimplicit); return 0; } -uint64_t participant_instance_id (const struct nn_guid *guid) +uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_guid *guid) { - struct entity_common *e; - e = (struct entity_common*)ephash_lookup_participant_guid(guid); - if (e) { - return e->iid; - } - e = (struct entity_common*)ephash_lookup_proxy_participant_guid(guid); - if (e) { - return e->iid; - } - return 0; -} - -/* PROXY-GROUP --------------------------------------------------- */ - -int new_proxy_group (const struct nn_guid *guid, const char *name, const struct nn_xqos *xqos, nn_wctime_t timestamp) -{ - struct proxy_participant *proxypp; - nn_guid_t ppguid; - (void)timestamp; - ppguid.prefix = guid->prefix; - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if ((proxypp = ephash_lookup_proxy_participant_guid (&ppguid)) == NULL) - { - DDS_LOG(DDS_LC_DISCOVERY, "new_proxy_group("PGUIDFMT") - unknown participant\n", PGUID (*guid)); - return 0; - } - else - { - struct proxy_group *pgroup; - ddsrt_avl_ipath_t ipath; - int is_sub; - switch (guid->entityid.u & (NN_ENTITYID_SOURCE_MASK | NN_ENTITYID_KIND_MASK)) - { - case NN_ENTITYID_SOURCE_VENDOR | NN_ENTITYID_KIND_PRISMTECH_PUBLISHER: - is_sub = 0; - break; - case NN_ENTITYID_SOURCE_VENDOR | NN_ENTITYID_KIND_PRISMTECH_SUBSCRIBER: - is_sub = 1; - break; - default: - DDS_WARNING("new_proxy_group: unrecognised entityid: %"PRIx32"\n", guid->entityid.u); - return Q_ERR_INVALID_DATA; - } - ddsrt_mutex_lock (&proxypp->e.lock); - if ((pgroup = ddsrt_avl_lookup_ipath (&proxypp_groups_treedef, &proxypp->groups, guid, &ipath)) != NULL) - { - /* Complete proxy group definition if it was a partial - definition made by creating a proxy reader or writer, - otherwise ignore this call */ - if (pgroup->name != NULL) - goto out; - } - else - { - /* Always have a guid, may not have a gid */ - DDS_LOG(DDS_LC_DISCOVERY, "new_proxy_group("PGUIDFMT"): new\n", PGUID (*guid)); - pgroup = ddsrt_malloc (sizeof (*pgroup)); - pgroup->guid = *guid; - pgroup->proxypp = proxypp; - pgroup->name = NULL; - pgroup->xqos = NULL; - ddsrt_avl_insert_ipath (&proxypp_groups_treedef, &proxypp->groups, pgroup, &ipath); - } - if (name) - { - assert (xqos != NULL); - DDS_LOG(DDS_LC_DISCOVERY, "new_proxy_group("PGUIDFMT"): setting name (%s) and qos\n", PGUID (*guid), name); - pgroup->name = ddsrt_strdup (name); - pgroup->xqos = nn_xqos_dup (xqos); - nn_xqos_mergein_missing (pgroup->xqos, is_sub ? &gv.default_xqos_sub : &gv.default_xqos_pub); - } - out: - ddsrt_mutex_unlock (&proxypp->e.lock); - DDS_LOG(DDS_LC_DISCOVERY, "\n"); - return 0; - } -} - -static void delete_proxy_group_locked (struct proxy_group *pgroup, nn_wctime_t timestamp, int isimplicit) -{ - struct proxy_participant *proxypp = pgroup->proxypp; - (void)timestamp; - (void)isimplicit; - assert ((pgroup->xqos != NULL) == (pgroup->name != NULL)); - DDS_LOG(DDS_LC_DISCOVERY, "delete_proxy_group_locked "PGUIDFMT"\n", PGUID (pgroup->guid)); - ddsrt_avl_delete (&proxypp_groups_treedef, &proxypp->groups, pgroup); - /* Publish corresponding built-in topic only if it is not a place - holder: in that case we haven't announced its presence and - therefore don't need to dispose it, and this saves us from having - to handle null pointers for name and QoS in the built-in topic - generation */ - if (pgroup->name) - { - nn_xqos_fini (pgroup->xqos); - ddsrt_free (pgroup->xqos); - ddsrt_free (pgroup->name); - } - ddsrt_free (pgroup); -} - -void delete_proxy_group (const nn_guid_t *guid, nn_wctime_t timestamp, int isimplicit) -{ - struct proxy_participant *proxypp; - nn_guid_t ppguid; - ppguid.prefix = guid->prefix; - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if ((proxypp = ephash_lookup_proxy_participant_guid (&ppguid)) != NULL) - { - struct proxy_group *pgroup; - ddsrt_mutex_lock (&proxypp->e.lock); - if ((pgroup = ddsrt_avl_lookup (&proxypp_groups_treedef, &proxypp->groups, guid)) != NULL) - delete_proxy_group_locked (pgroup, timestamp, isimplicit); - ddsrt_mutex_unlock (&proxypp->e.lock); - } + struct thread_state1 *ts1 = lookup_thread_state (); + struct entity_common *e; + uint64_t iid = 0; + thread_state_awake (ts1, gv); + if ((e = ephash_lookup_guid_untyped (gv->guid_hash, guid)) != NULL) + iid = e->iid; + thread_state_asleep (ts1); + return iid; } /* PROXY-ENDPOINT --------------------------------------------------- */ -static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct nn_guid *guid, nn_wctime_t tcreate, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist) +static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct nn_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist) { const char *name; @@ -4018,18 +4006,18 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en assert ((plist->qos.present & (QP_TOPIC_NAME | QP_TYPE_NAME)) == (QP_TOPIC_NAME | QP_TYPE_NAME)); name = (plist->present & PP_ENTITY_NAME) ? plist->entity_name : ""; - entity_common_init (e, guid, name, kind, tcreate, proxypp->vendor, false); + entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false); c->xqos = nn_xqos_dup (&plist->qos); c->as = ref_addrset (as); c->topic = NULL; /* set from first matching reader/writer */ c->vendor = proxypp->vendor; + c->seq = seq; if (plist->present & PP_GROUP_GUID) c->group_guid = plist->group_guid; else memset (&c->group_guid, 0, sizeof (c->group_guid)); - ref_proxy_participant (proxypp, c); } @@ -4047,7 +4035,7 @@ static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_en /* PROXY-WRITER ----------------------------------------------------- */ -int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp) +int new_proxy_writer (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq) { struct proxy_participant *proxypp; struct proxy_writer *pwr; @@ -4055,16 +4043,16 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, nn_mtime_t tnow = now_mt (); assert (is_writer_entityid (guid->entityid)); - assert (ephash_lookup_proxy_writer_guid (guid) == NULL); + assert (ephash_lookup_proxy_writer_guid (gv->guid_hash, guid) == NULL); - if ((proxypp = ephash_lookup_proxy_participant_guid (ppguid)) == NULL) + if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid)) == NULL) { - DDS_WARNING("new_proxy_writer("PGUIDFMT"): proxy participant unknown\n", PGUID (*guid)); - return Q_ERR_UNKNOWN_ENTITY; + GVWARNING ("new_proxy_writer("PGUIDFMT"): proxy participant unknown\n", PGUID (*guid)); + return DDS_RETCODE_BAD_PARAMETER; } pwr = ddsrt_malloc (sizeof (*pwr)); - proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, proxypp, as, plist); + proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, seq, proxypp, as, plist); ddsrt_avl_init (&pwr_readers_treedef, &pwr->readers); pwr->n_reliable_readers = 0; @@ -4078,8 +4066,8 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, /* The DDSI built-in proxy writers always deliver asynchronously */ pwr->deliver_synchronously = 0; - } else if (nn_from_ddsi_duration (pwr->c.xqos->latency_budget.duration) <= config.synchronous_delivery_latency_bound && - pwr->c.xqos->transport_priority.value >= config.synchronous_delivery_priority_threshold) { + } else if (pwr->c.xqos->latency_budget.duration <= gv->config.synchronous_delivery_latency_bound && + pwr->c.xqos->transport_priority.value >= gv->config.synchronous_delivery_priority_threshold) { /* Regular proxy-writers with a sufficiently low latency_budget and a sufficiently high transport_priority deliver synchronously */ @@ -4088,26 +4076,21 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, pwr->deliver_synchronously = 0; } /* Pretend we have seen a heartbeat if the proxy writer is a best-effort one */ - isreliable = (pwr->c.xqos->reliability.kind != NN_BEST_EFFORT_RELIABILITY_QOS); + isreliable = (pwr->c.xqos->reliability.kind != DDS_RELIABILITY_BEST_EFFORT); pwr->have_seen_heartbeat = !isreliable; pwr->local_matching_inprogress = 1; #ifdef DDSI_INCLUDE_SSM - pwr->supports_ssm = (addrset_contains_ssm (as) && config.allowMulticast & AMC_SSM) ? 1 : 0; + pwr->supports_ssm = (addrset_contains_ssm (gv, as) && gv->config.allowMulticast & AMC_SSM) ? 1 : 0; #endif - /* Only assert PP lease on receipt of data if enabled (duh) and the proxy participant is a - "real" participant, rather than the thing we use for endpoints discovered via the DS */ - pwr->assert_pp_lease = - (unsigned) !!config.arrival_of_data_asserts_pp_and_ep_liveliness; - assert (pwr->c.xqos->present & QP_LIVELINESS); - if (pwr->c.xqos->liveliness.kind != NN_AUTOMATIC_LIVELINESS_QOS) - DDS_LOG(DDS_LC_DISCOVERY, " FIXME: only AUTOMATIC liveliness supported"); + if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC) + GVLOGDISC (" FIXME: only AUTOMATIC liveliness supported"); #if 0 pwr->tlease_dur = nn_from_ddsi_duration (pwr->c.xqos->liveliness.lease_duration); if (pwr->tlease_dur == 0) { - DDS_LOG(DDS_LC_DISCOVERY, " FIXME: treating lease_duration=0 as inf"); + GVLOGDISC (" FIXME: treating lease_duration=0 as inf"); pwr->tlease_dur = T_NEVER; } pwr->tlease_end = add_duration_to_wctime (tnow, pwr->tlease_dur); @@ -4115,13 +4098,13 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, if (isreliable) { - pwr->defrag = nn_defrag_new (NN_DEFRAG_DROP_LATEST, config.defrag_reliable_maxsamples); - pwr->reorder = nn_reorder_new (NN_REORDER_MODE_NORMAL, config.primary_reorder_maxsamples); + pwr->defrag = nn_defrag_new (&gv->logconfig, NN_DEFRAG_DROP_LATEST, gv->config.defrag_reliable_maxsamples); + pwr->reorder = nn_reorder_new (&gv->logconfig, NN_REORDER_MODE_NORMAL, gv->config.primary_reorder_maxsamples, gv->config.late_ack_mode); } else { - pwr->defrag = nn_defrag_new (NN_DEFRAG_DROP_OLDEST, config.defrag_unreliable_maxsamples); - pwr->reorder = nn_reorder_new (NN_REORDER_MODE_MONOTONICALLY_INCREASING, config.primary_reorder_maxsamples); + pwr->defrag = nn_defrag_new (&gv->logconfig, NN_DEFRAG_DROP_OLDEST, gv->config.defrag_unreliable_maxsamples); + pwr->reorder = nn_reorder_new (&gv->logconfig, NN_REORDER_MODE_MONOTONICALLY_INCREASING, gv->config.primary_reorder_maxsamples, gv->config.late_ack_mode); } pwr->dqueue = dqueue; pwr->evq = evq; @@ -4132,8 +4115,8 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, /* locking the entity prevents matching while the built-in topic hasn't been published yet */ ddsrt_mutex_lock (&pwr->e.lock); - ephash_insert_proxy_writer_guid (pwr); - ddsi_plugin.builtintopic_write (&pwr->e, timestamp, true); + ephash_insert_proxy_writer_guid (gv->guid_hash, pwr); + builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, true); ddsrt_mutex_unlock (&pwr->e.lock); match_proxy_writer_with_readers (pwr, tnow); @@ -4145,38 +4128,44 @@ int new_proxy_writer (const struct nn_guid *ppguid, const struct nn_guid *guid, return 0; } -void update_proxy_writer (struct proxy_writer * pwr, struct addrset * as) +void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp) { struct reader * rd; - struct pwr_rd_match * m; + struct pwr_rd_match * m; ddsrt_avl_iter_t iter; /* Update proxy writer endpoints (from SEDP alive) */ ddsrt_mutex_lock (&pwr->e.lock); - if (! addrset_eq_onesidederr (pwr->c.as, as)) + if (seq > pwr->c.seq) { -#ifdef DDSI_INCLUDE_SSM - pwr->supports_ssm = (addrset_contains_ssm (as) && config.allowMulticast & AMC_SSM) ? 1 : 0; -#endif - unref_addrset (pwr->c.as); - ref_addrset (as); - pwr->c.as = as; - m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &iter); - while (m) + pwr->c.seq = seq; + if (! addrset_eq_onesidederr (pwr->c.as, as)) { - rd = ephash_lookup_reader_guid (&m->rd_guid); - if (rd) +#ifdef DDSI_INCLUDE_SSM + pwr->supports_ssm = (addrset_contains_ssm (pwr->e.gv, as) && pwr->e.gv->config.allowMulticast & AMC_SSM) ? 1 : 0; +#endif + unref_addrset (pwr->c.as); + ref_addrset (as); + pwr->c.as = as; + m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &iter); + while (m) { - qxev_pwr_entityid (pwr, &rd->e.guid.prefix); + rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid); + if (rd) + { + qxev_pwr_entityid (pwr, &rd->e.guid.prefix); + } + m = ddsrt_avl_iter_next (&iter); } - m = ddsrt_avl_iter_next (&iter); } + + update_qos_locked (&pwr->e, pwr->c.xqos, xqos, timestamp); } ddsrt_mutex_unlock (&pwr->e.lock); } -void update_proxy_reader (struct proxy_reader * prd, struct addrset * as) +void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp) { struct prd_wr_match * m; nn_guid_t wrguid; @@ -4184,46 +4173,52 @@ void update_proxy_reader (struct proxy_reader * prd, struct addrset * as) memset (&wrguid, 0, sizeof (wrguid)); ddsrt_mutex_lock (&prd->e.lock); - if (! addrset_eq_onesidederr (prd->c.as, as)) + if (seq > prd->c.seq) { - /* Update proxy reader endpoints (from SEDP alive) */ - - unref_addrset (prd->c.as); - ref_addrset (as); - prd->c.as = as; - - /* Rebuild writer endpoints */ - - while ((m = ddsrt_avl_lookup_succ_eq (&prd_writers_treedef, &prd->writers, &wrguid)) != NULL) + prd->c.seq = seq; + if (! addrset_eq_onesidederr (prd->c.as, as)) { - struct prd_wr_match *next; - nn_guid_t guid_next; - struct writer * wr; + /* Update proxy reader endpoints (from SEDP alive) */ - wrguid = m->wr_guid; - next = ddsrt_avl_find_succ (&prd_writers_treedef, &prd->writers, m); - if (next) - { - guid_next = next->wr_guid; - } - else - { - memset (&guid_next, 0xff, sizeof (guid_next)); - guid_next.entityid.u = (guid_next.entityid.u & ~(unsigned)0xff) | NN_ENTITYID_KIND_WRITER_NO_KEY; - } + unref_addrset (prd->c.as); + ref_addrset (as); + prd->c.as = as; - ddsrt_mutex_unlock (&prd->e.lock); - wr = ephash_lookup_writer_guid (&wrguid); - if (wr) + /* Rebuild writer endpoints */ + + while ((m = ddsrt_avl_lookup_succ_eq (&prd_writers_treedef, &prd->writers, &wrguid)) != NULL) { - ddsrt_mutex_lock (&wr->e.lock); - rebuild_writer_addrset (wr); - ddsrt_mutex_unlock (&wr->e.lock); - qxev_prd_entityid (prd, &wr->e.guid.prefix); + struct prd_wr_match *next; + nn_guid_t guid_next; + struct writer * wr; + + wrguid = m->wr_guid; + next = ddsrt_avl_find_succ (&prd_writers_treedef, &prd->writers, m); + if (next) + { + guid_next = next->wr_guid; + } + else + { + memset (&guid_next, 0xff, sizeof (guid_next)); + guid_next.entityid.u = (guid_next.entityid.u & ~(unsigned)0xff) | NN_ENTITYID_KIND_WRITER_NO_KEY; + } + + ddsrt_mutex_unlock (&prd->e.lock); + wr = ephash_lookup_writer_guid (prd->e.gv->guid_hash, &wrguid); + if (wr) + { + ddsrt_mutex_lock (&wr->e.lock); + rebuild_writer_addrset (wr); + ddsrt_mutex_unlock (&wr->e.lock); + qxev_prd_entityid (prd, &wr->e.guid.prefix); + } + wrguid = guid_next; + ddsrt_mutex_lock (&prd->e.lock); } - wrguid = guid_next; - ddsrt_mutex_lock (&prd->e.lock); } + + update_qos_locked (&prd->e, prd->c.xqos, xqos, timestamp); } ddsrt_mutex_unlock (&prd->e.lock); } @@ -4231,7 +4226,7 @@ void update_proxy_reader (struct proxy_reader * prd, struct addrset * as) static void gc_delete_proxy_writer (struct gcreq *gcreq) { struct proxy_writer *pwr = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_proxy_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); + ELOGDISC (pwr, "gc_delete_proxy_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); gcreq_free (gcreq); while (!ddsrt_avl_is_empty (&pwr->readers)) @@ -4239,7 +4234,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq) struct pwr_rd_match *m = ddsrt_avl_root_non_empty (&pwr_readers_treedef, &pwr->readers); ddsrt_avl_delete (&pwr_readers_treedef, &pwr->readers, m); reader_drop_connection (&m->rd_guid, pwr); - update_reader_init_acknack_count (&m->rd_guid, m->count); + update_reader_init_acknack_count (&pwr->e.gv->logconfig, pwr->e.gv->guid_hash, &m->rd_guid, m->count); free_pwr_rd_match (m); } local_reader_ary_fini (&pwr->rdary); @@ -4249,34 +4244,34 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq) ddsrt_free (pwr); } -int delete_proxy_writer (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit) { struct proxy_writer *pwr; (void)isimplicit; - DDS_LOG(DDS_LC_DISCOVERY, "delete_proxy_writer ("PGUIDFMT") ", PGUID (*guid)); - ddsrt_mutex_lock (&gv.lock); - if ((pwr = ephash_lookup_proxy_writer_guid (guid)) == NULL) + GVLOGDISC ("delete_proxy_writer ("PGUIDFMT") ", PGUID (*guid)); + ddsrt_mutex_lock (&gv->lock); + if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL) { - ddsrt_mutex_unlock (&gv.lock); - DDS_LOG(DDS_LC_DISCOVERY, "- unknown\n"); - return Q_ERR_UNKNOWN_ENTITY; + ddsrt_mutex_unlock (&gv->lock); + GVLOGDISC ("- unknown\n"); + return DDS_RETCODE_BAD_PARAMETER; } /* Set "deleting" flag in particular for Lite, to signal to the receive path it can't trust rdary[] anymore, which is because removing the proxy writer from the hash table will prevent the readers from looking up the proxy writer, and consequently from removing themselves from the proxy writer's rdary[]. */ local_reader_ary_setinvalid (&pwr->rdary); - DDS_LOG(DDS_LC_DISCOVERY, "- deleting\n"); - ddsi_plugin.builtintopic_write (&pwr->e, timestamp, false); - ephash_remove_proxy_writer_guid (pwr); - ddsrt_mutex_unlock (&gv.lock); + GVLOGDISC ("- deleting\n"); + builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false); + ephash_remove_proxy_writer_guid (gv->guid_hash, pwr); + ddsrt_mutex_unlock (&gv->lock); gcreq_proxy_writer (pwr); return 0; } /* PROXY-READER ----------------------------------------------------- */ -int new_proxy_reader (const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp +int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq #ifdef DDSI_INCLUDE_SSM , int favours_ssm #endif @@ -4287,32 +4282,29 @@ int new_proxy_reader (const struct nn_guid *ppguid, const struct nn_guid *guid, nn_mtime_t tnow = now_mt (); assert (!is_writer_entityid (guid->entityid)); - assert (ephash_lookup_proxy_reader_guid (guid) == NULL); + assert (ephash_lookup_proxy_reader_guid (gv->guid_hash, guid) == NULL); - if ((proxypp = ephash_lookup_proxy_participant_guid (ppguid)) == NULL) + if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid)) == NULL) { - DDS_WARNING("new_proxy_reader("PGUIDFMT"): proxy participant unknown\n", PGUID (*guid)); - return Q_ERR_UNKNOWN_ENTITY; + GVWARNING ("new_proxy_reader("PGUIDFMT"): proxy participant unknown\n", PGUID (*guid)); + return DDS_RETCODE_BAD_PARAMETER; } prd = ddsrt_malloc (sizeof (*prd)); - proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, proxypp, as, plist); + proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, seq, proxypp, as, plist); prd->deleting = 0; #ifdef DDSI_INCLUDE_SSM - prd->favours_ssm = (favours_ssm && config.allowMulticast & AMC_SSM) ? 1 : 0; + prd->favours_ssm = (favours_ssm && gv->config.allowMulticast & AMC_SSM) ? 1 : 0; #endif prd->is_fict_trans_reader = 0; - /* Only assert PP lease on receipt of data if enabled (duh) and the proxy participant is a - "real" participant, rather than the thing we use for endpoints discovered via the DS */ - prd->assert_pp_lease = (unsigned) !!config.arrival_of_data_asserts_pp_and_ep_liveliness; ddsrt_avl_init (&prd_writers_treedef, &prd->writers); /* locking the entity prevents matching while the built-in topic hasn't been published yet */ ddsrt_mutex_lock (&prd->e.lock); - ephash_insert_proxy_reader_guid (prd); - ddsi_plugin.builtintopic_write (&prd->e, timestamp, true); + ephash_insert_proxy_reader_guid (gv->guid_hash, prd); + builtintopic_write (gv->builtin_topic_interface, &prd->e, timestamp, true); ddsrt_mutex_unlock (&prd->e.lock); match_proxy_reader_with_writers (prd, tnow); @@ -4344,7 +4336,7 @@ static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *p } ddsrt_mutex_unlock (&prd->e.lock); - if ((wr = ephash_lookup_writer_guid (&wrguid)) != NULL) + if ((wr = ephash_lookup_writer_guid (prd->e.gv->guid_hash, &wrguid)) != NULL) { struct whc_node *deferred_free_list = NULL; struct wr_prd_match *m_wr; @@ -4370,7 +4362,7 @@ static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *p static void gc_delete_proxy_reader (struct gcreq *gcreq) { struct proxy_reader *prd = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_proxy_reader(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (prd->e.guid)); + ELOGDISC (prd, "gc_delete_proxy_reader(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (prd->e.guid)); gcreq_free (gcreq); while (!ddsrt_avl_is_empty (&prd->writers)) @@ -4385,22 +4377,22 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq) ddsrt_free (prd); } -int delete_proxy_reader (const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_reader (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit) { struct proxy_reader *prd; (void)isimplicit; - DDS_LOG(DDS_LC_DISCOVERY, "delete_proxy_reader ("PGUIDFMT") ", PGUID (*guid)); - ddsrt_mutex_lock (&gv.lock); - if ((prd = ephash_lookup_proxy_reader_guid (guid)) == NULL) + GVLOGDISC ("delete_proxy_reader ("PGUIDFMT") ", PGUID (*guid)); + ddsrt_mutex_lock (&gv->lock); + if ((prd = ephash_lookup_proxy_reader_guid (gv->guid_hash, guid)) == NULL) { - ddsrt_mutex_unlock (&gv.lock); - DDS_LOG(DDS_LC_DISCOVERY, "- unknown\n"); - return Q_ERR_UNKNOWN_ENTITY; + ddsrt_mutex_unlock (&gv->lock); + GVLOGDISC ("- unknown\n"); + return DDS_RETCODE_BAD_PARAMETER; } - ddsi_plugin.builtintopic_write (&prd->e, timestamp, false); - ephash_remove_proxy_reader_guid (prd); - ddsrt_mutex_unlock (&gv.lock); - DDS_LOG(DDS_LC_DISCOVERY, "- deleting\n"); + builtintopic_write (gv->builtin_topic_interface, &prd->e, timestamp, false); + ephash_remove_proxy_reader_guid (gv->guid_hash, prd); + ddsrt_mutex_unlock (&gv->lock); + GVLOGDISC ("- deleting\n"); /* If the proxy reader is reliable, pretend it has just acked all messages: this allows a throttled writer to once again make @@ -4416,7 +4408,7 @@ int delete_proxy_reader (const struct nn_guid *guid, nn_wctime_t timestamp, int static int gcreq_participant (struct participant *pp) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_delete_participant); + struct gcreq *gcreq = gcreq_new (pp->e.gv->gcreq_queue, gc_delete_participant); gcreq->arg = pp; gcreq_enqueue (gcreq); return 0; @@ -4424,7 +4416,7 @@ static int gcreq_participant (struct participant *pp) static int gcreq_writer (struct writer *wr) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, wr->throttling ? gc_delete_writer_throttlewait : gc_delete_writer); + struct gcreq *gcreq = gcreq_new (wr->e.gv->gcreq_queue, wr->throttling ? gc_delete_writer_throttlewait : gc_delete_writer); gcreq->arg = wr; gcreq_enqueue (gcreq); return 0; @@ -4432,7 +4424,7 @@ static int gcreq_writer (struct writer *wr) static int gcreq_reader (struct reader *rd) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_delete_reader); + struct gcreq *gcreq = gcreq_new (rd->e.gv->gcreq_queue, gc_delete_reader); gcreq->arg = rd; gcreq_enqueue (gcreq); return 0; @@ -4440,7 +4432,7 @@ static int gcreq_reader (struct reader *rd) static int gcreq_proxy_participant (struct proxy_participant *proxypp) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_delete_proxy_participant); + struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_delete_proxy_participant); gcreq->arg = proxypp; gcreq_enqueue (gcreq); return 0; @@ -4450,7 +4442,7 @@ static void gc_delete_proxy_writer_dqueue_bubble_cb (struct gcreq *gcreq) { /* delete proxy_writer, phase 3 */ struct proxy_writer *pwr = gcreq->arg; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_proxy_writer_dqueue_bubble(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); + ELOGDISC (pwr, "gc_delete_proxy_writer_dqueue_bubble(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); gcreq_requeue (gcreq, gc_delete_proxy_writer); } @@ -4459,13 +4451,13 @@ static void gc_delete_proxy_writer_dqueue (struct gcreq *gcreq) /* delete proxy_writer, phase 2 */ struct proxy_writer *pwr = gcreq->arg; struct nn_dqueue *dqueue = pwr->dqueue; - DDS_LOG(DDS_LC_DISCOVERY, "gc_delete_proxy_writer_dqueue(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); + ELOGDISC (pwr, "gc_delete_proxy_writer_dqueue(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid)); nn_dqueue_enqueue_callback (dqueue, (void (*) (void *)) gc_delete_proxy_writer_dqueue_bubble_cb, gcreq); } static int gcreq_proxy_writer (struct proxy_writer *pwr) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_delete_proxy_writer_dqueue); + struct gcreq *gcreq = gcreq_new (pwr->e.gv->gcreq_queue, gc_delete_proxy_writer_dqueue); gcreq->arg = pwr; gcreq_enqueue (gcreq); return 0; @@ -4473,7 +4465,7 @@ static int gcreq_proxy_writer (struct proxy_writer *pwr) static int gcreq_proxy_reader (struct proxy_reader *prd) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_delete_proxy_reader); + struct gcreq *gcreq = gcreq_new (prd->e.gv->gcreq_queue, gc_delete_proxy_reader); gcreq->arg = prd; gcreq_enqueue (gcreq); return 0; diff --git a/src/core/ddsi/src/q_ephash.c b/src/core/ddsi/src/q_ephash.c index d02fcba..0a106be 100644 --- a/src/core/ddsi/src/q_ephash.c +++ b/src/core/ddsi/src/q_ephash.c @@ -69,18 +69,19 @@ static void gc_buckets_cb (struct gcreq *gcreq) ddsrt_free (bs); } -static void gc_buckets (void *bs) +static void gc_buckets (void *bs, void *varg) { - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, gc_buckets_cb); + struct q_globals *gv = varg; + struct gcreq *gcreq = gcreq_new (gv->gcreq_queue, gc_buckets_cb); gcreq->arg = bs; gcreq_enqueue (gcreq); } -struct ephash *ephash_new (void) +struct ephash *ephash_new (struct q_globals *gv) { struct ephash *ephash; ephash = ddsrt_malloc (sizeof (*ephash)); - ephash->hash = ddsrt_chh_new (32, hash_entity_guid_wrapper, entity_guid_eq_wrapper, gc_buckets); + ephash->hash = ddsrt_chh_new (32, hash_entity_guid_wrapper, entity_guid_eq_wrapper, gc_buckets, gv); if (ephash->hash == NULL) { ddsrt_free (ephash); return NULL; @@ -96,194 +97,190 @@ void ephash_free (struct ephash *ephash) ddsrt_free (ephash); } -static void ephash_guid_insert (struct entity_common *e) +static void ephash_guid_insert (struct ephash *gh, struct entity_common *e) { int x; - assert(gv.guid_hash); - assert(gv.guid_hash->hash); - x = ddsrt_chh_add (gv.guid_hash->hash, e); + x = ddsrt_chh_add (gh->hash, e); (void)x; assert (x); } -static void ephash_guid_remove (struct entity_common *e) +static void ephash_guid_remove (struct ephash *gh, struct entity_common *e) { int x; - assert(gv.guid_hash); - assert(gv.guid_hash->hash); - x = ddsrt_chh_remove (gv.guid_hash->hash, e); + x = ddsrt_chh_remove (gh->hash, e); (void)x; assert (x); } -void *ephash_lookup_guid_untyped (const struct nn_guid *guid) +void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct nn_guid *guid) { /* FIXME: could (now) require guid to be first in entity_common; entity_common already is first in entity */ struct entity_common e; e.guid = *guid; - return ddsrt_chh_lookup (gv.guid_hash->hash, &e); + assert (thread_is_awake ()); + return ddsrt_chh_lookup (gh->hash, &e); } -static void *ephash_lookup_guid_int (const struct ephash *ephash, const struct nn_guid *guid, enum entity_kind kind) +static void *ephash_lookup_guid_int (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind) { struct entity_common *res; - (void)ephash; - if ((res = ephash_lookup_guid_untyped (guid)) != NULL && res->kind == kind) + if ((res = ephash_lookup_guid_untyped (gh, guid)) != NULL && res->kind == kind) return res; else return NULL; } -void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind) +void *ephash_lookup_guid (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind) { - return ephash_lookup_guid_int (NULL, guid, kind); + return ephash_lookup_guid_int (gh, guid, kind); } -void ephash_insert_participant_guid (struct participant *pp) +void ephash_insert_participant_guid (struct ephash *gh, struct participant *pp) { - ephash_guid_insert (&pp->e); + ephash_guid_insert (gh, &pp->e); } -void ephash_insert_proxy_participant_guid (struct proxy_participant *proxypp) +void ephash_insert_proxy_participant_guid (struct ephash *gh, struct proxy_participant *proxypp) { - ephash_guid_insert (&proxypp->e); + ephash_guid_insert (gh, &proxypp->e); } -void ephash_insert_writer_guid (struct writer *wr) +void ephash_insert_writer_guid (struct ephash *gh, struct writer *wr) { - ephash_guid_insert (&wr->e); + ephash_guid_insert (gh, &wr->e); } -void ephash_insert_reader_guid (struct reader *rd) +void ephash_insert_reader_guid (struct ephash *gh, struct reader *rd) { - ephash_guid_insert (&rd->e); + ephash_guid_insert (gh, &rd->e); } -void ephash_insert_proxy_writer_guid (struct proxy_writer *pwr) +void ephash_insert_proxy_writer_guid (struct ephash *gh, struct proxy_writer *pwr) { - ephash_guid_insert (&pwr->e); + ephash_guid_insert (gh, &pwr->e); } -void ephash_insert_proxy_reader_guid (struct proxy_reader *prd) +void ephash_insert_proxy_reader_guid (struct ephash *gh, struct proxy_reader *prd) { - ephash_guid_insert (&prd->e); + ephash_guid_insert (gh, &prd->e); } -void ephash_remove_participant_guid (struct participant *pp) +void ephash_remove_participant_guid (struct ephash *gh, struct participant *pp) { - ephash_guid_remove (&pp->e); + ephash_guid_remove (gh, &pp->e); } -void ephash_remove_proxy_participant_guid (struct proxy_participant *proxypp) +void ephash_remove_proxy_participant_guid (struct ephash *gh, struct proxy_participant *proxypp) { - ephash_guid_remove (&proxypp->e); + ephash_guid_remove (gh, &proxypp->e); } -void ephash_remove_writer_guid (struct writer *wr) +void ephash_remove_writer_guid (struct ephash *gh, struct writer *wr) { - ephash_guid_remove (&wr->e); + ephash_guid_remove (gh, &wr->e); } -void ephash_remove_reader_guid (struct reader *rd) +void ephash_remove_reader_guid (struct ephash *gh, struct reader *rd) { - ephash_guid_remove (&rd->e); + ephash_guid_remove (gh, &rd->e); } -void ephash_remove_proxy_writer_guid (struct proxy_writer *pwr) +void ephash_remove_proxy_writer_guid (struct ephash *gh, struct proxy_writer *pwr) { - ephash_guid_remove (&pwr->e); + ephash_guid_remove (gh, &pwr->e); } -void ephash_remove_proxy_reader_guid (struct proxy_reader *prd) +void ephash_remove_proxy_reader_guid (struct ephash *gh, struct proxy_reader *prd) { - ephash_guid_remove (&prd->e); + ephash_guid_remove (gh, &prd->e); } -struct participant *ephash_lookup_participant_guid (const struct nn_guid *guid) +struct participant *ephash_lookup_participant_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT); assert (offsetof (struct participant, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PARTICIPANT); + return ephash_lookup_guid_int (gh, guid, EK_PARTICIPANT); } -struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct nn_guid *guid) +struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT); assert (offsetof (struct proxy_participant, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_PARTICIPANT); + return ephash_lookup_guid_int (gh, guid, EK_PROXY_PARTICIPANT); } -struct writer *ephash_lookup_writer_guid (const struct nn_guid *guid) +struct writer *ephash_lookup_writer_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (is_writer_entityid (guid->entityid)); assert (offsetof (struct writer, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_WRITER); + return ephash_lookup_guid_int (gh, guid, EK_WRITER); } -struct reader *ephash_lookup_reader_guid (const struct nn_guid *guid) +struct reader *ephash_lookup_reader_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (is_reader_entityid (guid->entityid)); assert (offsetof (struct reader, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_READER); + return ephash_lookup_guid_int (gh, guid, EK_READER); } -struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct nn_guid *guid) +struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (is_writer_entityid (guid->entityid)); assert (offsetof (struct proxy_writer, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_WRITER); + return ephash_lookup_guid_int (gh, guid, EK_PROXY_WRITER); } -struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct nn_guid *guid) +struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *gh, const struct nn_guid *guid) { assert (is_reader_entityid (guid->entityid)); assert (offsetof (struct proxy_reader, e) == 0); - return ephash_lookup_guid_int (gv.guid_hash, guid, EK_PROXY_READER); + return ephash_lookup_guid_int (gh, guid, EK_PROXY_READER); } /* Enumeration */ -static void ephash_enum_init_int (struct ephash_enum *st, struct ephash *ephash, enum entity_kind kind) +static void ephash_enum_init_int (struct ephash_enum *st, const struct ephash *gh, enum entity_kind kind) { st->kind = kind; - st->cur = ddsrt_chh_iter_first (ephash->hash, &st->it); + st->cur = ddsrt_chh_iter_first (gh->hash, &st->it); while (st->cur && st->cur->kind != st->kind) st->cur = ddsrt_chh_iter_next (&st->it); } -void ephash_enum_init (struct ephash_enum *st, enum entity_kind kind) +void ephash_enum_init (struct ephash_enum *st, const struct ephash *gh, enum entity_kind kind) { - ephash_enum_init_int(st, gv.guid_hash, kind); + ephash_enum_init_int(st, gh, kind); } -void ephash_enum_writer_init (struct ephash_enum_writer *st) +void ephash_enum_writer_init (struct ephash_enum_writer *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_WRITER); + ephash_enum_init (&st->st, gh, EK_WRITER); } -void ephash_enum_reader_init (struct ephash_enum_reader *st) +void ephash_enum_reader_init (struct ephash_enum_reader *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_READER); + ephash_enum_init (&st->st, gh, EK_READER); } -void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st) +void ephash_enum_proxy_writer_init (struct ephash_enum_proxy_writer *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_PROXY_WRITER); + ephash_enum_init (&st->st, gh, EK_PROXY_WRITER); } -void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st) +void ephash_enum_proxy_reader_init (struct ephash_enum_proxy_reader *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_PROXY_READER); + ephash_enum_init (&st->st, gh, EK_PROXY_READER); } -void ephash_enum_participant_init (struct ephash_enum_participant *st) +void ephash_enum_participant_init (struct ephash_enum_participant *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_PARTICIPANT); + ephash_enum_init (&st->st, gh, EK_PARTICIPANT); } -void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st) +void ephash_enum_proxy_participant_init (struct ephash_enum_proxy_participant *st, const struct ephash *gh) { - ephash_enum_init (&st->st, EK_PROXY_PARTICIPANT); + ephash_enum_init (&st->st, gh, EK_PROXY_PARTICIPANT); } void *ephash_enum_next (struct ephash_enum *st) diff --git a/src/core/ddsi/src/q_freelist.c b/src/core/ddsi/src/q_freelist.c index fd7aef7..9d1a1bc 100644 --- a/src/core/ddsi/src/q_freelist.c +++ b/src/core/ddsi/src/q_freelist.c @@ -140,9 +140,9 @@ void nn_freelist_fini (struct nn_freelist *fl, void (*xfree) (void *)) xfree (fl->inner[i].m->x[j]); ddsrt_free(fl->inner[i].m); } -/* The compiler can't make sense of all these linked lists and doesn't - * realize that the next pointers are always initialized here. */ -DDSRT_WARNING_MSVC_OFF(6001); + /* The compiler can't make sense of all these linked lists and doesn't + * realize that the next pointers are always initialized here. */ + DDSRT_WARNING_MSVC_OFF(6001); while ((m = fl->mlist) != NULL) { fl->mlist = m->next; @@ -155,7 +155,7 @@ DDSRT_WARNING_MSVC_OFF(6001); fl->emlist = m->next; ddsrt_free (m); } -DDSRT_WARNING_MSVC_ON(6001); + DDSRT_WARNING_MSVC_ON(6001); } static ddsrt_atomic_uint32_t freelist_inner_idx_off = DDSRT_ATOMIC_UINT32_INIT(0); diff --git a/src/core/ddsi/src/q_gc.c b/src/core/ddsi/src/q_gc.c index 42fc0ef..054485c 100644 --- a/src/core/ddsi/src/q_gc.c +++ b/src/core/ddsi/src/q_gc.c @@ -25,6 +25,7 @@ #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_lease.h" #include "dds/ddsi/q_globals.h" /* for mattr, cattr */ +#include "dds/ddsi/q_receive.h" /* for trigger_receive_threads */ #include "dds/ddsi/q_rtps.h" /* for guid_hash */ @@ -35,35 +36,45 @@ struct gcreq_queue { ddsrt_cond_t cond; int terminate; int32_t count; + struct q_globals *gv; struct thread_state1 *ts; }; -static void threads_vtime_gather_for_wait (unsigned *nivs, struct idx_vtime *ivs) +static void threads_vtime_gather_for_wait (const struct q_globals *gv, unsigned *nivs, struct idx_vtime *ivs) { /* copy vtimes of threads, skipping those that are sleeping */ - unsigned i, j; + uint32_t i, j; for (i = j = 0; i < thread_states.nthreads; i++) { - vtime_t vtime = thread_states.ts[i].vtime; + vtime_t vtime = ddsrt_atomic_ld32 (&thread_states.ts[i].vtime); if (vtime_awake_p (vtime)) { - ivs[j].idx = i; - ivs[j].vtime = vtime; - ++j; + ddsrt_atomic_fence_ldld (); + /* ts[i].gv is set before ts[i].vtime indicates the thread is awake, so if the thread hasn't + gone through another sleep/wake cycle since loading ts[i].vtime, ts[i].gv is correct; if + instead it has gone through another cycle since loading ts[i].vtime, then the thread will + be dropped from the live threads on the next check. So it won't ever wait with unknown + duration for progres of threads stuck in another domain */ + if (gv == ddsrt_atomic_ldvoidp (&thread_states.ts[i].gv)) + { + ivs[j].idx = i; + ivs[j].vtime = vtime; + ++j; + } } } *nivs = j; } -static int threads_vtime_check (unsigned *nivs, struct idx_vtime *ivs) +static int threads_vtime_check (uint32_t *nivs, struct idx_vtime *ivs) { /* check all threads in ts have made progress those that have are removed from the set */ - unsigned i = 0; + uint32_t i = 0; while (i < *nivs) { - unsigned thridx = ivs[i].idx; - vtime_t vtime = thread_states.ts[thridx].vtime; + uint32_t thridx = ivs[i].idx; + vtime_t vtime = ddsrt_atomic_ld32 (&thread_states.ts[thridx].vtime); assert (vtime_awake_p (ivs[i].vtime)); if (!vtime_gt (vtime, ivs[i].vtime)) ++i; @@ -81,14 +92,28 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) { struct thread_state1 * const ts1 = lookup_thread_state (); nn_mtime_t next_thread_cputime = { 0 }; - dds_time_t shortsleep = 1 * T_MILLISECOND; + nn_mtime_t t_trigger_recv_threads = { 0 }; + int64_t shortsleep = 1 * T_MILLISECOND; int64_t delay = T_MILLISECOND; /* force evaluation after startup */ struct gcreq *gcreq = NULL; int trace_shortsleep = 1; ddsrt_mutex_lock (&q->lock); while (!(q->terminate && q->count == 0)) { - LOG_THREAD_CPUTIME (next_thread_cputime); + LOG_THREAD_CPUTIME (&q->gv->logconfig, next_thread_cputime); + + /* While deaf, we need to make sure the receive thread wakes up + every now and then to try recreating sockets & rejoining multicast + groups. Do rate-limit it a bit. */ + if (q->gv->deaf) + { + nn_mtime_t tnow_mt = now_mt (); + if (tnow_mt.v > t_trigger_recv_threads.v) + { + trigger_recv_threads (q->gv); + t_trigger_recv_threads.v = tnow_mt.v + DDS_MSECS (100); + } + } /* If we are waiting for a gcreq to become ready, don't bother looking at the queue; if we aren't, wait for a request to come @@ -100,14 +125,15 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) if (q->first == NULL) { /* FIXME: use absolute timeouts */ + /* avoid overflows; ensure periodic wakeups of receive thread if deaf */ + const int64_t maxdelay = q->gv->deaf ? DDS_MSECS (100) : DDS_SECS (1000); dds_time_t to; - if (delay >= 1000 * T_SECOND) { - /* avoid overflow */ - to = DDS_SECS(1000); + if (delay >= maxdelay) { + to = maxdelay; } else { to = delay; } - ddsrt_cond_waitfor(&q->cond, &q->lock, to); + ddsrt_cond_waitfor (&q->cond, &q->lock, to); } if (q->first) { @@ -124,8 +150,8 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) very little impact on its primary purpose and be less of a burden on the system than having a separate thread or adding it to the workload of the data handling threads. */ - thread_state_awake (ts1); - delay = check_and_handle_lease_expiration (now_et ()); + thread_state_awake_fixed_domain (ts1); + delay = check_and_handle_lease_expiration (q->gv, now_et ()); thread_state_asleep (ts1); if (gcreq) @@ -139,7 +165,7 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) reasonable. */ if (trace_shortsleep) { - DDS_TRACE("gc %p: not yet, shortsleep\n", (void*)gcreq); + DDS_CTRACE (&q->gv->logconfig, "gc %p: not yet, shortsleep\n", (void *) gcreq); trace_shortsleep = 0; } dds_sleepfor (shortsleep); @@ -150,8 +176,8 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) it; the callback is responsible for requeueing (if complex multi-phase delete) or freeing the delete request. Reset the current gcreq as this one obviously is no more. */ - DDS_TRACE("gc %p: deleting\n", (void*)gcreq); - thread_state_awake (ts1); + DDS_CTRACE (&q->gv->logconfig, "gc %p: deleting\n", (void *) gcreq); + thread_state_awake_fixed_domain (ts1); gcreq->cb (gcreq); thread_state_asleep (ts1); gcreq = NULL; @@ -165,16 +191,17 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) return 0; } -struct gcreq_queue *gcreq_queue_new (void) +struct gcreq_queue *gcreq_queue_new (struct q_globals *gv) { struct gcreq_queue *q = ddsrt_malloc (sizeof (*q)); q->first = q->last = NULL; q->terminate = 0; q->count = 0; + q->gv = gv; ddsrt_mutex_init (&q->lock); ddsrt_cond_init (&q->cond); - if (create_thread (&q->ts, "gc", (uint32_t (*) (void *)) gcreq_queue_thread, q) == DDS_RETCODE_OK) + if (create_thread (&q->ts, gv, "gc", (uint32_t (*) (void *)) gcreq_queue_thread, q) == DDS_RETCODE_OK) return q; else { @@ -229,7 +256,7 @@ struct gcreq *gcreq_new (struct gcreq_queue *q, gcreq_cb_t cb) gcreq = ddsrt_malloc (offsetof (struct gcreq, vtimes) + thread_states.nthreads * sizeof (*gcreq->vtimes)); gcreq->cb = cb; gcreq->queue = q; - threads_vtime_gather_for_wait (&gcreq->nvtimes, gcreq->vtimes); + threads_vtime_gather_for_wait (q->gv, &gcreq->nvtimes, gcreq->vtimes); ddsrt_mutex_lock (&q->lock); q->count++; ddsrt_mutex_unlock (&q->lock); diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index 2c4601d..54601d9 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -36,7 +36,6 @@ #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_ddsi_discovery.h" #include "dds/ddsi/q_radmin.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_lease.h" @@ -50,6 +49,7 @@ #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_debmon.h" #include "dds/ddsi/q_init.h" +#include "dds/ddsi/ddsi_threadmon.h" #include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/ddsi_udp.h" @@ -62,22 +62,22 @@ #include "dds__whc.h" #include "dds/ddsi/ddsi_iid.h" -static void add_peer_addresses (struct addrset *as, const struct config_peer_listelem *list) +static void add_peer_addresses (const struct q_globals *gv, struct addrset *as, const struct config_peer_listelem *list) { while (list) { - add_addresses_to_addrset (as, list->peer, -1, "add_peer_addresses", 0); + add_addresses_to_addrset (gv, as, list->peer, -1, "add_peer_addresses", 0); list = list->next; } } -static int make_uc_sockets (uint32_t * pdisc, uint32_t * pdata, int ppid) +static int make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid) { - if (config.many_sockets_mode == MSM_NO_UNICAST) + if (gv->config.many_sockets_mode == MSM_NO_UNICAST) { assert (ppid == PARTICIPANT_INDEX_NONE); - *pdata = *pdisc = (uint32_t) (config.port_base + config.port_dg * config.domainId.value); - if (config.allowMulticast) + *pdata = *pdisc = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId); + if (gv->config.allowMulticast) { /* FIXME: ugly hack - but we'll fix up after creating the multicast sockets */ return 0; @@ -87,9 +87,9 @@ static int make_uc_sockets (uint32_t * pdisc, uint32_t * pdata, int ppid) if (ppid >= 0) { /* FIXME: verify port numbers are in range instead of truncating them like this */ - int base = config.port_base + (config.port_dg * config.domainId.value) + (ppid * config.port_pg); - *pdisc = (uint32_t) (base + config.port_d1); - *pdata = (uint32_t) (base + config.port_d3); + uint32_t base = gv->config.port_base + (gv->config.port_dg * gv->config.domainId) + ((uint32_t) ppid * gv->config.port_pg); + *pdisc = base + gv->config.port_d1; + *pdata = base + gv->config.port_d3; } else if (ppid == PARTICIPANT_INDEX_NONE) { @@ -98,135 +98,135 @@ static int make_uc_sockets (uint32_t * pdisc, uint32_t * pdata, int ppid) } else { - DDS_FATAL("make_uc_sockets: invalid participant index %d\n", ppid); + DDS_FATAL ("make_uc_sockets: invalid participant index %d\n", ppid); return -1; } - gv.disc_conn_uc = ddsi_factory_create_conn (gv.m_factory, *pdisc, NULL); - if (gv.disc_conn_uc) + gv->disc_conn_uc = ddsi_factory_create_conn (gv->m_factory, *pdisc, NULL); + if (gv->disc_conn_uc) { /* Check not configured to use same unicast port for data and discovery */ if (*pdata != 0 && (*pdata != *pdisc)) { - gv.data_conn_uc = ddsi_factory_create_conn (gv.m_factory, *pdata, NULL); + gv->data_conn_uc = ddsi_factory_create_conn (gv->m_factory, *pdata, NULL); } else { - gv.data_conn_uc = gv.disc_conn_uc; + gv->data_conn_uc = gv->disc_conn_uc; } - if (gv.data_conn_uc == NULL) + if (gv->data_conn_uc == NULL) { - ddsi_conn_free (gv.disc_conn_uc); - gv.disc_conn_uc = NULL; + ddsi_conn_free (gv->disc_conn_uc); + gv->disc_conn_uc = NULL; } else { /* Set unicast locators */ - ddsi_conn_locator (gv.disc_conn_uc, &gv.loc_meta_uc); - ddsi_conn_locator (gv.data_conn_uc, &gv.loc_default_uc); + ddsi_conn_locator (gv->disc_conn_uc, &gv->loc_meta_uc); + ddsi_conn_locator (gv->data_conn_uc, &gv->loc_default_uc); } } - return gv.data_conn_uc ? 0 : -1; + return gv->data_conn_uc ? 0 : -1; } -static void make_builtin_endpoint_xqos (nn_xqos_t *q, const nn_xqos_t *template) +static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) { nn_xqos_copy (q, template); - q->reliability.kind = NN_RELIABLE_RELIABILITY_QOS; - q->reliability.max_blocking_time = nn_to_ddsi_duration (100 * T_MILLISECOND); - q->durability.kind = NN_TRANSIENT_LOCAL_DURABILITY_QOS; + q->reliability.kind = DDS_RELIABILITY_RELIABLE; + q->reliability.max_blocking_time = 100 * T_MILLISECOND; + q->durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL; } -static int set_recvips (void) +static int set_recvips (struct q_globals *gv) { - gv.recvips = NULL; + gv->recvips = NULL; - if (config.networkRecvAddressStrings) + if (gv->config.networkRecvAddressStrings) { - if (ddsrt_strcasecmp (config.networkRecvAddressStrings[0], "all") == 0) + if (ddsrt_strcasecmp (gv->config.networkRecvAddressStrings[0], "all") == 0) { #if DDSRT_HAVE_IPV6 - if (gv.ipv6_link_local) + if (gv->ipv6_link_local) { - DDS_WARNING("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: using 'preferred' instead of 'all' because of IPv6 link-local address\n"); - gv.recvips_mode = RECVIPS_MODE_PREFERRED; + GVWARNING ("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: using 'preferred' instead of 'all' because of IPv6 link-local address\n"); + gv->recvips_mode = RECVIPS_MODE_PREFERRED; } else #endif { - gv.recvips_mode = RECVIPS_MODE_ALL; + gv->recvips_mode = RECVIPS_MODE_ALL; } } - else if (ddsrt_strcasecmp (config.networkRecvAddressStrings[0], "any") == 0) + else if (ddsrt_strcasecmp (gv->config.networkRecvAddressStrings[0], "any") == 0) { #if DDSRT_HAVE_IPV6 - if (gv.ipv6_link_local) + if (gv->ipv6_link_local) { - DDS_ERROR("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: 'any' is unsupported in combination with an IPv6 link-local address\n"); + GVERROR ("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: 'any' is unsupported in combination with an IPv6 link-local address\n"); return -1; } #endif - gv.recvips_mode = RECVIPS_MODE_ANY; + gv->recvips_mode = RECVIPS_MODE_ANY; } - else if (ddsrt_strcasecmp (config.networkRecvAddressStrings[0], "preferred") == 0) + else if (ddsrt_strcasecmp (gv->config.networkRecvAddressStrings[0], "preferred") == 0) { - gv.recvips_mode = RECVIPS_MODE_PREFERRED; + gv->recvips_mode = RECVIPS_MODE_PREFERRED; } - else if (ddsrt_strcasecmp (config.networkRecvAddressStrings[0], "none") == 0) + else if (ddsrt_strcasecmp (gv->config.networkRecvAddressStrings[0], "none") == 0) { - gv.recvips_mode = RECVIPS_MODE_NONE; + gv->recvips_mode = RECVIPS_MODE_NONE; } #if DDSRT_HAVE_IPV6 - else if (gv.ipv6_link_local) + else if (gv->ipv6_link_local) { /* If the configuration explicitly includes the selected interface, treat it as "preferred", else as "none"; warn if interfaces other than the selected one are included. */ int i, have_selected = 0, have_others = 0; - for (i = 0; config.networkRecvAddressStrings[i] != NULL; i++) + for (i = 0; gv->config.networkRecvAddressStrings[i] != NULL; i++) { nn_locator_t loc; - if (ddsi_locator_from_string(&loc, config.networkRecvAddressStrings[i]) != AFSR_OK) + if (ddsi_locator_from_string(gv, &loc, gv->config.networkRecvAddressStrings[i], gv->m_factory) != AFSR_OK) { - DDS_ERROR("%s: not a valid address in DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses\n", config.networkRecvAddressStrings[i]); + GVERROR ("%s: not a valid address in DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses\n", gv->config.networkRecvAddressStrings[i]); return -1; } - if (compare_locators(&loc, &gv.interfaces[gv.selected_interface].loc) == 0) + if (compare_locators(&loc, &gv->interfaces[gv->selected_interface].loc) == 0) have_selected = 1; else have_others = 1; } - gv.recvips_mode = have_selected ? RECVIPS_MODE_PREFERRED : RECVIPS_MODE_NONE; + gv->recvips_mode = have_selected ? RECVIPS_MODE_PREFERRED : RECVIPS_MODE_NONE; if (have_others) { - DDS_WARNING("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: using 'preferred' because of IPv6 local address\n"); + GVWARNING ("DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses: using 'preferred' because of IPv6 local address\n"); } } #endif else { - struct config_in_addr_node **recvnode = &gv.recvips; + struct config_in_addr_node **recvnode = &gv->recvips; int i, j; - gv.recvips_mode = RECVIPS_MODE_SOME; - for (i = 0; config.networkRecvAddressStrings[i] != NULL; i++) + gv->recvips_mode = RECVIPS_MODE_SOME; + for (i = 0; gv->config.networkRecvAddressStrings[i] != NULL; i++) { nn_locator_t loc; - if (ddsi_locator_from_string(&loc, config.networkRecvAddressStrings[i]) != AFSR_OK) + if (ddsi_locator_from_string(gv, &loc, gv->config.networkRecvAddressStrings[i], gv->m_factory) != AFSR_OK) { - DDS_ERROR("%s: not a valid address in DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses\n", config.networkRecvAddressStrings[i]); + GVERROR ("%s: not a valid address in DDSI2EService/General/MulticastRecvNetworkInterfaceAddresses\n", gv->config.networkRecvAddressStrings[i]); return -1; } - for (j = 0; j < gv.n_interfaces; j++) + for (j = 0; j < gv->n_interfaces; j++) { - if (compare_locators(&loc, &gv.interfaces[j].loc) == 0) + if (compare_locators(&loc, &gv->interfaces[j].loc) == 0) break; } - if (j == gv.n_interfaces) + if (j == gv->n_interfaces) { - DDS_ERROR("No interface bound to requested address '%s'\n", config.networkRecvAddressStrings[i]); + GVERROR ("No interface bound to requested address '%s'\n", gv->config.networkRecvAddressStrings[i]); return -1; } *recvnode = ddsrt_malloc (sizeof (struct config_in_addr_node)); @@ -245,25 +245,25 @@ static int set_recvips (void) * return -1 : ddsi is unicast, but 'mc' indicates it expects multicast * return 0 : ddsi is multicast, but 'mc' indicates it expects unicast * The return 0 means that the possible changes in 'loc' can be ignored. */ -static int string_to_default_locator (nn_locator_t *loc, const char *string, uint32_t port, int mc, const char *tag) +static int string_to_default_locator (const struct q_globals *gv, nn_locator_t *loc, const char *string, uint32_t port, int mc, const char *tag) { if (strspn (string, " \t") == strlen (string)) { /* string consisting of just spaces and/or tabs (that includes the empty string) is ignored */ return 0; } - switch (ddsi_locator_from_string(loc, string)) + switch (ddsi_locator_from_string(gv, loc, string, gv->m_factory)) { case AFSR_OK: break; case AFSR_INVALID: - DDS_ERROR("%s: not a valid address (%s)\n", string, tag); + GVERROR ("%s: not a valid address (%s)\n", string, tag); return -1; case AFSR_UNKNOWN: - DDS_ERROR("%s: address name resolution failure (%s)\n", string, tag); + GVERROR ("%s: address name resolution failure (%s)\n", string, tag); return -1; case AFSR_MISMATCH: - DDS_ERROR("%s: invalid address kind (%s)\n", string, tag); + GVERROR ("%s: invalid address kind (%s)\n", string, tag); return -1; } if (port != 0 && !is_unspec_locator(loc)) @@ -274,28 +274,28 @@ static int string_to_default_locator (nn_locator_t *loc, const char *string, uin if (mc >= 0) { const char *rel = mc ? "must" : "may not"; - const int ismc = is_unspec_locator (loc) || ddsi_is_mcaddr (loc); + const int ismc = is_unspec_locator (loc) || ddsi_is_mcaddr (gv, loc); if (mc != ismc) { - DDS_ERROR("%s: %s %s be the unspecified address or a multicast address\n", string, tag, rel); + GVERROR ("%s: %s %s be the unspecified address or a multicast address\n", string, tag, rel); return -1; } } return 1; } -static int set_spdp_address (void) +static int set_spdp_address (struct q_globals *gv) { - const uint32_t port = (uint32_t) (config.port_base + config.port_dg * config.domainId.value + config.port_d0); + const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0); int rc = 0; /* FIXME: FIXME: FIXME: */ - gv.loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID; - if (strcmp (config.spdpMulticastAddressString, "239.255.0.1") != 0) + gv->loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID; + if (strcmp (gv->config.spdpMulticastAddressString, "239.255.0.1") != 0) { - if ((rc = string_to_default_locator (&gv.loc_spdp_mc, config.spdpMulticastAddressString, port, 1, "SPDP address")) < 0) + if ((rc = string_to_default_locator (gv, &gv->loc_spdp_mc, gv->config.spdpMulticastAddressString, port, 1, "SPDP address")) < 0) return rc; } - if (rc == 0 && gv.m_factory->m_connless) /* FIXME: connless the right one? */ + if (rc == 0 && gv->m_factory->m_connless) /* FIXME: connless the right one? */ { /* There isn't a standard IPv6 multicast group for DDSI. For some reason, node-local multicast addresses seem to be @@ -303,80 +303,80 @@ static int set_spdp_address (void) instead do link-local. I suppose we could use the hop limit to make it node-local. If other hosts reach us in some way, we'll of course respond. */ - rc = string_to_default_locator (&gv.loc_spdp_mc, gv.m_factory->m_default_spdp_address, port, 1, "SPDP address"); + rc = string_to_default_locator (gv, &gv->loc_spdp_mc, gv->m_factory->m_default_spdp_address, port, 1, "SPDP address"); assert (rc > 0); } #ifdef DDSI_INCLUDE_SSM - if (gv.loc_spdp_mc.kind != NN_LOCATOR_KIND_INVALID && ddsi_is_ssm_mcaddr (&gv.loc_spdp_mc)) + if (gv->loc_spdp_mc.kind != NN_LOCATOR_KIND_INVALID && ddsi_is_ssm_mcaddr (gv, &gv->loc_spdp_mc)) { - DDS_ERROR("%s: SPDP address may not be an SSM address\n", config.spdpMulticastAddressString); + GVERROR ("%s: SPDP address may not be an SSM address\n", gv->config.spdpMulticastAddressString); return -1; } #endif return 0; } -static int set_default_mc_address (void) +static int set_default_mc_address (struct q_globals *gv) { - const uint32_t port = (uint32_t) (config.port_base + config.port_dg * config.domainId.value + config.port_d2); + const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2); int rc; - if (!config.defaultMulticastAddressString) - gv.loc_default_mc = gv.loc_spdp_mc; - else if ((rc = string_to_default_locator (&gv.loc_default_mc, config.defaultMulticastAddressString, port, 1, "default multicast address")) < 0) + if (!gv->config.defaultMulticastAddressString) + gv->loc_default_mc = gv->loc_spdp_mc; + else if ((rc = string_to_default_locator (gv, &gv->loc_default_mc, gv->config.defaultMulticastAddressString, port, 1, "default multicast address")) < 0) return rc; else if (rc == 0) - gv.loc_default_mc = gv.loc_spdp_mc; - gv.loc_meta_mc = gv.loc_default_mc; + gv->loc_default_mc = gv->loc_spdp_mc; + gv->loc_meta_mc = gv->loc_default_mc; return 0; } -static int set_ext_address_and_mask (void) +static int set_ext_address_and_mask (struct q_globals *gv) { nn_locator_t loc; int rc; - if (!config.externalAddressString) - gv.extloc = gv.ownloc; - else if ((rc = string_to_default_locator (&loc, config.externalAddressString, 0, 0, "external address")) < 0) + if (!gv->config.externalAddressString) + gv->extloc = gv->ownloc; + else if ((rc = string_to_default_locator (gv, &loc, gv->config.externalAddressString, 0, 0, "external address")) < 0) return rc; else if (rc == 0) { - DDS_WARNING("Ignoring ExternalNetworkAddress %s\n", config.externalAddressString); - gv.extloc = gv.ownloc; + GVWARNING ("Ignoring ExternalNetworkAddress %s\n", gv->config.externalAddressString); + gv->extloc = gv->ownloc; } else { - gv.extloc = loc; + gv->extloc = loc; } - if (!config.externalMaskString || strcmp (config.externalMaskString, "0.0.0.0") == 0) + if (!gv->config.externalMaskString || strcmp (gv->config.externalMaskString, "0.0.0.0") == 0) { - memset(&gv.extmask.address, 0, sizeof(gv.extmask.address)); - gv.extmask.kind = NN_LOCATOR_KIND_INVALID; - gv.extmask.port = NN_LOCATOR_PORT_INVALID; + memset(&gv->extmask.address, 0, sizeof(gv->extmask.address)); + gv->extmask.kind = NN_LOCATOR_KIND_INVALID; + gv->extmask.port = NN_LOCATOR_PORT_INVALID; } - else if (config.transport_selector != TRANS_UDP) + else if (gv->config.transport_selector != TRANS_UDP) { - DDS_ERROR("external network masks only supported in IPv4 mode\n"); + GVERROR ("external network masks only supported in IPv4 mode\n"); return -1; } else { - if ((rc = string_to_default_locator (&gv.extmask, config.externalMaskString, 0, -1, "external mask")) < 0) + if ((rc = string_to_default_locator (gv, &gv->extmask, gv->config.externalMaskString, 0, -1, "external mask")) < 0) return rc; } return 0; } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -static int known_channel_p (const char *name) +static int known_channel_p (const struct q_globals *gv, const char *name) { const struct config_channel_listelem *c; - for (c = config.channels; c; c = c->next) + for (c = gv->config.channels; c; c = c->next) if (strcmp (name, c->name) == 0) return 1; return 0; } #endif -static int check_thread_properties (void) +static int check_thread_properties (const struct q_globals *gv) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", NULL }; @@ -386,7 +386,7 @@ static int check_thread_properties (void) #endif const struct config_thread_properties_listelem *e; int ok = 1, i; - for (e = config.thread_properties; e; e = e->next) + for (e = gv->config.thread_properties; e; e = e->next) { for (i = 0; fixed[i]; i++) if (strcmp (fixed[i], e->name) == 0) @@ -399,16 +399,16 @@ static int check_thread_properties (void) for (i = 0; chanprefix[i]; i++) { size_t n = strlen (chanprefix[i]); - if (strncmp (chanprefix[i], e->name, n) == 0 && known_channel_p (e->name + n)) + if (strncmp (chanprefix[i], e->name, n) == 0 && known_channel_p (gv, e->name + n)) break; } if (chanprefix[i] == NULL) { - DDS_ERROR("config: DDSI2Service/Threads/Thread[@name=\"%s\"]: unknown thread\n", e->name); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "config: DDSI2Service/Threads/Thread[@name=\"%s\"]: unknown thread\n", e->name); ok = 0; } #else - DDS_ERROR("config: DDSI2Service/Threads/Thread[@name=\"%s\"]: unknown thread\n", e->name); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "config: DDSI2Service/Threads/Thread[@name=\"%s\"]: unknown thread\n", e->name); ok = 0; #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ } @@ -416,45 +416,43 @@ static int check_thread_properties (void) return ok; } -DDSRT_WARNING_MSVC_OFF(4996); -int rtps_config_open (void) +int rtps_config_open_trace (struct q_globals *gv) { - int status; + DDSRT_WARNING_MSVC_OFF(4996); + int status; - if (config.tracingOutputFileName == NULL || *config.tracingOutputFileName == 0 || config.enabled_logcats == 0) - { - config.enabled_logcats = 0; - config.tracingOutputFile = NULL; - status = 1; - } - else if (ddsrt_strcasecmp (config.tracingOutputFileName, "stdout") == 0) - { - config.tracingOutputFile = stdout; - status = 1; - } - else if (ddsrt_strcasecmp (config.tracingOutputFileName, "stderr") == 0) - { - config.tracingOutputFile = stderr; - status = 1; - } - else if ((config.tracingOutputFile = fopen (config.tracingOutputFileName, config.tracingAppendToFile ? "a" : "w")) == NULL) - { - DDS_ERROR("%s: cannot open for writing\n", config.tracingOutputFileName); - status = 0; - } - else - { - status = 1; - } + if (gv->config.tracefile == NULL || *gv->config.tracefile == 0 || gv->config.tracemask == 0) + { + gv->config.tracemask = 0; + gv->config.tracefp = NULL; + status = 1; + } + else if (ddsrt_strcasecmp (gv->config.tracefile, "stdout") == 0) + { + gv->config.tracefp = stdout; + status = 1; + } + else if (ddsrt_strcasecmp (gv->config.tracefile, "stderr") == 0) + { + gv->config.tracefp = stderr; + status = 1; + } + else if ((gv->config.tracefp = fopen (gv->config.tracefile, gv->config.tracingAppendToFile ? "a" : "w")) == NULL) + { + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "%s: cannot open for writing\n", gv->config.tracefile); + status = 0; + } + else + { + status = 1; + } - dds_set_log_mask(config.enabled_logcats); - dds_set_trace_file(config.tracingOutputFile); - - return status; + dds_log_cfg_init (&gv->logconfig, gv->config.domainId, gv->config.tracemask, stderr, gv->config.tracefp); + return status; + DDSRT_WARNING_MSVC_ON(4996); } -DDSRT_WARNING_MSVC_ON(4996); -int rtps_config_prep (struct cfgst *cfgst) +int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS unsigned num_channels = 0; @@ -462,17 +460,17 @@ int rtps_config_prep (struct cfgst *cfgst) #endif /* retry_on_reject_duration default is dependent on late_ack_mode and responsiveness timeout, so fix up */ - if (config.whc_init_highwater_mark.isdefault) - config.whc_init_highwater_mark.value = config.whc_lowwater_mark; - if (config.whc_highwater_mark < config.whc_lowwater_mark || - config.whc_init_highwater_mark.value < config.whc_lowwater_mark || - config.whc_init_highwater_mark.value > config.whc_highwater_mark) + if (gv->config.whc_init_highwater_mark.isdefault) + gv->config.whc_init_highwater_mark.value = gv->config.whc_lowwater_mark; + if (gv->config.whc_highwater_mark < gv->config.whc_lowwater_mark || + gv->config.whc_init_highwater_mark.value < gv->config.whc_lowwater_mark || + gv->config.whc_init_highwater_mark.value > gv->config.whc_highwater_mark) { - DDS_ERROR("Invalid watermark settings\n"); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "Invalid watermark settings\n"); goto err_config_late_error; } - if (config.besmode == BESMODE_MINIMAL && config.many_sockets_mode == MSM_MANY_UNICAST) + if (gv->config.besmode == BESMODE_MINIMAL && gv->config.many_sockets_mode == MSM_MANY_UNICAST) { /* These two are incompatible because minimal bes mode can result in implicitly creating proxy participants inheriting the @@ -480,41 +478,40 @@ int rtps_config_prep (struct cfgst *cfgst) inherited by readers/writers), but in many sockets mode each participant has its own socket, and therefore unique address set */ - DDS_ERROR ("Minimal built-in endpoint set mode and ManySocketsMode are incompatible\n"); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "Minimal built-in endpoint set mode and ManySocketsMode are incompatible\n"); goto err_config_late_error; } /* Dependencies between default values is not handled - automatically by the config processing (yet) */ - if (config.many_sockets_mode == MSM_MANY_UNICAST) + automatically by the gv->config processing (yet) */ + if (gv->config.many_sockets_mode == MSM_MANY_UNICAST) { - if (config.max_participants == 0) - config.max_participants = 100; + if (gv->config.max_participants == 0) + gv->config.max_participants = 100; } - if (config.max_queued_rexmit_bytes == 0) + if (gv->config.max_queued_rexmit_bytes == 0) { #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING - if (config.auxiliary_bandwidth_limit == 0) - config.max_queued_rexmit_bytes = 2147483647u; + if (gv->config.auxiliary_bandwidth_limit == 0) + gv->config.max_queued_rexmit_bytes = 2147483647u; else { - double max = (double) config.auxiliary_bandwidth_limit * ((double) config.nack_delay / 1e9); + double max = (double) gv->config.auxiliary_bandwidth_limit * ((double) gv->config.nack_delay / 1e9); if (max < 0) { - DDS_ERROR ("AuxiliaryBandwidthLimit * NackDelay = %g bytes is insane\n", max); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId.value, "AuxiliaryBandwidthLimit * NackDelay = %g bytes is insane\n", max); goto err_config_late_error; } - config.max_queued_rexmit_bytes = max > 2147483647.0 ? 2147483647u : (unsigned) max; + gv->config.max_queued_rexmit_bytes = max > 2147483647.0 ? 2147483647u : (unsigned) max; } #else - config.max_queued_rexmit_bytes = 2147483647u; + gv->config.max_queued_rexmit_bytes = 2147483647u; #endif /* DDSI_INCLUDE_BANDWIDTH_LIMITING */ } /* Verify thread properties refer to defined threads */ - if (!check_thread_properties ()) + if (!check_thread_properties (gv)) { - DDS_TRACE ("Could not initialise configuration\n"); goto err_config_late_error; } @@ -524,7 +521,7 @@ int rtps_config_prep (struct cfgst *cfgst) determine the correct number of threads. Also fix fields if at default, and check for some known IPv4/IPv6 "compatibility" issues */ - struct config_channel_listelem *chptr = config.channels; + struct config_channel_listelem *chptr = gv->config.channels; int error = 0; while (chptr) @@ -536,9 +533,9 @@ int rtps_config_prep (struct cfgst *cfgst) num_channels++; num_channel_threads += 2; /* xmit and dqueue */ - if (config.transport_selector != TRANS_UDP && chptr->diffserv_field != 0) + if (gv->config.transport_selector != TRANS_UDP && chptr->diffserv_field != 0) { - DDS_ERROR ("channel %s specifies IPv4 DiffServ settings which is incompatible with IPv6 use\n", chptr->name); + DDS_ILOG (DDS_LC_ERROR, gv->config.domainId.value, "channel %s specifies IPv4 DiffServ settings which is incompatible with IPv6 use\n", chptr->name); error = 1; } @@ -557,11 +554,9 @@ int rtps_config_prep (struct cfgst *cfgst) } #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ - /* Open tracing file after all possible config errors have been - printed */ - if (! rtps_config_open ()) + /* Open tracing file after all possible config errors have been printed */ + if (! rtps_config_open_trace (gv)) { - DDS_TRACE ("Could not initialise configuration\n"); goto err_config_late_error; } @@ -570,22 +565,25 @@ int rtps_config_prep (struct cfgst *cfgst) lease, gc, debmon; once thread state admin has been inited, upgrade the main thread one participating in the thread tracking stuff as if it had been created using create_thread(). */ - +#if 0 /* FIXME: threads are per-process, not per-domain */ { /* Temporary: thread states for each application thread is managed using thread_states structure */ #define USER_MAX_THREADS 50 #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - const unsigned max_threads = 9 + USER_MAX_THREADS + num_channel_threads + config.ddsi2direct_max_threads; + const unsigned max_threads = 9 + USER_MAX_THREADS + num_channel_threads + gv->config.ddsi2direct_max_threads; #else - const unsigned max_threads = 11 + USER_MAX_THREADS + config.ddsi2direct_max_threads; + const unsigned max_threads = 11 + USER_MAX_THREADS + gv->config.ddsi2direct_max_threads; #endif thread_states_init (max_threads); } +#endif - /* Now the per-thread-log-buffers are set up, so print the configuration */ - config_print_cfgst (cfgst); + /* Now the per-thread-log-buffers are set up, so print the configuration. After this there + is no value to the source information for the various configuration elements, so free those. */ + config_print_cfgst (cfgst, &gv->logconfig); + config_free_source_info (cfgst); return 0; err_config_late_error: @@ -593,6 +591,7 @@ err_config_late_error: } struct joinleave_spdp_defmcip_helper_arg { + struct q_globals *gv; int errcount; int dojoin; }; @@ -600,44 +599,47 @@ struct joinleave_spdp_defmcip_helper_arg { static void joinleave_spdp_defmcip_helper (const nn_locator_t *loc, void *varg) { struct joinleave_spdp_defmcip_helper_arg *arg = varg; - if (!ddsi_is_mcaddr (loc)) + if (!ddsi_is_mcaddr (arg->gv, loc)) return; #ifdef DDSI_INCLUDE_SSM /* Can't join SSM until we actually have a source */ - if (ddsi_is_ssm_mcaddr (loc)) + if (ddsi_is_ssm_mcaddr (arg->gv, loc)) return; #endif if (arg->dojoin) { - if (ddsi_join_mc (gv.disc_conn_mc, NULL, loc) < 0 || ddsi_join_mc (gv.data_conn_mc, NULL, loc) < 0) + if (ddsi_join_mc (arg->gv, arg->gv->mship, arg->gv->disc_conn_mc, NULL, loc) < 0 || + ddsi_join_mc (arg->gv, arg->gv->mship, arg->gv->data_conn_mc, NULL, loc) < 0) arg->errcount++; } else { - if (ddsi_leave_mc (gv.disc_conn_mc, NULL, loc) < 0 || ddsi_leave_mc (gv.data_conn_mc, NULL, loc) < 0) + if (ddsi_leave_mc (arg->gv, arg->gv->mship, arg->gv->disc_conn_mc, NULL, loc) < 0 || + ddsi_leave_mc (arg->gv, arg->gv->mship, arg->gv->data_conn_mc, NULL, loc) < 0) arg->errcount++; } } -int joinleave_spdp_defmcip (int dojoin) +int joinleave_spdp_defmcip (struct q_globals *gv, int dojoin) { /* Addrset provides an easy way to filter out duplicates */ struct joinleave_spdp_defmcip_helper_arg arg; struct addrset *as = new_addrset (); + arg.gv = gv; arg.errcount = 0; arg.dojoin = dojoin; - if (config.allowMulticast & AMC_SPDP) - add_to_addrset (as, &gv.loc_spdp_mc); - if (config.allowMulticast & ~AMC_SPDP) - add_to_addrset (as, &gv.loc_default_mc); + if (gv->config.allowMulticast & AMC_SPDP) + add_to_addrset (gv, as, &gv->loc_spdp_mc); + if (gv->config.allowMulticast & ~AMC_SPDP) + add_to_addrset (gv, as, &gv->loc_default_mc); addrset_forall (as, joinleave_spdp_defmcip_helper, &arg); unref_addrset (as); if (arg.errcount) { - DDS_ERROR("rtps_init: failed to join multicast groups for domain %"PRId32" participant %d\n", config.domainId.value, config.participantIndex); + GVERROR ("rtps_init: failed to join multicast groups for domain %"PRIu32" participant %d\n", gv->config.domainId, gv->config.participantIndex); return -1; } return 0; } -int create_multicast_sockets(void) +int create_multicast_sockets (struct q_globals *gv) { ddsi_tran_qos_t qos = ddsi_tran_create_qos (); ddsi_tran_conn_t disc, data; @@ -645,26 +647,26 @@ int create_multicast_sockets(void) qos->m_multicast = 1; /* FIXME: should check for overflow */ - port = (uint32_t) (config.port_base + config.port_dg * config.domainId.value + config.port_d0); - if ((disc = ddsi_factory_create_conn (gv.m_factory, port, qos)) == NULL) + port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0); + if ((disc = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL) goto err_disc; - if (config.many_sockets_mode == MSM_NO_UNICAST) + if (gv->config.many_sockets_mode == MSM_NO_UNICAST) { /* FIXME: not quite logical to tie this to "no unicast" */ data = disc; } else { - port = (uint32_t) (config.port_base + config.port_dg * config.domainId.value + config.port_d2); - if ((data = ddsi_factory_create_conn (gv.m_factory, port, qos)) == NULL) + port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2); + if ((data = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL) goto err_data; } ddsi_tran_free_qos (qos); - gv.disc_conn_mc = disc; - gv.data_conn_mc = data; - DDS_TRACE("Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n", - ddsi_conn_port (gv.disc_conn_mc), ddsi_conn_port (gv.data_conn_mc)); + gv->disc_conn_mc = disc; + gv->data_conn_mc = data; + GVTRACE ("Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n", + ddsi_conn_port (gv->disc_conn_mc), ddsi_conn_port (gv->data_conn_mc)); return 1; err_data: @@ -674,53 +676,54 @@ err_disc: return 0; } -static void rtps_term_prep (void) +static void rtps_term_prep (struct q_globals *gv) { /* Stop all I/O */ - ddsrt_mutex_lock (&gv.lock); - if (gv.rtps_keepgoing) + ddsrt_mutex_lock (&gv->lock); + if (ddsrt_atomic_ld32 (&gv->rtps_keepgoing)) { - gv.rtps_keepgoing = 0; /* so threads will stop once they get round to checking */ + ddsrt_atomic_st32 (&gv->rtps_keepgoing, 0); /* so threads will stop once they get round to checking */ ddsrt_atomic_fence (); /* can't wake up throttle_writer, currently, but it'll check every few seconds */ - trigger_recv_threads (); + trigger_recv_threads (gv); } - ddsrt_mutex_unlock (&gv.lock); + ddsrt_mutex_unlock (&gv->lock); } struct wait_for_receive_threads_helper_arg { + struct q_globals *gv; unsigned count; }; static void wait_for_receive_threads_helper (struct xevent *xev, void *varg, nn_mtime_t tnow) { struct wait_for_receive_threads_helper_arg * const arg = varg; - if (arg->count++ == config.recv_thread_stop_maxretries) + if (arg->count++ == arg->gv->config.recv_thread_stop_maxretries) abort (); - trigger_recv_threads (); + trigger_recv_threads (arg->gv); resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND)); } -static void wait_for_receive_threads (void) +static void wait_for_receive_threads (struct q_globals *gv) { struct xevent *trigev; - unsigned i; struct wait_for_receive_threads_helper_arg cbarg; + cbarg.gv = gv; cbarg.count = 0; - if ((trigev = qxev_callback (add_duration_to_mtime (now_mt (), T_SECOND), wait_for_receive_threads_helper, &cbarg)) == NULL) + if ((trigev = qxev_callback (gv->xevents, add_duration_to_mtime (now_mt (), T_SECOND), wait_for_receive_threads_helper, &cbarg)) == NULL) { /* retrying is to deal a packet geting lost because the socket buffer is full or because the macOS firewall (and perhaps others) likes to ask if the process is allowed to receive data, dropping the packets until the user approves. */ - DDS_WARNING("wait_for_receive_threads: failed to schedule periodic triggering of the receive threads to deal with packet loss\n"); + GVWARNING ("wait_for_receive_threads: failed to schedule periodic triggering of the receive threads to deal with packet loss\n"); } - for (i = 0; i < gv.n_recv_threads; i++) + for (uint32_t i = 0; i < gv->n_recv_threads; i++) { - if (gv.recv_threads[i].ts) + if (gv->recv_threads[i].ts) { - join_thread (gv.recv_threads[i].ts); + join_thread (gv->recv_threads[i].ts); /* setting .ts to NULL helps in sanity checking */ - gv.recv_threads[i].ts = NULL; + gv->recv_threads[i].ts = NULL; } } if (trigev) @@ -729,7 +732,7 @@ static void wait_for_receive_threads (void) } } -static struct ddsi_sertopic *make_special_topic (uint16_t enc_id, const struct ddsi_serdata_ops *ops) +static struct ddsi_sertopic *make_special_topic (struct serdatapool *serpool, uint16_t enc_id, const struct ddsi_serdata_ops *ops) { /* FIXME: two things (at least) - it claims there is a key, but the underlying type description is missing @@ -741,91 +744,88 @@ static struct ddsi_sertopic *make_special_topic (uint16_t enc_id, const struct d (kinda natural if they stop being "default" ones) */ struct ddsi_sertopic_default *st = ddsrt_malloc (sizeof (*st)); memset (st, 0, sizeof (*st)); - ddsrt_atomic_st32 (&st->c.refc, 1); - st->c.ops = &ddsi_sertopic_ops_default; - st->c.serdata_ops = ops; - st->c.serdata_basehash = ddsi_sertopic_compute_serdata_basehash (st->c.serdata_ops); - st->c.iid = ddsi_iid_gen (); + ddsi_sertopic_init_anon (&st->c, &ddsi_sertopic_ops_default, ops, false); st->native_encoding_identifier = enc_id; + st->serpool = serpool; st->nkeys = 1; - return (struct ddsi_sertopic *)st; + return (struct ddsi_sertopic *) st; } -static void make_special_topics (void) +static void make_special_topics (struct q_globals *gv) { - gv.plist_topic = make_special_topic (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? PL_CDR_LE : PL_CDR_BE, &ddsi_serdata_ops_plist); - gv.rawcdr_topic = make_special_topic (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE, &ddsi_serdata_ops_rawcdr); + gv->plist_topic = make_special_topic (gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? PL_CDR_LE : PL_CDR_BE, &ddsi_serdata_ops_plist); + gv->rawcdr_topic = make_special_topic (gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE, &ddsi_serdata_ops_rawcdr); } -static void free_special_topics (void) +static void free_special_topics (struct q_globals *gv) { - ddsi_sertopic_unref (gv.plist_topic); - ddsi_sertopic_unref (gv.rawcdr_topic); + ddsi_sertopic_unref (gv->plist_topic); + ddsi_sertopic_unref (gv->rawcdr_topic); } -static int setup_and_start_recv_threads (void) +static int setup_and_start_recv_threads (struct q_globals *gv) { - unsigned i; - for (i = 0; i < MAX_RECV_THREADS; i++) + for (uint32_t i = 0; i < MAX_RECV_THREADS; i++) { - gv.recv_threads[i].ts = NULL; - gv.recv_threads[i].arg.mode = RTM_SINGLE; - gv.recv_threads[i].arg.rbpool = NULL; - gv.recv_threads[i].arg.u.single.loc = NULL; - gv.recv_threads[i].arg.u.single.conn = NULL; + gv->recv_threads[i].ts = NULL; + gv->recv_threads[i].arg.mode = RTM_SINGLE; + gv->recv_threads[i].arg.rbpool = NULL; + gv->recv_threads[i].arg.gv = gv; + gv->recv_threads[i].arg.u.single.loc = NULL; + gv->recv_threads[i].arg.u.single.conn = NULL; } /* First thread always uses a waitset and gobbles up all sockets not handled by dedicated threads - FIXME: MSM_NO_UNICAST mode with UDP probably doesn't even need this one to use a waitset */ - gv.n_recv_threads = 1; - gv.recv_threads[0].name = "recv"; - gv.recv_threads[0].arg.mode = RTM_MANY; - if (gv.m_factory->m_connless && config.many_sockets_mode != MSM_NO_UNICAST && config.multiple_recv_threads) + gv->n_recv_threads = 1; + gv->recv_threads[0].name = "recv"; + gv->recv_threads[0].arg.mode = RTM_MANY; + if (gv->m_factory->m_connless && gv->config.many_sockets_mode != MSM_NO_UNICAST && gv->config.multiple_recv_threads) { - if (ddsi_is_mcaddr (&gv.loc_default_mc) && !ddsi_is_ssm_mcaddr (&gv.loc_default_mc) && (config.allowMulticast & AMC_ASM)) + if (ddsi_is_mcaddr (gv, &gv->loc_default_mc) && !ddsi_is_ssm_mcaddr (gv, &gv->loc_default_mc) && (gv->config.allowMulticast & AMC_ASM)) { /* Multicast enabled, but it isn't an SSM address => handle data multicasts on a separate thread (the trouble with SSM addresses is that we only join matching writers, which our own sockets typically would not be) */ - gv.recv_threads[gv.n_recv_threads].name = "recvMC"; - gv.recv_threads[gv.n_recv_threads].arg.mode = RTM_SINGLE; - gv.recv_threads[gv.n_recv_threads].arg.u.single.conn = gv.data_conn_mc; - gv.recv_threads[gv.n_recv_threads].arg.u.single.loc = &gv.loc_default_mc; - ddsi_conn_disable_multiplexing (gv.data_conn_mc); - gv.n_recv_threads++; + gv->recv_threads[gv->n_recv_threads].name = "recvMC"; + gv->recv_threads[gv->n_recv_threads].arg.mode = RTM_SINGLE; + gv->recv_threads[gv->n_recv_threads].arg.u.single.conn = gv->data_conn_mc; + gv->recv_threads[gv->n_recv_threads].arg.u.single.loc = &gv->loc_default_mc; + ddsi_conn_disable_multiplexing (gv->data_conn_mc); + gv->n_recv_threads++; } - if (config.many_sockets_mode == MSM_SINGLE_UNICAST) + if (gv->config.many_sockets_mode == MSM_SINGLE_UNICAST) { /* No per-participant sockets => handle data unicasts on a separate thread as well */ - gv.recv_threads[gv.n_recv_threads].name = "recvUC"; - gv.recv_threads[gv.n_recv_threads].arg.mode = RTM_SINGLE; - gv.recv_threads[gv.n_recv_threads].arg.u.single.conn = gv.data_conn_uc; - gv.recv_threads[gv.n_recv_threads].arg.u.single.loc = &gv.loc_default_uc; - ddsi_conn_disable_multiplexing (gv.data_conn_uc); - gv.n_recv_threads++; + gv->recv_threads[gv->n_recv_threads].name = "recvUC"; + gv->recv_threads[gv->n_recv_threads].arg.mode = RTM_SINGLE; + gv->recv_threads[gv->n_recv_threads].arg.u.single.conn = gv->data_conn_uc; + gv->recv_threads[gv->n_recv_threads].arg.u.single.loc = &gv->loc_default_uc; + ddsi_conn_disable_multiplexing (gv->data_conn_uc); + gv->n_recv_threads++; } } - assert (gv.n_recv_threads <= MAX_RECV_THREADS); + assert (gv->n_recv_threads <= MAX_RECV_THREADS); /* For each thread, create rbufpool and waitset if needed, then start it */ - for (i = 0; i < gv.n_recv_threads; i++) + for (uint32_t i = 0; i < gv->n_recv_threads; i++) { /* We create the rbufpool for the receive thread, and so we'll become the initial owner thread. The receive thread will change it before it does anything with it. */ - if ((gv.recv_threads[i].arg.rbpool = nn_rbufpool_new (config.rbuf_size, config.rmsg_chunk_size)) == NULL) + if ((gv->recv_threads[i].arg.rbpool = nn_rbufpool_new (&gv->logconfig, gv->config.rbuf_size, gv->config.rmsg_chunk_size)) == NULL) { - DDS_ERROR("rtps_init: can't allocate receive buffer pool for thread %s\n", gv.recv_threads[i].name); + GVERROR ("rtps_init: can't allocate receive buffer pool for thread %s\n", gv->recv_threads[i].name); goto fail; } - if (gv.recv_threads[i].arg.mode == RTM_MANY) + if (gv->recv_threads[i].arg.mode == RTM_MANY) { - if ((gv.recv_threads[i].arg.u.many.ws = os_sockWaitsetNew ()) == NULL) + if ((gv->recv_threads[i].arg.u.many.ws = os_sockWaitsetNew ()) == NULL) { - DDS_ERROR("rtps_init: can't allocate sock waitset for thread %s\n", gv.recv_threads[i].name); + GVERROR ("rtps_init: can't allocate sock waitset for thread %s\n", gv->recv_threads[i].name); goto fail; } } - if (create_thread (&gv.recv_threads[i].ts, gv.recv_threads[i].name, recv_thread, &gv.recv_threads[i].arg) != DDS_RETCODE_OK) + if (create_thread (&gv->recv_threads[i].ts, gv, gv->recv_threads[i].name, recv_thread, &gv->recv_threads[i].arg) != DDS_RETCODE_OK) { - DDS_ERROR("rtps_init: failed to start thread %s\n", gv.recv_threads[i].name); + GVERROR ("rtps_init: failed to start thread %s\n", gv->recv_threads[i].name); goto fail; } } @@ -833,142 +833,156 @@ static int setup_and_start_recv_threads (void) fail: /* to trigger any threads we already started to stop - xevent thread has already been started */ - rtps_term_prep (); - wait_for_receive_threads (); - for (i = 0; i < gv.n_recv_threads; i++) + rtps_term_prep (gv); + wait_for_receive_threads (gv); + for (uint32_t i = 0; i < gv->n_recv_threads; i++) { - if (gv.recv_threads[i].arg.mode == RTM_MANY && gv.recv_threads[i].arg.u.many.ws) - os_sockWaitsetFree (gv.recv_threads[i].arg.u.many.ws); - if (gv.recv_threads[i].arg.rbpool) - nn_rbufpool_free (gv.recv_threads[i].arg.rbpool); + if (gv->recv_threads[i].arg.mode == RTM_MANY && gv->recv_threads[i].arg.u.many.ws) + os_sockWaitsetFree (gv->recv_threads[i].arg.u.many.ws); + if (gv->recv_threads[i].arg.rbpool) + nn_rbufpool_free (gv->recv_threads[i].arg.rbpool); } return -1; } -int rtps_init (void) +int rtps_init (struct q_globals *gv) { uint32_t port_disc_uc = 0; uint32_t port_data_uc = 0; bool mc_available = true; - ddsi_plugin_init (); - ddsi_iid_init (); + gv->tstart = now (); /* wall clock time, used in logs */ - gv.tstart = now (); /* wall clock time, used in logs */ + nn_plist_init_tables (); - gv.disc_conn_uc = NULL; - gv.data_conn_uc = NULL; - gv.disc_conn_mc = NULL; - gv.data_conn_mc = NULL; - gv.tev_conn = NULL; - gv.listener = NULL; - gv.thread_pool = NULL; - gv.debmon = NULL; + gv->disc_conn_uc = NULL; + gv->data_conn_uc = NULL; + gv->disc_conn_mc = NULL; + gv->data_conn_mc = NULL; + gv->tev_conn = NULL; + gv->listener = NULL; + gv->thread_pool = NULL; + gv->debmon = NULL; - /* Print start time for referencing relative times in the remainder - of the DDS_LOG. */ + /* Print start time for referencing relative times in the remainder of the DDS_LOG. */ { - int sec = (int) (gv.tstart.v / 1000000000); - int usec = (int) (gv.tstart.v % 1000000000) / 1000; - char str[DDSRT_RFC3339STRLEN]; - ddsrt_ctime(gv.tstart.v, str, sizeof(str)); - DDS_LOG(DDS_LC_CONFIG, "started at %d.06%d -- %s\n", sec, usec, str); + int sec = (int) (gv->tstart.v / 1000000000); + int usec = (int) (gv->tstart.v % 1000000000) / 1000; + char str[DDSRT_RFC3339STRLEN+1]; + ddsrt_ctime(gv->tstart.v, str, sizeof(str)); + GVLOG (DDS_LC_CONFIG, "started at %d.06%d -- %s\n", sec, usec, str); } /* Initialize thread pool */ - - if (config.tp_enable) + if (gv->config.tp_enable) { - gv.thread_pool = ddsrt_thread_pool_new - (config.tp_threads, config.tp_max_threads, 0, NULL); + gv->thread_pool = ddsrt_thread_pool_new (gv->config.tp_threads, gv->config.tp_max_threads, 0, NULL); } /* Initialize UDP or TCP transport and resolve factory */ - switch (config.transport_selector) + switch (gv->config.transport_selector) { case TRANS_DEFAULT: assert(0); case TRANS_UDP: case TRANS_UDP6: - config.publish_uc_locators = 1; - config.enable_uc_locators = 1; - if (ddsi_udp_init () < 0) + gv->config.publish_uc_locators = 1; + gv->config.enable_uc_locators = 1; + if (ddsi_udp_init (gv) < 0) goto err_udp_tcp_init; - gv.m_factory = ddsi_factory_find (config.transport_selector == TRANS_UDP ? "udp" : "udp6"); + gv->m_factory = ddsi_factory_find (gv, gv->config.transport_selector == TRANS_UDP ? "udp" : "udp6"); break; case TRANS_TCP: case TRANS_TCP6: - config.publish_uc_locators = (config.tcp_port != -1); - config.enable_uc_locators = 1; + gv->config.publish_uc_locators = (gv->config.tcp_port != -1); + gv->config.enable_uc_locators = 1; /* TCP affects what features are supported/required */ - config.many_sockets_mode = MSM_SINGLE_UNICAST; - config.allowMulticast = AMC_FALSE; - if (ddsi_tcp_init () < 0) + gv->config.many_sockets_mode = MSM_SINGLE_UNICAST; + gv->config.allowMulticast = AMC_FALSE; + if (ddsi_tcp_init (gv) < 0) goto err_udp_tcp_init; - gv.m_factory = ddsi_factory_find (config.transport_selector == TRANS_TCP ? "tcp" : "tcp6"); + gv->m_factory = ddsi_factory_find (gv, gv->config.transport_selector == TRANS_TCP ? "tcp" : "tcp6"); break; case TRANS_RAWETH: - config.publish_uc_locators = 1; - config.enable_uc_locators = 0; - config.participantIndex = PARTICIPANT_INDEX_NONE; - config.many_sockets_mode = MSM_NO_UNICAST; - if (ddsi_raweth_init () < 0) + gv->config.publish_uc_locators = 1; + gv->config.enable_uc_locators = 0; + gv->config.participantIndex = PARTICIPANT_INDEX_NONE; + gv->config.many_sockets_mode = MSM_NO_UNICAST; + if (ddsi_raweth_init (gv) < 0) goto err_udp_tcp_init; - gv.m_factory = ddsi_factory_find ("raweth"); + gv->m_factory = ddsi_factory_find (gv, "raweth"); break; } - if (!find_own_ip (config.networkAddressString)) + if (!find_own_ip (gv, gv->config.networkAddressString)) { /* find_own_ip already logs a more informative error message */ - DDS_LOG(DDS_LC_CONFIG, "No network interface selected\n"); + GVLOG (DDS_LC_CONFIG, "No network interface selected\n"); goto err_find_own_ip; } - if (config.allowMulticast) + if (gv->config.allowMulticast) { - if (!gv.interfaces[gv.selected_interface].mc_capable) + if (!gv->interfaces[gv->selected_interface].mc_capable) { - DDS_WARNING("selected interface is not multicast-capable: disabling multicast\n"); - config.allowMulticast = AMC_FALSE; + GVWARNING ("selected interface is not multicast-capable: disabling multicast\n"); + gv->config.allowMulticast = AMC_FALSE; /* ensure discovery can work: firstly, that the process will be reachable on a "well-known" port number, and secondly, that the local interface's IP address gets added to the discovery address set */ - config.participantIndex = PARTICIPANT_INDEX_AUTO; + gv->config.participantIndex = PARTICIPANT_INDEX_AUTO; mc_available = false; } + else if (gv->config.allowMulticast & AMC_DEFAULT) + { + /* default is dependent on network interface type: if multicast is believed to be flaky, + use multicast only for SPDP packets */ + assert ((gv->config.allowMulticast & ~AMC_DEFAULT) == 0); + if (gv->interfaces[gv->selected_interface].mc_flaky) + { + gv->config.allowMulticast = AMC_SPDP; + GVLOG (DDS_LC_CONFIG, "presumed flaky multicast, use for SPDP only\n"); + } + else + { + GVLOG (DDS_LC_CONFIG, "presumed robust multicast support, use for everything\n"); + gv->config.allowMulticast = AMC_TRUE; + } + } } - if (set_recvips () < 0) + + assert ((gv->config.allowMulticast & AMC_DEFAULT) == 0); + if (set_recvips (gv) < 0) goto err_set_recvips; - if (set_spdp_address () < 0) + if (set_spdp_address (gv) < 0) goto err_set_ext_address; - if (set_default_mc_address () < 0) + if (set_default_mc_address (gv) < 0) goto err_set_ext_address; - if (set_ext_address_and_mask () < 0) + if (set_ext_address_and_mask (gv) < 0) goto err_set_ext_address; { char buf[DDSI_LOCSTRLEN]; /* the "ownip", "extip" labels in the trace have been there for so long, that it seems worthwhile to retain them even though they need not be IP any longer */ - DDS_LOG(DDS_LC_CONFIG, "ownip: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv.ownloc)); - DDS_LOG(DDS_LC_CONFIG, "extip: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv.extloc)); - DDS_LOG(DDS_LC_CONFIG, "extmask: %s%s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv.extmask), gv.m_factory->m_kind != NN_LOCATOR_KIND_UDPv4 ? " (not applicable)" : ""); - DDS_LOG(DDS_LC_CONFIG, "networkid: 0x%lx\n", (unsigned long) gv.myNetworkId); - DDS_LOG(DDS_LC_CONFIG, "SPDP MC: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv.loc_spdp_mc)); - DDS_LOG(DDS_LC_CONFIG, "default MC: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv.loc_default_mc)); + GVLOG (DDS_LC_CONFIG, "ownip: %s\n", ddsi_locator_to_string_no_port (gv, buf, sizeof(buf), &gv->ownloc)); + GVLOG (DDS_LC_CONFIG, "extip: %s\n", ddsi_locator_to_string_no_port (gv, buf, sizeof(buf), &gv->extloc)); + GVLOG (DDS_LC_CONFIG, "extmask: %s%s\n", ddsi_locator_to_string_no_port (gv, buf, sizeof(buf), &gv->extmask), gv->m_factory->m_kind != NN_LOCATOR_KIND_UDPv4 ? " (not applicable)" : ""); + GVLOG (DDS_LC_CONFIG, "networkid: 0x%lx\n", (unsigned long) gv->myNetworkId); + GVLOG (DDS_LC_CONFIG, "SPDP MC: %s\n", ddsi_locator_to_string_no_port (gv, buf, sizeof(buf), &gv->loc_spdp_mc)); + GVLOG (DDS_LC_CONFIG, "default MC: %s\n", ddsi_locator_to_string_no_port (gv, buf, sizeof(buf), &gv->loc_default_mc)); #ifdef DDSI_INCLUDE_SSM - DDS_LOG(DDS_LC_CONFIG, "SSM support included\n"); + GVLOG (DDS_LC_CONFIG, "SSM support included\n"); #endif } - if (gv.ownloc.kind != gv.extloc.kind) - DDS_FATAL("mismatch between network address kinds\n"); + if (gv->ownloc.kind != gv->extloc.kind) + DDS_FATAL ("mismatch between network address kinds\n"); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS /* Convert address sets in partition mappings from string to address sets */ { - const int port = config.port_base + config.port_dg * config.domainId.value + config.port_d2; + const uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2; struct config_networkpartition_listelem *np; - for (np = config.networkPartitions; np; np = np->next) + for (np = gv->config.networkPartitions; np; np = np->next) { static const char msgtag_fixed[] = ": partition address"; size_t slen = strlen (np->name) + sizeof (msgtag_fixed); @@ -976,7 +990,7 @@ int rtps_init (void) int rc; snprintf (msgtag, slen, "%s%s", np->name, msgtag_fixed); np->as = new_addrset (); - rc = add_addresses_to_addrset (np->as, np->address_string, port, msgtag, 1); + rc = add_addresses_to_addrset (gv, np->as, np->address_string, (int) port, msgtag, 1); ddsrt_free (msgtag); if (rc < 0) goto err_network_partition_addrset; @@ -984,175 +998,174 @@ int rtps_init (void) } #endif - (ddsi_plugin.init_fn) (); - - gv.xmsgpool = nn_xmsgpool_new (); - gv.serpool = ddsi_serdatapool_new (); + gv->xmsgpool = nn_xmsgpool_new (); + gv->serpool = ddsi_serdatapool_new (); #ifdef DDSI_INCLUDE_ENCRYPTION if (q_security_plugin.new_decoder) { - gv.recvSecurityCodec = (q_security_plugin.new_decoder) (); - DDS_LOG(DDS_LC_CONFIG, "decoderset created\n"); + gv->recvSecurityCodec = (q_security_plugin.new_decoder) (); + GVLOG (DDS_LC_CONFIG, "decoderset created\n"); } #endif - nn_plist_init_default_participant (&gv.default_plist_pp); - nn_xqos_init_default_reader (&gv.default_xqos_rd); - nn_xqos_init_default_writer (&gv.default_xqos_wr); - nn_xqos_init_default_writer_noautodispose (&gv.default_xqos_wr_nad); - nn_xqos_init_default_topic (&gv.default_xqos_tp); - nn_xqos_init_default_subscriber (&gv.default_xqos_sub); - nn_xqos_init_default_publisher (&gv.default_xqos_pub); - nn_xqos_copy (&gv.spdp_endpoint_xqos, &gv.default_xqos_rd); - gv.spdp_endpoint_xqos.durability.kind = NN_TRANSIENT_LOCAL_DURABILITY_QOS; - make_builtin_endpoint_xqos (&gv.builtin_endpoint_xqos_rd, &gv.default_xqos_rd); - make_builtin_endpoint_xqos (&gv.builtin_endpoint_xqos_wr, &gv.default_xqos_wr); + nn_plist_init_default_participant (&gv->default_plist_pp); + nn_plist_init_default_participant (&gv->default_local_plist_pp); + nn_xqos_init_default_reader (&gv->default_xqos_rd); + nn_xqos_init_default_writer (&gv->default_xqos_wr); + nn_xqos_init_default_writer_noautodispose (&gv->default_xqos_wr_nad); + nn_xqos_init_default_topic (&gv->default_xqos_tp); + nn_xqos_init_default_subscriber (&gv->default_xqos_sub); + nn_xqos_init_default_publisher (&gv->default_xqos_pub); + nn_xqos_copy (&gv->spdp_endpoint_xqos, &gv->default_xqos_rd); + gv->spdp_endpoint_xqos.durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL; + make_builtin_endpoint_xqos (&gv->builtin_endpoint_xqos_rd, &gv->default_xqos_rd); + make_builtin_endpoint_xqos (&gv->builtin_endpoint_xqos_wr, &gv->default_xqos_wr); - make_special_topics (); + make_special_topics (gv); - ddsrt_mutex_init (&gv.participant_set_lock); - ddsrt_cond_init (&gv.participant_set_cond); - lease_management_init (); - deleted_participants_admin_init (); - gv.guid_hash = ephash_new (); + ddsrt_mutex_init (&gv->participant_set_lock); + ddsrt_cond_init (&gv->participant_set_cond); + lease_management_init (gv); + gv->deleted_participants = deleted_participants_admin_new (gv->config.prune_deleted_ppant.delay); + gv->guid_hash = ephash_new (gv); - ddsrt_mutex_init (&gv.privileged_pp_lock); - gv.privileged_pp = NULL; + ddsrt_mutex_init (&gv->privileged_pp_lock); + gv->privileged_pp = NULL; /* Template PP guid -- protected by privileged_pp_lock for simplicity */ - gv.next_ppguid.prefix.u[0] = locator_to_hopefully_unique_uint32 (&gv.ownloc); - gv.next_ppguid.prefix.u[1] = (unsigned) ddsrt_getpid (); - gv.next_ppguid.prefix.u[2] = 1; - gv.next_ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; + gv->next_ppguid.prefix.u[0] = locator_to_hopefully_unique_uint32 (&gv->ownloc); + gv->next_ppguid.prefix.u[1] = (unsigned) ddsrt_getpid (); + gv->next_ppguid.prefix.u[2] = 1; + gv->next_ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - ddsrt_mutex_init (&gv.lock); - ddsrt_mutex_init (&gv.spdp_lock); - gv.spdp_defrag = nn_defrag_new (NN_DEFRAG_DROP_OLDEST, config.defrag_unreliable_maxsamples); - gv.spdp_reorder = nn_reorder_new (NN_REORDER_MODE_ALWAYS_DELIVER, config.primary_reorder_maxsamples); + ddsrt_mutex_init (&gv->lock); + ddsrt_mutex_init (&gv->spdp_lock); + gv->spdp_defrag = nn_defrag_new (&gv->logconfig, NN_DEFRAG_DROP_OLDEST, gv->config.defrag_unreliable_maxsamples); + gv->spdp_reorder = nn_reorder_new (&gv->logconfig, NN_REORDER_MODE_ALWAYS_DELIVER, gv->config.primary_reorder_maxsamples, false); - gv.m_tkmap = ddsi_tkmap_new (); + gv->m_tkmap = ddsi_tkmap_new (gv); - if (gv.m_factory->m_connless) + if (gv->m_factory->m_connless) { - if (config.participantIndex >= 0 || config.participantIndex == PARTICIPANT_INDEX_NONE) + if (gv->config.participantIndex >= 0 || gv->config.participantIndex == PARTICIPANT_INDEX_NONE) { - if (make_uc_sockets (&port_disc_uc, &port_data_uc, config.participantIndex) < 0) + if (make_uc_sockets (gv, &port_disc_uc, &port_data_uc, gv->config.participantIndex) < 0) { - DDS_ERROR("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", config.domainId.value, config.participantIndex); + GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, gv->config.participantIndex); goto err_unicast_sockets; } } - else if (config.participantIndex == PARTICIPANT_INDEX_AUTO) + else if (gv->config.participantIndex == PARTICIPANT_INDEX_AUTO) { - /* try to find a free one, and update config.participantIndex */ + /* try to find a free one, and update gv->config.participantIndex */ int ppid; - DDS_LOG(DDS_LC_CONFIG, "rtps_init: trying to find a free participant index\n"); - for (ppid = 0; ppid <= config.maxAutoParticipantIndex; ppid++) + GVLOG (DDS_LC_CONFIG, "rtps_init: trying to find a free participant index\n"); + for (ppid = 0; ppid <= gv->config.maxAutoParticipantIndex; ppid++) { - int r = make_uc_sockets (&port_disc_uc, &port_data_uc, ppid); + int r = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, ppid); if (r == 0) /* Success! */ break; else if (r == -1) /* Try next one */ continue; else /* Oops! */ { - DDS_ERROR("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", config.domainId.value, ppid); + GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, ppid); goto err_unicast_sockets; } } - if (ppid > config.maxAutoParticipantIndex) + if (ppid > gv->config.maxAutoParticipantIndex) { - DDS_ERROR("rtps_init: failed to find a free participant index for domain %"PRId32"\n", config.domainId.value); + GVERROR ("rtps_init: failed to find a free participant index for domain %"PRId32"\n", gv->config.domainId); goto err_unicast_sockets; } - config.participantIndex = ppid; + gv->config.participantIndex = ppid; } else { assert(0); } - DDS_LOG(DDS_LC_CONFIG, "rtps_init: uc ports: disc %"PRIu32" data %"PRIu32"\n", port_disc_uc, port_data_uc); + GVLOG (DDS_LC_CONFIG, "rtps_init: uc ports: disc %"PRIu32" data %"PRIu32"\n", port_disc_uc, port_data_uc); } - DDS_LOG(DDS_LC_CONFIG, "rtps_init: domainid %"PRId32" participantid %d\n", config.domainId.value, config.participantIndex); + GVLOG (DDS_LC_CONFIG, "rtps_init: domainid %"PRId32" participantid %d\n", gv->config.domainId, gv->config.participantIndex); - if (config.pcap_file && *config.pcap_file) + if (gv->config.pcap_file && *gv->config.pcap_file) { - gv.pcap_fp = new_pcap_file (config.pcap_file); - if (gv.pcap_fp) + gv->pcap_fp = new_pcap_file (&gv->logconfig, gv->config.pcap_file); + if (gv->pcap_fp) { - ddsrt_mutex_init (&gv.pcap_lock); + ddsrt_mutex_init (&gv->pcap_lock); } } else { - gv.pcap_fp = NULL; + gv->pcap_fp = NULL; } - gv.mship = new_group_membership(); + gv->mship = new_group_membership(); - if (gv.m_factory->m_connless) + if (gv->m_factory->m_connless) { - if (!(config.many_sockets_mode == MSM_NO_UNICAST && config.allowMulticast)) - DDS_TRACE("Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv.disc_conn_uc), ddsi_conn_port (gv.data_conn_uc)); + if (!(gv->config.many_sockets_mode == MSM_NO_UNICAST && gv->config.allowMulticast)) + GVTRACE ("Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv->disc_conn_uc), ddsi_conn_port (gv->data_conn_uc)); - if (config.allowMulticast) + if (gv->config.allowMulticast) { - if (!create_multicast_sockets()) + if (!create_multicast_sockets (gv)) goto err_mc_conn; - if (config.many_sockets_mode == MSM_NO_UNICAST) + if (gv->config.many_sockets_mode == MSM_NO_UNICAST) { - gv.data_conn_uc = gv.data_conn_mc; - gv.disc_conn_uc = gv.disc_conn_mc; + gv->data_conn_uc = gv->data_conn_mc; + gv->disc_conn_uc = gv->disc_conn_mc; } /* Set multicast locators */ - if (!is_unspec_locator(&gv.loc_spdp_mc)) - gv.loc_spdp_mc.port = ddsi_conn_port (gv.disc_conn_mc); - if (!is_unspec_locator(&gv.loc_meta_mc)) - gv.loc_meta_mc.port = ddsi_conn_port (gv.disc_conn_mc); - if (!is_unspec_locator(&gv.loc_default_mc)) - gv.loc_default_mc.port = ddsi_conn_port (gv.data_conn_mc); + if (!is_unspec_locator(&gv->loc_spdp_mc)) + gv->loc_spdp_mc.port = ddsi_conn_port (gv->disc_conn_mc); + if (!is_unspec_locator(&gv->loc_meta_mc)) + gv->loc_meta_mc.port = ddsi_conn_port (gv->disc_conn_mc); + if (!is_unspec_locator(&gv->loc_default_mc)) + gv->loc_default_mc.port = ddsi_conn_port (gv->data_conn_mc); - if (joinleave_spdp_defmcip (1) < 0) + if (joinleave_spdp_defmcip (gv, 1) < 0) goto err_mc_conn; } } else { /* Must have a data_conn_uc/tev_conn/transmit_conn */ - gv.data_conn_uc = ddsi_factory_create_conn (gv.m_factory, 0, NULL); + gv->data_conn_uc = ddsi_factory_create_conn (gv->m_factory, 0, NULL); - if (config.tcp_port != -1) + if (gv->config.tcp_port != -1) { - gv.listener = ddsi_factory_create_listener (gv.m_factory, config.tcp_port, NULL); - if (gv.listener == NULL || ddsi_listener_listen (gv.listener) != 0) + gv->listener = ddsi_factory_create_listener (gv->m_factory, gv->config.tcp_port, NULL); + if (gv->listener == NULL || ddsi_listener_listen (gv->listener) != 0) { - DDS_ERROR("Failed to create %s listener\n", gv.m_factory->m_typename); - if (gv.listener) - ddsi_listener_free(gv.listener); + GVERROR ("Failed to create %s listener\n", gv->m_factory->m_typename); + if (gv->listener) + ddsi_listener_free(gv->listener); goto err_mc_conn; } /* Set unicast locators from listener */ - set_unspec_locator (&gv.loc_spdp_mc); - set_unspec_locator (&gv.loc_meta_mc); - set_unspec_locator (&gv.loc_default_mc); + set_unspec_locator (&gv->loc_spdp_mc); + set_unspec_locator (&gv->loc_meta_mc); + set_unspec_locator (&gv->loc_default_mc); - ddsi_listener_locator (gv.listener, &gv.loc_meta_uc); - ddsi_listener_locator (gv.listener, &gv.loc_default_uc); + ddsi_listener_locator (gv->listener, &gv->loc_meta_uc); + ddsi_listener_locator (gv->listener, &gv->loc_default_uc); } } /* Create shared transmit connection */ - gv.tev_conn = gv.data_conn_uc; - DDS_TRACE("Timed event transmit port: %d\n", (int) ddsi_conn_port (gv.tev_conn)); + gv->tev_conn = gv->data_conn_uc; + GVTRACE ("Timed event transmit port: %d\n", (int) ddsi_conn_port (gv->tev_conn)); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS { - struct config_channel_listelem *chptr = config.channels; + struct config_channel_listelem *chptr = gv->config.channels; while (chptr) { size_t slen = strlen (chptr->name) + 5; @@ -1165,18 +1178,18 @@ int rtps_init (void) { ddsi_tran_qos_t qos = ddsi_tran_create_qos (); qos->m_diffserv = chptr->diffserv_field; - chptr->transmit_conn = ddsi_factory_create_conn (gv.m_factory, 0, qos); + chptr->transmit_conn = ddsi_factory_create_conn (gv->m_factory, 0, qos); ddsi_tran_free_qos (qos); if (chptr->transmit_conn == NULL) { - DDS_FATAL("failed to create transmit connection for channel %s\n", chptr->name); + DDS_FATAL ("failed to create transmit connection for channel %s\n", chptr->name); } } else { - chptr->transmit_conn = gv.data_conn_uc; + chptr->transmit_conn = gv->data_conn_uc; } - DDS_TRACE("channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn)); + GVTRACE ("channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn)); #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING if (chptr->auxiliary_bandwidth_limit > 0 || lookup_thread_properties (tname)) @@ -1184,8 +1197,8 @@ int rtps_init (void) chptr->evq = xeventq_new ( chptr->transmit_conn, - config.max_queued_rexmit_bytes, - config.max_queued_rexmit_msgs, + gv->config.max_queued_rexmit_bytes, + gv->config.max_queued_rexmit_msgs, chptr->auxiliary_bandwidth_limit ); } @@ -1195,8 +1208,8 @@ int rtps_init (void) chptr->evq = xeventq_new ( chptr->transmit_conn, - config.max_queued_rexmit_bytes, - config.max_queued_rexmit_msgs, + gv->config.max_queued_rexmit_bytes, + gv->config.max_queued_rexmit_msgs, 0 ); } @@ -1209,21 +1222,21 @@ int rtps_init (void) /* Create event queues */ - gv.xevents = xeventq_new + gv->xevents = xeventq_new ( - gv.tev_conn, - config.max_queued_rexmit_bytes, - config.max_queued_rexmit_msgs, + gv->tev_conn, + gv->config.max_queued_rexmit_bytes, + gv->config.max_queued_rexmit_msgs, #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING - config.auxiliary_bandwidth_limit + gv->config.auxiliary_bandwidth_limit #else 0 #endif ); - gv.as_disc = new_addrset (); - if (config.allowMulticast & AMC_SPDP) - add_to_addrset (gv.as_disc, &gv.loc_spdp_mc); + gv->as_disc = new_addrset (); + if (gv->config.allowMulticast & AMC_SPDP) + add_to_addrset (gv, gv->as_disc, &gv->loc_spdp_mc); /* If multicast was enabled but not available, always add the local interface to the discovery address set. Conversion via string and add_peer_addresses has the benefit that the port number expansion happens automatically. */ @@ -1231,160 +1244,158 @@ int rtps_init (void) { struct config_peer_listelem peer_local; char local_addr[DDSI_LOCSTRLEN]; - ddsi_locator_to_string_no_port (local_addr, sizeof (local_addr), &gv.interfaces[gv.selected_interface].loc); + ddsi_locator_to_string_no_port (gv, local_addr, sizeof (local_addr), &gv->interfaces[gv->selected_interface].loc); peer_local.next = NULL; peer_local.peer = local_addr; - add_peer_addresses (gv.as_disc, &peer_local); + add_peer_addresses (gv, gv->as_disc, &peer_local); } - if (config.peers) + if (gv->config.peers) { - add_peer_addresses (gv.as_disc, config.peers); + add_peer_addresses (gv, gv->as_disc, gv->config.peers); } - if (config.peers_group) + if (gv->config.peers_group) { - gv.as_disc_group = new_addrset (); - add_peer_addresses (gv.as_disc_group, config.peers_group); + gv->as_disc_group = new_addrset (); + add_peer_addresses (gv, gv->as_disc_group, gv->config.peers_group); } else { - gv.as_disc_group = NULL; + gv->as_disc_group = NULL; } - gv.gcreq_queue = gcreq_queue_new (); + gv->gcreq_queue = gcreq_queue_new (gv); - gv.rtps_keepgoing = 1; - ddsrt_rwlock_init (&gv.qoslock); + ddsrt_atomic_st32 (&gv->rtps_keepgoing, 1); - if (config.xpack_send_async) + if (gv->config.xpack_send_async) { - nn_xpack_sendq_init(); - nn_xpack_sendq_start(); + nn_xpack_sendq_init (gv); + nn_xpack_sendq_start (gv); } - gv.builtins_dqueue = nn_dqueue_new ("builtins", config.delivery_queue_maxsamples, builtins_dqueue_handler, NULL); + gv->builtins_dqueue = nn_dqueue_new ("builtins", gv, gv->config.delivery_queue_maxsamples, builtins_dqueue_handler, NULL); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - for (struct config_channel_listelem *chptr = config.channels; chptr; chptr = chptr->next) - chptr->dqueue = nn_dqueue_new (chptr->name, config.delivery_queue_maxsamples, user_dqueue_handler, NULL); + for (struct config_channel_listelem *chptr = gv->config.channels; chptr; chptr = chptr->next) + chptr->dqueue = nn_dqueue_new (chptr->name, &gv->config, gv->config.delivery_queue_maxsamples, user_dqueue_handler, NULL); #else - gv.user_dqueue = nn_dqueue_new ("user", config.delivery_queue_maxsamples, user_dqueue_handler, NULL); + gv->user_dqueue = nn_dqueue_new ("user", gv, gv->config.delivery_queue_maxsamples, user_dqueue_handler, NULL); #endif return 0; err_mc_conn: - if (gv.disc_conn_mc) - ddsi_conn_free (gv.disc_conn_mc); - if (gv.data_conn_mc && gv.data_conn_mc != gv.disc_conn_mc) - ddsi_conn_free (gv.data_conn_mc); - if (gv.pcap_fp) - ddsrt_mutex_destroy (&gv.pcap_lock); - if (gv.disc_conn_uc != gv.disc_conn_mc) - ddsi_conn_free (gv.disc_conn_uc); - if (gv.data_conn_uc != gv.disc_conn_uc) - ddsi_conn_free (gv.data_conn_uc); - free_group_membership(gv.mship); + if (gv->disc_conn_mc) + ddsi_conn_free (gv->disc_conn_mc); + if (gv->data_conn_mc && gv->data_conn_mc != gv->disc_conn_mc) + ddsi_conn_free (gv->data_conn_mc); + if (gv->pcap_fp) + ddsrt_mutex_destroy (&gv->pcap_lock); + if (gv->disc_conn_uc != gv->disc_conn_mc) + ddsi_conn_free (gv->disc_conn_uc); + if (gv->data_conn_uc != gv->disc_conn_uc) + ddsi_conn_free (gv->data_conn_uc); + free_group_membership (gv->mship); err_unicast_sockets: - ddsi_tkmap_free (gv.m_tkmap); - nn_reorder_free (gv.spdp_reorder); - nn_defrag_free (gv.spdp_defrag); - ddsrt_mutex_destroy (&gv.spdp_lock); - ddsrt_mutex_destroy (&gv.lock); - ddsrt_mutex_destroy (&gv.privileged_pp_lock); - ephash_free (gv.guid_hash); - gv.guid_hash = NULL; - deleted_participants_admin_fini (); - lease_management_term (); - ddsrt_cond_destroy (&gv.participant_set_cond); - ddsrt_mutex_destroy (&gv.participant_set_lock); - free_special_topics (); + ddsi_tkmap_free (gv->m_tkmap); + nn_reorder_free (gv->spdp_reorder); + nn_defrag_free (gv->spdp_defrag); + ddsrt_mutex_destroy (&gv->spdp_lock); + ddsrt_mutex_destroy (&gv->lock); + ddsrt_mutex_destroy (&gv->privileged_pp_lock); + ephash_free (gv->guid_hash); + gv->guid_hash = NULL; + deleted_participants_admin_free (gv->deleted_participants); + lease_management_term (gv); + ddsrt_cond_destroy (&gv->participant_set_cond); + ddsrt_mutex_destroy (&gv->participant_set_lock); + free_special_topics (gv); #ifdef DDSI_INCLUDE_ENCRYPTION if (q_security_plugin.free_decoder) - q_security_plugin.free_decoder (gv.recvSecurityCodec); + q_security_plugin.free_decoder (gv->recvSecurityCodec); #endif - nn_xqos_fini (&gv.builtin_endpoint_xqos_wr); - nn_xqos_fini (&gv.builtin_endpoint_xqos_rd); - nn_xqos_fini (&gv.spdp_endpoint_xqos); - nn_xqos_fini (&gv.default_xqos_pub); - nn_xqos_fini (&gv.default_xqos_sub); - nn_xqos_fini (&gv.default_xqos_tp); - nn_xqos_fini (&gv.default_xqos_wr_nad); - nn_xqos_fini (&gv.default_xqos_wr); - nn_xqos_fini (&gv.default_xqos_rd); - nn_plist_fini (&gv.default_plist_pp); - ddsi_serdatapool_free (gv.serpool); - nn_xmsgpool_free (gv.xmsgpool); - ddsi_iid_fini (); - (ddsi_plugin.fini_fn) (); + nn_xqos_fini (&gv->builtin_endpoint_xqos_wr); + nn_xqos_fini (&gv->builtin_endpoint_xqos_rd); + nn_xqos_fini (&gv->spdp_endpoint_xqos); + nn_xqos_fini (&gv->default_xqos_pub); + nn_xqos_fini (&gv->default_xqos_sub); + nn_xqos_fini (&gv->default_xqos_tp); + nn_xqos_fini (&gv->default_xqos_wr_nad); + nn_xqos_fini (&gv->default_xqos_wr); + nn_xqos_fini (&gv->default_xqos_rd); + nn_plist_fini (&gv->default_local_plist_pp); + nn_plist_fini (&gv->default_plist_pp); + ddsi_serdatapool_free (gv->serpool); + nn_xmsgpool_free (gv->xmsgpool); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS err_network_partition_addrset: - for (struct config_networkpartition_listelem *np = config.networkPartitions; np; np = np->next) + for (struct config_networkpartition_listelem *np = gv->config.networkPartitions; np; np = np->next) unref_addrset (np->as); #endif err_set_ext_address: - while (gv.recvips) + while (gv->recvips) { - struct config_in_addr_node *n = gv.recvips; - gv.recvips = n->next; + struct config_in_addr_node *n = gv->recvips; + gv->recvips = n->next; ddsrt_free (n); } err_set_recvips: - { - int i; - for (i = 0; i < gv.n_interfaces; i++) - ddsrt_free (gv.interfaces[i].name); - } err_find_own_ip: - ddsi_tran_factories_fini (); + for (int i = 0; i < gv->n_interfaces; i++) + ddsrt_free (gv->interfaces[i].name); + ddsi_tran_factories_fini (gv); err_udp_tcp_init: - if (config.tp_enable) - ddsrt_thread_pool_free (gv.thread_pool); + if (gv->config.tp_enable) + ddsrt_thread_pool_free (gv->thread_pool); return -1; } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS static void stop_all_xeventq_upto (struct config_channel_listelem *chptr) { - for (struct config_channel_listelem *chptr1 = config.channels; chptr1 != chptr; chptr1 = chptr1->next) + for (struct config_channel_listelem *chptr1 = gv->config.channels; chptr1 != chptr; chptr1 = chptr1->next) if (chptr1->evq) xeventq_stop (chptr1->evq); } #endif -int rtps_start (void) +int rtps_start (struct q_globals *gv) { - if (xeventq_start (gv.xevents, NULL) < 0) + if (xeventq_start (gv->xevents, NULL) < 0) return -1; #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - for (struct config_channel_listelem *chptr = config.channels; chptr; chptr = chptr->next) + for (struct config_channel_listelem *chptr = gv->config.channels; chptr; chptr = chptr->next) { if (chptr->evq) { if (xeventq_start (chptr->evq, chptr->name) < 0) { stop_all_xeventq_upto (chptr); - xeventq_stop (gv.xevents); + xeventq_stop (gv->xevents); return -1; } } } #endif - if (setup_and_start_recv_threads () < 0) + if (setup_and_start_recv_threads (gv) < 0) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS stop_all_xeventq_upto (NULL); #endif - xeventq_stop (gv.xevents); + xeventq_stop (gv->xevents); return -1; } - if (gv.listener) + if (gv->listener) { - create_thread (&gv.listen_ts, "listen", (uint32_t (*) (void *)) listen_thread, gv.listener); + create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener); + /* FIXME: error handling */ } - if (config.monitor_port >= 0) + if (gv->config.monitor_port >= 0) { - gv.debmon = new_debug_monitor (config.monitor_port); + gv->debmon = new_debug_monitor (gv, gv->config.monitor_port); + /* FIXME: clean up */ } + return 0; } @@ -1403,7 +1414,7 @@ static void builtins_dqueue_ready_cb (void *varg) ddsrt_mutex_unlock (&arg->lock); } -void rtps_stop (void) +void rtps_stop (struct q_globals *gv) { struct thread_state1 * const ts1 = lookup_thread_state (); @@ -1411,26 +1422,26 @@ void rtps_stop (void) struct config_channel_listelem * chptr; #endif - if (gv.debmon) + if (gv->debmon) { - free_debug_monitor (gv.debmon); - gv.debmon = NULL; + free_debug_monitor (gv->debmon); + gv->debmon = NULL; } /* Stop all I/O */ - rtps_term_prep (); - wait_for_receive_threads (); + rtps_term_prep (gv); + wait_for_receive_threads (gv); - if (gv.listener) + if (gv->listener) { - ddsi_listener_unblock(gv.listener); - join_thread (gv.listen_ts); - ddsi_listener_free(gv.listener); + ddsi_listener_unblock(gv->listener); + join_thread (gv->listen_ts); + ddsi_listener_free(gv->listener); } - xeventq_stop (gv.xevents); + xeventq_stop (gv->xevents); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - for (chptr = config.channels; chptr; chptr = chptr->next) + for (chptr = gv->config.channels; chptr; chptr = chptr->next) { if (chptr->evq) xeventq_stop (chptr->evq); @@ -1445,7 +1456,7 @@ void rtps_stop (void) ddsrt_mutex_init (&arg.lock); ddsrt_cond_init (&arg.cond); arg.ready = 0; - nn_dqueue_enqueue_callback(gv.builtins_dqueue, builtins_dqueue_ready_cb, &arg); + nn_dqueue_enqueue_callback(gv->builtins_dqueue, builtins_dqueue_ready_cb, &arg); ddsrt_mutex_lock (&arg.lock); while (!arg.ready) ddsrt_cond_wait (&arg.cond, &arg.lock); @@ -1456,13 +1467,13 @@ void rtps_stop (void) /* Once the receive threads have stopped, defragmentation and reorder state can't change anymore, and can be freed safely. */ - nn_reorder_free (gv.spdp_reorder); - nn_defrag_free (gv.spdp_defrag); - ddsrt_mutex_destroy (&gv.spdp_lock); + nn_reorder_free (gv->spdp_reorder); + nn_defrag_free (gv->spdp_defrag); + ddsrt_mutex_destroy (&gv->spdp_lock); #ifdef DDSI_INCLUDE_ENCRYPTION if (q_security_plugin.free_decoder) { - (q_security_plugin.free_decoder) (gv.recvSecurityCodec); + (q_security_plugin.free_decoder) (gv->recvSecurityCodec); } #endif /* DDSI_INCLUDE_ENCRYPTION */ @@ -1473,11 +1484,11 @@ void rtps_stop (void) /* Clean up proxy readers, proxy writers and proxy participants. Deleting a proxy participants deletes all its readers and writers automatically */ - thread_state_awake (ts1); - ephash_enum_proxy_participant_init (&est); + thread_state_awake (ts1, gv); + ephash_enum_proxy_participant_init (&est, gv->guid_hash); while ((proxypp = ephash_enum_proxy_participant_next (&est)) != NULL) { - delete_proxy_participant_by_guid(&proxypp->e.guid, tnow, 1); + delete_proxy_participant_by_guid (gv, &proxypp->e.guid, tnow, 1); } ephash_enum_proxy_participant_fini (&est); thread_state_asleep (ts1); @@ -1495,27 +1506,27 @@ void rtps_stop (void) rwriters to get all SEDP and SPDP dispose+unregister messages out. FIXME: need to keep xevent thread alive for a while longer. */ - thread_state_awake (ts1); - ephash_enum_writer_init (&est_wr); + thread_state_awake (ts1, gv); + ephash_enum_writer_init (&est_wr, gv->guid_hash); while ((wr = ephash_enum_writer_next (&est_wr)) != NULL) { if (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) - delete_writer_nolinger (&wr->e.guid); + delete_writer_nolinger (gv, &wr->e.guid); } ephash_enum_writer_fini (&est_wr); thread_state_awake_to_awake_no_nest (ts1); - ephash_enum_reader_init (&est_rd); + ephash_enum_reader_init (&est_rd, gv->guid_hash); while ((rd = ephash_enum_reader_next (&est_rd)) != NULL) { if (!is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE)) - (void)delete_reader (&rd->e.guid); + delete_reader (gv, &rd->e.guid); } ephash_enum_reader_fini (&est_rd); thread_state_awake_to_awake_no_nest (ts1); - ephash_enum_participant_init (&est_pp); + ephash_enum_participant_init (&est_pp, gv->guid_hash); while ((pp = ephash_enum_participant_next (&est_pp)) != NULL) { - delete_participant (&pp->e.guid); + delete_participant (gv, &pp->e.guid); } ephash_enum_participant_fini (&est_pp); thread_state_asleep (ts1); @@ -1524,60 +1535,60 @@ void rtps_stop (void) /* Wait until all participants are really gone => by then we can be certain that no new GC requests will be added, short of what we do here */ - ddsrt_mutex_lock (&gv.participant_set_lock); - while (gv.nparticipants > 0) - ddsrt_cond_wait (&gv.participant_set_cond, &gv.participant_set_lock); - ddsrt_mutex_unlock (&gv.participant_set_lock); + ddsrt_mutex_lock (&gv->participant_set_lock); + while (gv->nparticipants > 0) + ddsrt_cond_wait (&gv->participant_set_cond, &gv->participant_set_lock); + ddsrt_mutex_unlock (&gv->participant_set_lock); /* Wait until no more GC requests are outstanding -- not really necessary, but it allows us to claim the stack is quiescent at this point */ - gcreq_queue_drain (gv.gcreq_queue); + gcreq_queue_drain (gv->gcreq_queue); /* Clean up privileged_pp -- it must be NULL now (all participants are gone), but the lock still needs to be destroyed */ - assert (gv.privileged_pp == NULL); - ddsrt_mutex_destroy (&gv.privileged_pp_lock); + assert (gv->privileged_pp == NULL); + ddsrt_mutex_destroy (&gv->privileged_pp_lock); } -void rtps_fini (void) +void rtps_fini (struct q_globals *gv) { /* Shut down the GC system -- no new requests will be added */ - gcreq_queue_free (gv.gcreq_queue); + gcreq_queue_free (gv->gcreq_queue); /* No new data gets added to any admin, all synchronous processing has ended, so now we can drain the delivery queues to end up with the expected reference counts all over the radmin thingummies. */ - nn_dqueue_free (gv.builtins_dqueue); + nn_dqueue_free (gv->builtins_dqueue); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - chptr = config.channels; + chptr = gv->config.channels; while (chptr) { nn_dqueue_free (chptr->dqueue); chptr = chptr->next; } #else - nn_dqueue_free (gv.user_dqueue); + nn_dqueue_free (gv->user_dqueue); #endif - xeventq_free (gv.xevents); + xeventq_free (gv->xevents); - if (config.xpack_send_async) + if (gv->config.xpack_send_async) { - nn_xpack_sendq_stop(); - nn_xpack_sendq_fini(); + nn_xpack_sendq_stop (gv); + nn_xpack_sendq_fini (gv); } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - chptr = config.channels; + chptr = gv->config.channels; while (chptr) { if (chptr->evq) { xeventq_free (chptr->evq); } - if (chptr->transmit_conn != gv.data_conn_uc) + if (chptr->transmit_conn != gv->data_conn_uc) { ddsi_conn_free (chptr->transmit_conn); } @@ -1585,93 +1596,85 @@ void rtps_fini (void) } #endif - ddsrt_thread_pool_free (gv.thread_pool); + ddsrt_thread_pool_free (gv->thread_pool); - (void) joinleave_spdp_defmcip (0); + (void) joinleave_spdp_defmcip (gv, 0); - ddsi_conn_free (gv.disc_conn_mc); - if (gv.data_conn_mc != gv.disc_conn_mc) - ddsi_conn_free (gv.data_conn_mc); - if (gv.disc_conn_uc != gv.disc_conn_mc) - ddsi_conn_free (gv.disc_conn_uc); - if (gv.data_conn_uc != gv.disc_conn_uc) - ddsi_conn_free (gv.data_conn_uc); + ddsi_conn_free (gv->disc_conn_mc); + if (gv->data_conn_mc != gv->disc_conn_mc) + ddsi_conn_free (gv->data_conn_mc); + if (gv->disc_conn_uc != gv->disc_conn_mc) + ddsi_conn_free (gv->disc_conn_uc); + if (gv->data_conn_uc != gv->disc_conn_uc) + ddsi_conn_free (gv->data_conn_uc); - /* Not freeing gv.tev_conn: it aliases data_conn_uc */ + /* Not freeing gv->tev_conn: it aliases data_conn_uc */ - free_group_membership(gv.mship); - ddsi_tran_factories_fini (); + free_group_membership(gv->mship); + ddsi_tran_factories_fini (gv); - if (gv.pcap_fp) + if (gv->pcap_fp) { - ddsrt_mutex_destroy (&gv.pcap_lock); - fclose (gv.pcap_fp); + ddsrt_mutex_destroy (&gv->pcap_lock); + fclose (gv->pcap_fp); } #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS - for (struct config_networkpartition_listelem *np = config.networkPartitions; np; np = np->next) + for (struct config_networkpartition_listelem *np = gv->config.networkPartitions; np; np = np->next) unref_addrset (np->as); #endif - unref_addrset (gv.as_disc); - unref_addrset (gv.as_disc_group); + unref_addrset (gv->as_disc); + unref_addrset (gv->as_disc_group); /* Must delay freeing of rbufpools until after *all* references have been dropped, which only happens once all receive threads have stopped, defrags and reorders have been freed, and all delivery queues been drained. I.e., until very late in the game. */ + for (uint32_t i = 0; i < gv->n_recv_threads; i++) { - unsigned i; - for (i = 0; i < gv.n_recv_threads; i++) - { - if (gv.recv_threads[i].arg.mode == RTM_MANY) - os_sockWaitsetFree (gv.recv_threads[i].arg.u.many.ws); - nn_rbufpool_free (gv.recv_threads[i].arg.rbpool); - } + if (gv->recv_threads[i].arg.mode == RTM_MANY) + os_sockWaitsetFree (gv->recv_threads[i].arg.u.many.ws); + nn_rbufpool_free (gv->recv_threads[i].arg.rbpool); } - ddsi_tkmap_free (gv.m_tkmap); + ddsi_tkmap_free (gv->m_tkmap); - ephash_free (gv.guid_hash); - gv.guid_hash = NULL; - deleted_participants_admin_fini (); - lease_management_term (); - ddsrt_mutex_destroy (&gv.participant_set_lock); - ddsrt_cond_destroy (&gv.participant_set_cond); - free_special_topics (); + ephash_free (gv->guid_hash); + gv->guid_hash = NULL; + deleted_participants_admin_free (gv->deleted_participants); + lease_management_term (gv); + ddsrt_mutex_destroy (&gv->participant_set_lock); + ddsrt_cond_destroy (&gv->participant_set_cond); + free_special_topics (gv); - nn_xqos_fini (&gv.builtin_endpoint_xqos_wr); - nn_xqos_fini (&gv.builtin_endpoint_xqos_rd); - nn_xqos_fini (&gv.spdp_endpoint_xqos); - nn_xqos_fini (&gv.default_xqos_pub); - nn_xqos_fini (&gv.default_xqos_sub); - nn_xqos_fini (&gv.default_xqos_tp); - nn_xqos_fini (&gv.default_xqos_wr_nad); - nn_xqos_fini (&gv.default_xqos_wr); - nn_xqos_fini (&gv.default_xqos_rd); - nn_plist_fini (&gv.default_plist_pp); + nn_xqos_fini (&gv->builtin_endpoint_xqos_wr); + nn_xqos_fini (&gv->builtin_endpoint_xqos_rd); + nn_xqos_fini (&gv->spdp_endpoint_xqos); + nn_xqos_fini (&gv->default_xqos_pub); + nn_xqos_fini (&gv->default_xqos_sub); + nn_xqos_fini (&gv->default_xqos_tp); + nn_xqos_fini (&gv->default_xqos_wr_nad); + nn_xqos_fini (&gv->default_xqos_wr); + nn_xqos_fini (&gv->default_xqos_rd); + nn_plist_fini (&gv->default_local_plist_pp); + nn_plist_fini (&gv->default_plist_pp); - ddsrt_mutex_destroy (&gv.lock); - ddsrt_rwlock_destroy (&gv.qoslock); + ddsrt_mutex_destroy (&gv->lock); - while (gv.recvips) + while (gv->recvips) { - struct config_in_addr_node *n = gv.recvips; -/* The compiler doesn't realize that n->next is always initialized. */ -DDSRT_WARNING_MSVC_OFF(6001); - gv.recvips = n->next; -DDSRT_WARNING_MSVC_ON(6001); + struct config_in_addr_node *n = gv->recvips; + /* The compiler doesn't realize that n->next is always initialized. */ + DDSRT_WARNING_MSVC_OFF(6001); + gv->recvips = n->next; + DDSRT_WARNING_MSVC_ON(6001); ddsrt_free (n); } - { - int i; - for (i = 0; i < (int) gv.n_interfaces; i++) - ddsrt_free (gv.interfaces[i].name); - } + for (int i = 0; i < (int) gv->n_interfaces; i++) + ddsrt_free (gv->interfaces[i].name); - ddsi_serdatapool_free (gv.serpool); - nn_xmsgpool_free (gv.xmsgpool); - ddsi_iid_fini (); - (ddsi_plugin.fini_fn) (); - DDS_LOG(DDS_LC_CONFIG, "Finis.\n"); + ddsi_serdatapool_free (gv->serpool); + nn_xmsgpool_free (gv->xmsgpool); + GVLOG (DDS_LC_CONFIG, "Finis.\n"); } diff --git a/src/core/ddsi/src/q_lat_estim.c b/src/core/ddsi/src/q_lat_estim.c index 2302b32..d451b41 100644 --- a/src/core/ddsi/src/q_lat_estim.c +++ b/src/core/ddsi/src/q_lat_estim.c @@ -56,7 +56,7 @@ void nn_lat_estim_update (struct nn_lat_estim *le, int64_t est) le->smoothed = (1.0f - alpha) * le->smoothed + alpha * med; } -int nn_lat_estim_log (uint32_t logcat, const char *tag, const struct nn_lat_estim *le) +int nn_lat_estim_log (uint32_t logcat, const struct ddsrt_log_cfg *logcfg, const char *tag, const struct nn_lat_estim *le) { if (le->smoothed == 0.0f) return 0; @@ -67,12 +67,12 @@ int nn_lat_estim_log (uint32_t logcat, const char *tag, const struct nn_lat_esti memcpy (tmp, le->window, sizeof (tmp)); qsort (tmp, NN_LAT_ESTIM_MEDIAN_WINSZ, sizeof (tmp[0]), (int (*) (const void *, const void *)) cmpfloat); if (tag) - DDS_LOG(logcat, " LAT(%s: %e {", tag, le->smoothed); + DDS_CLOG (logcat, logcfg, " LAT(%s: %e {", tag, le->smoothed); else - DDS_LOG(logcat, " LAT(%e {", le->smoothed); + DDS_CLOG (logcat, logcfg, " LAT(%e {", le->smoothed); for (i = 0; i < NN_LAT_ESTIM_MEDIAN_WINSZ; i++) - DDS_LOG(logcat, "%s%e", (i > 0) ? "," : "", tmp[i]); - DDS_LOG(logcat, "})"); + DDS_CLOG (logcat, logcfg, "%s%e", (i > 0) ? "," : "", tmp[i]); + DDS_CLOG (logcat, logcfg, "})"); return 1; } } diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c index 4ec8892..85ccc92 100644 --- a/src/core/ddsi/src/q_lease.c +++ b/src/core/ddsi/src/q_lease.c @@ -45,9 +45,9 @@ struct lease { ddsrt_fibheap_node_t heapnode; - nn_etime_t tsched; /* access guarded by leaseheap_lock */ - nn_etime_t tend; /* access guarded by lock_lease/unlock_lease */ - int64_t tdur; /* constant (renew depends on it) */ + nn_etime_t tsched; /* access guarded by leaseheap_lock */ + ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */ + dds_duration_t tdur; /* constant (renew depends on it) */ struct entity_common *entity; /* constant */ }; @@ -55,9 +55,9 @@ static int compare_lease_tsched (const void *va, const void *vb); static const ddsrt_fibheap_def_t lease_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, heapnode), compare_lease_tsched); -static void force_lease_check (void) +static void force_lease_check (struct gcreq_queue *gcreq_queue) { - gcreq_enqueue(gcreq_new(gv.gcreq_queue, gcreq_free)); + gcreq_enqueue (gcreq_new (gcreq_queue, gcreq_free)); } static int compare_lease_tsched (const void *va, const void *vb) @@ -67,173 +67,148 @@ static int compare_lease_tsched (const void *va, const void *vb) return (a->tsched.v == b->tsched.v) ? 0 : (a->tsched.v < b->tsched.v) ? -1 : 1; } -void lease_management_init (void) +void lease_management_init (struct q_globals *gv) { - int i; - ddsrt_mutex_init (&gv.leaseheap_lock); - for (i = 0; i < N_LEASE_LOCKS; i++) - ddsrt_mutex_init (&gv.lease_locks[i]); - ddsrt_fibheap_init (&lease_fhdef, &gv.leaseheap); + ddsrt_mutex_init (&gv->leaseheap_lock); + ddsrt_fibheap_init (&lease_fhdef, &gv->leaseheap); } -void lease_management_term (void) +void lease_management_term (struct q_globals *gv) { - int i; - assert (ddsrt_fibheap_min (&lease_fhdef, &gv.leaseheap) == NULL); - for (i = 0; i < N_LEASE_LOCKS; i++) - ddsrt_mutex_destroy (&gv.lease_locks[i]); - ddsrt_mutex_destroy (&gv.leaseheap_lock); + assert (ddsrt_fibheap_min (&lease_fhdef, &gv->leaseheap) == NULL); + ddsrt_mutex_destroy (&gv->leaseheap_lock); } -static ddsrt_mutex_t *lock_lease_addr (struct lease const * const l) -{ - uint32_t u = (uint16_t) ((uintptr_t) l >> 3); - uint32_t v = u * 0xb4817365; - unsigned idx = v >> (32 - N_LEASE_LOCKS_LG2); - return &gv.lease_locks[idx]; -} - -static void lock_lease (const struct lease *l) -{ - ddsrt_mutex_lock (lock_lease_addr (l)); -} - -static void unlock_lease (const struct lease *l) -{ - ddsrt_mutex_unlock (lock_lease_addr (l)); -} - -struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e) +struct lease *lease_new (nn_etime_t texpire, dds_duration_t tdur, struct entity_common *e) { struct lease *l; if ((l = ddsrt_malloc (sizeof (*l))) == NULL) return NULL; - DDS_TRACE("lease_new(tdur %"PRId64" guid "PGUIDFMT") @ %p\n", tdur, PGUID (e->guid), (void *) l); + EETRACE (e, "lease_new(tdur %"PRId64" guid "PGUIDFMT") @ %p\n", tdur, PGUID (e->guid), (void *) l); l->tdur = tdur; - l->tend = texpire; + ddsrt_atomic_st64 (&l->tend, (uint64_t) texpire.v); l->tsched.v = TSCHED_NOT_ON_HEAP; l->entity = e; return l; } -void lease_register (struct lease *l) +void lease_register (struct lease *l) /* FIXME: make lease admin struct */ { - DDS_TRACE("lease_register(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid)); - ddsrt_mutex_lock (&gv.leaseheap_lock); - lock_lease (l); + struct q_globals * const gv = l->entity->gv; + GVTRACE ("lease_register(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid)); + ddsrt_mutex_lock (&gv->leaseheap_lock); assert (l->tsched.v == TSCHED_NOT_ON_HEAP); - if (l->tend.v != T_NEVER) + int64_t tend = (int64_t) ddsrt_atomic_ld64 (&l->tend); + if (tend != T_NEVER) { - l->tsched = l->tend; - ddsrt_fibheap_insert (&lease_fhdef, &gv.leaseheap, l); + l->tsched.v = tend; + ddsrt_fibheap_insert (&lease_fhdef, &gv->leaseheap, l); } - unlock_lease (l); - ddsrt_mutex_unlock (&gv.leaseheap_lock); + ddsrt_mutex_unlock (&gv->leaseheap_lock); /* check_and_handle_lease_expiration runs on GC thread and the only way to be sure that it wakes up in time is by forcing re-evaluation (strictly speaking only needed if this is the first lease to expire, but this operation is quite rare anyway) */ - force_lease_check(); + force_lease_check (gv->gcreq_queue); } void lease_free (struct lease *l) { - DDS_TRACE("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid)); - ddsrt_mutex_lock (&gv.leaseheap_lock); + struct q_globals * const gv = l->entity->gv; + GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid)); + ddsrt_mutex_lock (&gv->leaseheap_lock); if (l->tsched.v != TSCHED_NOT_ON_HEAP) - ddsrt_fibheap_delete (&lease_fhdef, &gv.leaseheap, l); - ddsrt_mutex_unlock (&gv.leaseheap_lock); + ddsrt_fibheap_delete (&lease_fhdef, &gv->leaseheap, l); + ddsrt_mutex_unlock (&gv->leaseheap_lock); ddsrt_free (l); /* see lease_register() */ - force_lease_check(); + force_lease_check (gv->gcreq_queue); } void lease_renew (struct lease *l, nn_etime_t tnowE) { + struct q_globals const * const gv = l->entity->gv; nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur); - int did_update; - lock_lease (l); - /* do not touch tend if moving forward or if already expired */ - if (tend_new.v <= l->tend.v || tnowE.v >= l->tend.v) - did_update = 0; - else - { - l->tend = tend_new; - did_update = 1; - } - unlock_lease (l); - if (did_update && (dds_get_log_mask() & DDS_LC_TRACE)) + /* do not touch tend if moving forward or if already expired */ + int64_t tend; + do { + tend = (int64_t) ddsrt_atomic_ld64 (&l->tend); + if (tend_new.v <= tend || tnowE.v >= tend) + return; + } while (!ddsrt_atomic_cas64 (&l->tend, (uint64_t) tend, (uint64_t) tend_new.v)); + + if (gv->logconfig.c.mask & DDS_LC_TRACE) { int32_t tsec, tusec; - DDS_TRACE(" L("); + GVTRACE (" L("); if (l->entity->guid.entityid.u == NN_ENTITYID_PARTICIPANT) - DDS_TRACE(":%"PRIx32, l->entity->guid.entityid.u); + GVTRACE (":%"PRIx32, l->entity->guid.entityid.u); else - DDS_TRACE(""PGUIDFMT"", PGUID (l->entity->guid)); + GVTRACE (""PGUIDFMT"", PGUID (l->entity->guid)); etime_to_sec_usec (&tsec, &tusec, tend_new); - DDS_TRACE(" %"PRId32".%06"PRId32")", tsec, tusec); + GVTRACE (" %"PRId32".%06"PRId32")", tsec, tusec); } } void lease_set_expiry (struct lease *l, nn_etime_t when) { + struct q_globals * const gv = l->entity->gv; bool trigger = false; assert (when.v >= 0); - ddsrt_mutex_lock (&gv.leaseheap_lock); - lock_lease (l); - l->tend = when; - if (l->tend.v < l->tsched.v) + ddsrt_mutex_lock (&gv->leaseheap_lock); + /* only possible concurrent action is to move tend into the future (renew_lease), + all other operations occur with leaseheap_lock held */ + ddsrt_atomic_st64 (&l->tend, (uint64_t) when.v); + if (when.v < l->tsched.v) { /* moved forward and currently scheduled (by virtue of TSCHED_NOT_ON_HEAP == INT64_MIN) */ - l->tsched = l->tend; - ddsrt_fibheap_decrease_key (&lease_fhdef, &gv.leaseheap, l); + l->tsched = when; + ddsrt_fibheap_decrease_key (&lease_fhdef, &gv->leaseheap, l); trigger = true; } - else if (l->tsched.v == TSCHED_NOT_ON_HEAP && l->tend.v < T_NEVER) + else if (l->tsched.v == TSCHED_NOT_ON_HEAP && when.v < T_NEVER) { /* not currently scheduled, with a finite new expiry time */ - l->tsched = l->tend; - ddsrt_fibheap_insert (&lease_fhdef, &gv.leaseheap, l); + l->tsched = when; + ddsrt_fibheap_insert (&lease_fhdef, &gv->leaseheap, l); trigger = true; } - unlock_lease (l); - ddsrt_mutex_unlock (&gv.leaseheap_lock); + ddsrt_mutex_unlock (&gv->leaseheap_lock); /* see lease_register() */ if (trigger) - force_lease_check(); + force_lease_check (gv->gcreq_queue); } -int64_t check_and_handle_lease_expiration (nn_etime_t tnowE) +int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnowE) { struct lease *l; int64_t delay; - ddsrt_mutex_lock (&gv.leaseheap_lock); - while ((l = ddsrt_fibheap_min (&lease_fhdef, &gv.leaseheap)) != NULL && l->tsched.v <= tnowE.v) + ddsrt_mutex_lock (&gv->leaseheap_lock); + while ((l = ddsrt_fibheap_min (&lease_fhdef, &gv->leaseheap)) != NULL && l->tsched.v <= tnowE.v) { nn_guid_t g = l->entity->guid; enum entity_kind k = l->entity->kind; assert (l->tsched.v != TSCHED_NOT_ON_HEAP); - ddsrt_fibheap_extract_min (&lease_fhdef, &gv.leaseheap); - - lock_lease (l); - if (tnowE.v < l->tend.v) + ddsrt_fibheap_extract_min (&lease_fhdef, &gv->leaseheap); + /* only possible concurrent action is to move tend into the future (renew_lease), + all other operations occur with leaseheap_lock held */ + int64_t tend = (int64_t) ddsrt_atomic_ld64 (&l->tend); + if (tnowE.v < tend) { - if (l->tend.v == T_NEVER) { + if (tend == T_NEVER) { /* don't reinsert if it won't expire */ l->tsched.v = TSCHED_NOT_ON_HEAP; - unlock_lease (l); } else { - l->tsched = l->tend; - unlock_lease (l); - ddsrt_fibheap_insert (&lease_fhdef, &gv.leaseheap, l); + l->tsched.v = tend; + ddsrt_fibheap_insert (&lease_fhdef, &gv->leaseheap, l); } continue; } - DDS_LOG(DDS_LC_DISCOVERY, "lease expired: l %p guid "PGUIDFMT" tend %"PRId64" < now %"PRId64"\n", (void *) l, PGUID (g), l->tend.v, tnowE.v); + GVLOGDISC ("lease expired: l %p guid "PGUIDFMT" tend %"PRId64" < now %"PRId64"\n", (void *) l, PGUID (g), tend, tnowE.v); /* If the proxy participant is relying on another participant for writing its discovery data (on the privileged participant, @@ -263,108 +238,105 @@ int64_t check_and_handle_lease_expiration (nn_etime_t tnowE) if (k == EK_PROXY_PARTICIPANT) { struct proxy_participant *proxypp; - if ((proxypp = ephash_lookup_proxy_participant_guid (&g)) != NULL && - ephash_lookup_proxy_participant_guid (&proxypp->privileged_pp_guid) != NULL) + if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &g)) != NULL && + ephash_lookup_proxy_participant_guid (gv->guid_hash, &proxypp->privileged_pp_guid) != NULL) { - DDS_LOG(DDS_LC_DISCOVERY, "but postponing because privileged pp "PGUIDFMT" is still live\n", - PGUID (proxypp->privileged_pp_guid)); - l->tsched = l->tend = add_duration_to_etime (tnowE, 200 * T_MILLISECOND); - unlock_lease (l); - ddsrt_fibheap_insert (&lease_fhdef, &gv.leaseheap, l); + GVLOGDISC ("but postponing because privileged pp "PGUIDFMT" is still live\n", PGUID (proxypp->privileged_pp_guid)); + l->tsched = add_duration_to_etime (tnowE, 200 * T_MILLISECOND); + ddsrt_fibheap_insert (&lease_fhdef, &gv->leaseheap, l); continue; } } - unlock_lease (l); - l->tsched.v = TSCHED_NOT_ON_HEAP; - ddsrt_mutex_unlock (&gv.leaseheap_lock); + ddsrt_mutex_unlock (&gv->leaseheap_lock); switch (k) { case EK_PARTICIPANT: - delete_participant (&g); + delete_participant (gv, &g); break; case EK_PROXY_PARTICIPANT: - delete_proxy_participant_by_guid (&g, now(), 1); + delete_proxy_participant_by_guid (gv, &g, now(), 1); break; case EK_WRITER: - delete_writer_nolinger (&g); + delete_writer_nolinger (gv, &g); break; case EK_PROXY_WRITER: - delete_proxy_writer (&g, now(), 1); + delete_proxy_writer (gv, &g, now(), 1); break; case EK_READER: - (void)delete_reader (&g); + delete_reader (gv, &g); break; case EK_PROXY_READER: - delete_proxy_reader (&g, now(), 1); + delete_proxy_reader (gv, &g, now(), 1); break; } - ddsrt_mutex_lock (&gv.leaseheap_lock); + ddsrt_mutex_lock (&gv->leaseheap_lock); } delay = (l == NULL) ? T_NEVER : (l->tsched.v - tnowE.v); - ddsrt_mutex_unlock (&gv.leaseheap_lock); + ddsrt_mutex_unlock (&gv->leaseheap_lock); return delay; } /******/ -static void debug_print_rawdata (const char *msg, const void *data, size_t len) +static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len) { const unsigned char *c = data; size_t i; - DDS_TRACE("%s<", msg); + GVTRACE ("%s<", msg); for (i = 0; i < len; i++) { if (32 < c[i] && c[i] <= 127) - DDS_TRACE("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]); + GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]); else - DDS_TRACE("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]); + GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]); } - DDS_TRACE(">"); + GVTRACE (">"); } -void handle_PMD (UNUSED_ARG (const struct receiver_state *rst), nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) +void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len) { const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); struct proxy_participant *pp; nn_guid_t ppguid; - DDS_TRACE(" PMD ST%x", statusinfo); + RSTTRACE (" PMD ST%x", statusinfo); if (data->identifier != CDR_LE && data->identifier != CDR_BE) { - DDS_TRACE(" PMD data->identifier %u !?\n", ntohs (data->identifier)); + RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier)); return; } switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { case 0: if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader)) - debug_print_rawdata (" SHORT1", data, len); + debug_print_rawdata (rst->gv, " SHORT1", data, len); else { const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1); nn_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix); - unsigned kind = ntohl (pmd->kind); - unsigned length = bswap ? bswap4u (pmd->length) : pmd->length; - DDS_TRACE(" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length); + uint32_t kind = ntohl (pmd->kind); + uint32_t length = bswap ? bswap4u (pmd->length) : pmd->length; + RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length); if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length) - debug_print_rawdata (" SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value)); + debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value)); else - debug_print_rawdata ("", pmd->value, length); + debug_print_rawdata (rst->gv, "", pmd->value, length); ppguid.prefix = p; ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if ((pp = ephash_lookup_proxy_participant_guid (&ppguid)) == NULL) - DDS_TRACE(" PPunknown"); + if ((pp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL) + RSTTRACE (" PPunknown"); else { /* Renew lease if arrival of this message didn't already do so, also renew the lease of the virtual participant used for DS-discovered endpoints */ - if (!config.arrival_of_data_asserts_pp_and_ep_liveliness) - lease_renew (ddsrt_atomic_ldvoidp (&pp->lease), now_et ()); +#if 0 // FIXME: superfluous ... receipt of the message already did it */ + lease_renew (ddsrt_atomic_ldvoidp (&pp->lease), now_et ()); +#endif } } break; @@ -374,18 +346,18 @@ void handle_PMD (UNUSED_ARG (const struct receiver_state *rst), nn_wctime_t time case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER: /* Serialized key; BE or LE doesn't matter as both fields are defined as octets. */ - if (len < (int) (sizeof (struct CDRHeader) + sizeof (nn_guid_prefix_t))) - debug_print_rawdata (" SHORT3", data, len); + if (len < sizeof (struct CDRHeader) + sizeof (nn_guid_prefix_t)) + debug_print_rawdata (rst->gv, " SHORT3", data, len); else { ppguid.prefix = nn_ntoh_guid_prefix (*((nn_guid_prefix_t *) (data + 1))); ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if (delete_proxy_participant_by_guid (&ppguid, timestamp, 0) < 0) - DDS_TRACE(" unknown"); + if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0) + RSTTRACE (" unknown"); else - DDS_TRACE(" delete"); + RSTTRACE (" delete"); } break; } - DDS_TRACE("\n"); + RSTTRACE ("\n"); } diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c index 3f5ac27..bed0449 100644 --- a/src/core/ddsi/src/q_nwif.c +++ b/src/core/ddsi/src/q_nwif.c @@ -33,14 +33,14 @@ #include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsrt/avl.h" -static void print_sockerror (const char *msg) +static void print_sockerror (const struct ddsrt_log_cfg *logcfg, const char *msg) { - DDS_ERROR("SOCKET %s\n", msg); + DDS_CERROR (logcfg, "SOCKET %s\n", msg); } -unsigned locator_to_hopefully_unique_uint32 (const nn_locator_t *src) +uint32_t locator_to_hopefully_unique_uint32 (const nn_locator_t *src) { - unsigned id = 0; + uint32_t id = 0; if (src->kind == NN_LOCATOR_KIND_UDPv4 || src->kind == NN_LOCATOR_KIND_TCPv4) memcpy (&id, src->address + 12, sizeof (id)); else @@ -53,56 +53,62 @@ unsigned locator_to_hopefully_unique_uint32 (const nn_locator_t *src) ddsrt_md5_finish (&st, digest); memcpy (&id, digest, sizeof (id)); #else - DDS_FATAL("IPv6 unavailable\n"); + DDS_FATAL ("IPv6 unavailable\n"); #endif } return id; } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -void set_socket_diffserv (ddsrt_socket_t sock, int diffserv) +void set_socket_diffserv (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock, int diffserv) { if (ddsrt_setsockopt (sock, IPPROTO_IP, IP_TOS, (char*) &diffserv, sizeof (diffserv)) != DDS_RETCODE_OK) { - print_sockerror ("IP_TOS"); + print_sockerror (logcfg, "IP_TOS"); } } #endif #ifdef SO_NOSIGPIPE -static void set_socket_nosigpipe (ddsrt_socket_t sock) +static void set_socket_nosigpipe (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock) { int val = 1; if (ddsrt_setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, (char*) &val, sizeof (val)) != DDS_RETCODE_OK) { - print_sockerror ("SO_NOSIGPIPE"); + print_sockerror (logcfg, "SO_NOSIGPIPE"); } } #endif #ifdef TCP_NODELAY -static void set_socket_nodelay (ddsrt_socket_t sock) +static void set_socket_nodelay (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t sock) { int val = 1; if (ddsrt_setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char*) &val, sizeof (val)) != DDS_RETCODE_OK) { - print_sockerror ("TCP_NODELAY"); + print_sockerror (logcfg, "TCP_NODELAY"); } } #endif -static int set_rcvbuf (ddsrt_socket_t socket) +static int set_rcvbuf (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, const struct config_maybe_uint32 *min_size) { uint32_t ReceiveBufferSize; socklen_t optlen = (socklen_t) sizeof (ReceiveBufferSize); uint32_t socket_min_rcvbuf_size; - if (config.socket_min_rcvbuf_size.isdefault) + dds_return_t rc; + if (min_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) - { - print_sockerror ("get SO_RCVBUF"); + socket_min_rcvbuf_size = min_size->value; + 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_CLOG (DDS_LC_CONFIG, logcfg, "cannot retrieve socket receive buffer size\n"); + return 0; + } else if (rc != DDS_RETCODE_OK) { + print_sockerror (logcfg, "get SO_RCVBUF"); return -2; } if (ReceiveBufferSize < socket_min_rcvbuf_size) @@ -116,69 +122,73 @@ static int set_rcvbuf (ddsrt_socket_t socket) the option value back and check it is now set correctly. */ if (ddsrt_getsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, &optlen) != DDS_RETCODE_OK) { - print_sockerror ("get SO_RCVBUF"); + print_sockerror (logcfg, "get SO_RCVBUF"); return -2; } if (ReceiveBufferSize < socket_min_rcvbuf_size) { /* NN_ERROR does more than just DDS_ERROR(), hence the duplication */ - if (config.socket_min_rcvbuf_size.isdefault) - DDS_LOG(DDS_LC_CONFIG, "failed to increase socket receive buffer size to %"PRIu32" bytes, continuing with %"PRIu32" bytes\n", socket_min_rcvbuf_size, ReceiveBufferSize); - else - DDS_ERROR("failed to increase socket receive buffer size to %"PRIu32" bytes, continuing with %"PRIu32" bytes\n", socket_min_rcvbuf_size, ReceiveBufferSize); + DDS_CLOG (min_size->isdefault ? DDS_LC_CONFIG : DDS_LC_ERROR, logcfg, + "failed to increase socket receive buffer size to %"PRIu32" bytes, continuing with %"PRIu32" bytes\n", + socket_min_rcvbuf_size, ReceiveBufferSize); } else { - DDS_LOG(DDS_LC_CONFIG, "socket receive buffer size set to %"PRIu32" bytes\n", ReceiveBufferSize); + DDS_CLOG (DDS_LC_CONFIG, logcfg, "socket receive buffer size set to %"PRIu32" bytes\n", ReceiveBufferSize); } } return 0; } -static int set_sndbuf (ddsrt_socket_t socket) +static int set_sndbuf (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, uint32_t min_size) { unsigned SendBufferSize; socklen_t optlen = (socklen_t) sizeof(SendBufferSize); - if (ddsrt_getsockopt(socket, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen) != DDS_RETCODE_OK) - { - print_sockerror ("get SO_SNDBUF"); + dds_return_t rc; + rc = ddsrt_getsockopt( + socket, SOL_SOCKET, SO_SNDBUF,(char *)&SendBufferSize, &optlen); + if (rc == DDS_RETCODE_BAD_PARAMETER) { + DDS_CLOG (DDS_LC_CONFIG, logcfg, "cannot retrieve socket send buffer size\n"); + return 0; + } else if (rc != DDS_RETCODE_OK) { + print_sockerror (logcfg, "get SO_SNDBUF"); return -2; } - if (SendBufferSize < config.socket_min_sndbuf_size ) + if (SendBufferSize < min_size ) { /* make sure the send buffersize is at least the minimum required */ - SendBufferSize = config.socket_min_sndbuf_size; + SendBufferSize = min_size; if (ddsrt_setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (const char *)&SendBufferSize, sizeof (SendBufferSize)) != DDS_RETCODE_OK) { - print_sockerror ("SO_SNDBUF"); + print_sockerror (logcfg, "SO_SNDBUF"); return -2; } } return 0; } -static int maybe_set_dont_route (ddsrt_socket_t socket) +static int maybe_set_dont_route (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t socket, const struct config *config) { - if (config.dontRoute) + if (config->dontRoute) { #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6) + if (config->transport_selector == TRANS_TCP6 || config->transport_selector == TRANS_UDP6) { unsigned ipv6Flag = 1; if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ipv6Flag, sizeof (ipv6Flag)) != DDS_RETCODE_OK) { - print_sockerror ("IPV6_UNICAST_HOPS"); + print_sockerror (logcfg, "IPV6_UNICAST_HOPS"); return -2; } } else #endif - if (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP) + if (config->transport_selector == TRANS_TCP || config->transport_selector == TRANS_UDP) { int one = 1; if (ddsrt_setsockopt (socket, SOL_SOCKET, SO_DONTROUTE, (char *) &one, sizeof (one)) != DDS_RETCODE_OK) { - print_sockerror ("SO_DONTROUTE"); + print_sockerror (logcfg, "SO_DONTROUTE"); return -2; } } @@ -186,26 +196,30 @@ static int maybe_set_dont_route (ddsrt_socket_t socket) return 0; } -static int set_reuse_options (ddsrt_socket_t socket) +static int set_reuse_options (const struct ddsrt_log_cfg *logcfg, 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) - { - print_sockerror ("SO_REUSEADDR"); + dds_return_t rc = ddsrt_setsockopt ( + socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof (one)); + if (rc == DDS_RETCODE_BAD_PARAMETER) { + DDS_CLOG (DDS_LC_CONFIG, logcfg, "cannot enable address reuse on socket\n"); + return 0; + } else if (rc != DDS_RETCODE_OK) { + print_sockerror (logcfg, "SO_REUSEADDR"); return -2; } + return 0; } -static int bind_socket (ddsrt_socket_t socket, unsigned short port) +static int bind_socket (ddsrt_socket_t socket, unsigned short port, const struct q_globals *gv) { - dds_retcode_t rc = DDS_RETCODE_ERROR; + dds_return_t rc = DDS_RETCODE_ERROR; #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6) + if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6) { struct sockaddr_in6 socketname; memset (&socketname, 0, sizeof (socketname)); @@ -213,13 +227,13 @@ static int bind_socket (ddsrt_socket_t socket, unsigned short port) socketname.sin6_port = htons (port); socketname.sin6_addr = ddsrt_in6addr_any; if (IN6_IS_ADDR_LINKLOCAL (&socketname.sin6_addr)) { - socketname.sin6_scope_id = gv.interfaceNo; + socketname.sin6_scope_id = gv->interfaceNo; } rc = ddsrt_bind (socket, (struct sockaddr *) &socketname, sizeof (socketname)); } else #endif - if (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP) + if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP) { struct sockaddr_in socketname; socketname.sin_family = AF_INET; @@ -229,94 +243,94 @@ static int bind_socket (ddsrt_socket_t socket, unsigned short port) } if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_PRECONDITION_NOT_MET) { - print_sockerror ("bind"); + print_sockerror (&gv->logconfig, "bind"); } return (rc == DDS_RETCODE_OK) ? 0 : -1; } #if DDSRT_HAVE_IPV6 -static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket) +static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket, const struct q_globals *gv) { - unsigned interfaceNo = gv.interfaceNo; - unsigned ttl = (unsigned) config.multicast_ttl; + unsigned interfaceNo = gv->interfaceNo; + unsigned ttl = (unsigned) gv->config.multicast_ttl; unsigned loop; if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceNo, sizeof (interfaceNo)) != DDS_RETCODE_OK) { - print_sockerror ("IPV6_MULTICAST_IF"); + print_sockerror (&gv->logconfig, "IPV6_MULTICAST_IF"); return -2; } if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof (ttl)) != DDS_RETCODE_OK) { - print_sockerror ("IPV6_MULTICAST_HOPS"); + print_sockerror (&gv->logconfig, "IPV6_MULTICAST_HOPS"); return -2; } - loop = (unsigned) !!config.enableMulticastLoopback; + loop = (unsigned) !!gv->config.enableMulticastLoopback; if (ddsrt_setsockopt (socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, sizeof (loop)) != DDS_RETCODE_OK) { - print_sockerror ("IPV6_MULTICAST_LOOP"); + print_sockerror (&gv->logconfig, "IPV6_MULTICAST_LOOP"); return -2; } return 0; } #endif -static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket) +static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket, const struct q_globals *gv) { - unsigned char ttl = (unsigned char) config.multicast_ttl; + unsigned char ttl = (unsigned char) gv->config.multicast_ttl; unsigned char loop; - dds_retcode_t ret; + dds_return_t ret; -#if defined __linux || defined __APPLE__ - if (config.use_multicast_if_mreqn) +#if (defined(__linux) || defined(__APPLE__)) && !LWIP_SOCKET + if (gv->config.use_multicast_if_mreqn) { struct ip_mreqn mreqn; memset (&mreqn, 0, sizeof (mreqn)); /* looks like imr_multiaddr is not relevant, not sure about imr_address */ mreqn.imr_multiaddr.s_addr = htonl (INADDR_ANY); - if (config.use_multicast_if_mreqn > 1) - memcpy (&mreqn.imr_address.s_addr, gv.ownloc.address + 12, 4); + if (gv->config.use_multicast_if_mreqn > 1) + memcpy (&mreqn.imr_address.s_addr, gv->ownloc.address + 12, 4); else mreqn.imr_address.s_addr = htonl (INADDR_ANY); - mreqn.imr_ifindex = (int) gv.interfaceNo; + mreqn.imr_ifindex = (int) gv->interfaceNo; ret = ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof (mreqn)); } else #endif { - ret = ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, gv.ownloc.address + 12, 4); + ret = ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, gv->ownloc.address + 12, 4); } if (ret != DDS_RETCODE_OK) { - print_sockerror ("IP_MULTICAST_IF"); + print_sockerror (&gv->logconfig, "IP_MULTICAST_IF"); return -2; } if (ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttl, sizeof (ttl)) != DDS_RETCODE_OK) { - print_sockerror ("IP_MULICAST_TTL"); + print_sockerror (&gv->logconfig, "IP_MULICAST_TTL"); return -2; } - loop = (unsigned char) config.enableMulticastLoopback; + loop = (unsigned char) gv->config.enableMulticastLoopback; if (ddsrt_setsockopt (socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof (loop)) != DDS_RETCODE_OK) { - print_sockerror ("IP_MULTICAST_LOOP"); + print_sockerror (&gv->logconfig, "IP_MULTICAST_LOOP"); return -2; } return 0; } -static int set_mc_options_transmit (ddsrt_socket_t socket) +static int set_mc_options_transmit (ddsrt_socket_t socket, const struct q_globals *gv) { #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6) + if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6) { - return set_mc_options_transmit_ipv6 (socket); + return set_mc_options_transmit_ipv6 (socket, gv); } else #endif - if (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP) + if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP) { - return set_mc_options_transmit_ipv4 (socket); + return set_mc_options_transmit_ipv4 (socket, gv); } else { @@ -324,25 +338,20 @@ static int set_mc_options_transmit (ddsrt_socket_t socket) } } -int make_socket -( - ddsrt_socket_t * sock, - unsigned short port, - bool stream, - bool reuse -) +int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, const struct q_globals *gv) { + /* FIXME: this stuff has to move to the transports */ int rc = -2; - dds_retcode_t ret; + dds_return_t ret; #if DDSRT_HAVE_IPV6 - if (config.transport_selector == TRANS_TCP6 || config.transport_selector == TRANS_UDP6) + if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6) { ret = ddsrt_socket(sock, AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0); } else #endif - if (config.transport_selector == TRANS_TCP || config.transport_selector == TRANS_UDP) + if (gv->config.transport_selector == TRANS_TCP || gv->config.transport_selector == TRANS_UDP) { ret = ddsrt_socket(sock, AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0); } @@ -353,21 +362,21 @@ int make_socket if (ret != DDS_RETCODE_OK) { - print_sockerror ("socket"); + print_sockerror (&gv->logconfig, "socket"); return rc; } - if (port && reuse && ((rc = set_reuse_options (*sock)) < 0)) + if (port && reuse && ((rc = set_reuse_options (&gv->logconfig, *sock)) < 0)) { goto fail; } if ( - (rc = set_rcvbuf (*sock) < 0) || - (rc = set_sndbuf (*sock) < 0) || - ((rc = maybe_set_dont_route (*sock)) < 0) || - ((rc = bind_socket (*sock, port)) < 0) + (rc = set_rcvbuf (&gv->logconfig, *sock, &gv->config.socket_min_rcvbuf_size) < 0) || + (rc = set_sndbuf (&gv->logconfig, *sock, gv->config.socket_min_sndbuf_size) < 0) || + ((rc = maybe_set_dont_route (&gv->logconfig, *sock, &gv->config)) < 0) || + ((rc = bind_socket (*sock, port, gv)) < 0) ) { goto fail; @@ -375,7 +384,7 @@ int make_socket if (! stream) { - if ((rc = set_mc_options_transmit (*sock)) < 0) + if ((rc = set_mc_options_transmit (*sock, gv)) < 0) { goto fail; } @@ -384,12 +393,12 @@ int make_socket if (stream) { #ifdef SO_NOSIGPIPE - set_socket_nosigpipe (*sock); + set_socket_nosigpipe (&gv->logconfig, *sock); #endif #ifdef TCP_NODELAY - if (config.tcp_nodelay) + if (gv->config.tcp_nodelay) { - set_socket_nodelay (*sock); + set_socket_nodelay (&gv->logconfig, *sock); } #endif } @@ -403,9 +412,9 @@ fail: return rc; } -static int multicast_override(const char *ifname) +static int multicast_override(const char *ifname, const struct config *config) { - char *copy = ddsrt_strdup (config.assumeMulticastCapable), *cursor = copy, *tok; + char *copy = ddsrt_strdup (config->assumeMulticastCapable), *cursor = copy, *tok; int match = 0; if (copy != NULL) { @@ -424,7 +433,7 @@ static int multicast_override(const char *ifname) #include #endif -int find_own_ip (const char *requested_address) +int find_own_ip (struct q_globals *gv, const char *requested_address) { const char *sep = " "; char last_if_name[80] = ""; @@ -437,18 +446,18 @@ int find_own_ip (const char *requested_address) int selected_idx = -1; char addrbuf[DDSI_LOCSTRLEN]; - DDS_LOG(DDS_LC_CONFIG, "interfaces:"); + GVLOG (DDS_LC_CONFIG, "interfaces:"); { int ret; - ret = ddsi_enumerate_interfaces(gv.m_factory, &ifa_root); + ret = ddsi_enumerate_interfaces(gv->m_factory, gv->config.transport_selector, &ifa_root); if (ret < 0) { - DDS_ERROR("ddsi_enumerate_interfaces(%s): %d\n", gv.m_factory->m_typename, ret); + GVERROR ("ddsi_enumerate_interfaces(%s): %d\n", gv->m_factory->m_typename, ret); return 0; } } - gv.n_interfaces = 0; + gv->n_interfaces = 0; last_if_name[0] = 0; for (ifa = ifa_root; ifa != NULL; ifa = ifa->next) { @@ -458,23 +467,35 @@ int find_own_ip (const char *requested_address) ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name)); if (strcmp (if_name, last_if_name)) - DDS_LOG(DDS_LC_CONFIG, "%s%s", sep, if_name); + GVLOG (DDS_LC_CONFIG, "%s%s", sep, if_name); ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name)); /* interface must be up */ if ((ifa->flags & IFF_UP) == 0) { - DDS_LOG(DDS_LC_CONFIG, " (interface down)"); + GVLOG (DDS_LC_CONFIG, " (interface down)"); continue; } else if (ddsrt_sockaddr_isunspecified(ifa->addr)) { - DDS_LOG(DDS_LC_CONFIG, " (address unspecified)"); + GVLOG (DDS_LC_CONFIG, " (address unspecified)"); continue; } -#ifdef __linux + switch (ifa->type) + { + case DDSRT_IFTYPE_WIFI: + DDS_LOG(DDS_LC_CONFIG, " wireless"); + break; + case DDSRT_IFTYPE_WIRED: + DDS_LOG(DDS_LC_CONFIG, " wired"); + break; + case DDSRT_IFTYPE_UNKNOWN: + break; + } + +#if defined(__linux) && !LWIP_SOCKET if (ifa->addr->sa_family == AF_PACKET) { /* FIXME: weirdo warning warranted */ - nn_locator_t *l = &gv.interfaces[gv.n_interfaces].loc; + nn_locator_t *l = &gv->interfaces[gv->n_interfaces].loc; l->kind = NN_LOCATOR_KIND_RAWETH; l->port = NN_LOCATOR_PORT_INVALID; memset(l->address, 0, 10); @@ -483,14 +504,14 @@ int find_own_ip (const char *requested_address) else #endif { - ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].loc, ifa->addr, gv.m_factory->m_kind); + ddsi_ipaddr_to_loc(&gv->interfaces[gv->n_interfaces].loc, ifa->addr, gv->m_factory->m_kind); } - ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv.interfaces[gv.n_interfaces].loc); - DDS_LOG(DDS_LC_CONFIG, " %s(", addrbuf); + ddsi_locator_to_string_no_port(gv, addrbuf, sizeof(addrbuf), &gv->interfaces[gv->n_interfaces].loc); + GVLOG (DDS_LC_CONFIG, " %s(", addrbuf); - if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name)) + if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name, &gv->config)) { - DDS_LOG(DDS_LC_CONFIG, "assume-mc:"); + GVLOG (DDS_LC_CONFIG, "assume-mc:"); ifa->flags |= IFF_MULTICAST; } @@ -533,13 +554,13 @@ int find_own_ip (const char *requested_address) q += 2; } - DDS_LOG(DDS_LC_CONFIG, "q%d)", q); + GVLOG (DDS_LC_CONFIG, "q%d)", q); if (q == quality) { - maxq_list[maxq_count] = gv.n_interfaces; + maxq_list[maxq_count] = gv->n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count++; } else if (q > quality) { - maxq_list[0] = gv.n_interfaces; + maxq_list[0] = gv->n_interfaces; maxq_strlen += 2 + strlen (if_name); maxq_count = 1; quality = q; @@ -547,21 +568,22 @@ int find_own_ip (const char *requested_address) if (ifa->addr->sa_family == AF_INET && ifa->netmask) { - ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].netmask, ifa->netmask, gv.m_factory->m_kind); + ddsi_ipaddr_to_loc(&gv->interfaces[gv->n_interfaces].netmask, ifa->netmask, gv->m_factory->m_kind); } else { - gv.interfaces[gv.n_interfaces].netmask.kind = gv.m_factory->m_kind; - gv.interfaces[gv.n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID; - memset(&gv.interfaces[gv.n_interfaces].netmask.address, 0, sizeof(gv.interfaces[gv.n_interfaces].netmask.address)); + gv->interfaces[gv->n_interfaces].netmask.kind = gv->m_factory->m_kind; + gv->interfaces[gv->n_interfaces].netmask.port = NN_LOCATOR_PORT_INVALID; + memset(&gv->interfaces[gv->n_interfaces].netmask.address, 0, sizeof(gv->interfaces[gv->n_interfaces].netmask.address)); } - gv.interfaces[gv.n_interfaces].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0); - gv.interfaces[gv.n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0); - gv.interfaces[gv.n_interfaces].if_index = ifa->index; - gv.interfaces[gv.n_interfaces].name = ddsrt_strdup (if_name); - gv.n_interfaces++; + gv->interfaces[gv->n_interfaces].mc_capable = ((ifa->flags & IFF_MULTICAST) != 0); + gv->interfaces[gv->n_interfaces].mc_flaky = ((ifa->type == DDSRT_IFTYPE_WIFI) != 0); + gv->interfaces[gv->n_interfaces].point_to_point = ((ifa->flags & IFF_POINTOPOINT) != 0); + gv->interfaces[gv->n_interfaces].if_index = ifa->index; + gv->interfaces[gv->n_interfaces].name = ddsrt_strdup (if_name); + gv->n_interfaces++; } - DDS_LOG(DDS_LC_CONFIG, "\n"); + GVLOG (DDS_LC_CONFIG, "\n"); ddsrt_freeifaddrs (ifa_root); if (requested_address == NULL) @@ -571,51 +593,51 @@ int find_own_ip (const char *requested_address) const int idx = maxq_list[0]; char *names; int p; - ddsi_locator_to_string_no_port (addrbuf, sizeof(addrbuf), &gv.interfaces[idx].loc); + ddsi_locator_to_string_no_port (gv, addrbuf, sizeof(addrbuf), &gv->interfaces[idx].loc); names = ddsrt_malloc (maxq_strlen + 1); p = 0; for (i = 0; i < maxq_count && (size_t) p < maxq_strlen; i++) - p += snprintf (names + p, maxq_strlen - (size_t) p, ", %s", gv.interfaces[maxq_list[i]].name); - DDS_WARNING("using network interface %s (%s) selected arbitrarily from: %s\n", - gv.interfaces[idx].name, addrbuf, names + 2); + p += snprintf (names + p, maxq_strlen - (size_t) p, ", %s", gv->interfaces[maxq_list[i]].name); + GVWARNING ("using network interface %s (%s) selected arbitrarily from: %s\n", + gv->interfaces[idx].name, addrbuf, names + 2); ddsrt_free (names); } if (maxq_count > 0) selected_idx = maxq_list[0]; else - DDS_ERROR("failed to determine default own IP address\n"); + GVERROR ("failed to determine default own IP address\n"); } else { nn_locator_t req; /* Presumably an interface name */ - for (i = 0; i < gv.n_interfaces; i++) + for (i = 0; i < gv->n_interfaces; i++) { - if (strcmp (gv.interfaces[i].name, config.networkAddressString) == 0) + if (strcmp (gv->interfaces[i].name, gv->config.networkAddressString) == 0) break; } - if (i < gv.n_interfaces) + if (i < gv->n_interfaces) ; /* got a match */ - else if (ddsi_locator_from_string(&req, config.networkAddressString) != AFSR_OK) - ; /* not good, i = gv.n_interfaces, so error handling will kick in */ + else if (ddsi_locator_from_string(gv, &req, gv->config.networkAddressString, gv->m_factory) != AFSR_OK) + ; /* not good, i = gv->n_interfaces, so error handling will kick in */ else { /* Try an exact match on the address */ - for (i = 0; i < gv.n_interfaces; i++) - if (compare_locators(&gv.interfaces[i].loc, &req) == 0) + for (i = 0; i < gv->n_interfaces; i++) + if (compare_locators(&gv->interfaces[i].loc, &req) == 0) break; - if (i == gv.n_interfaces && req.kind == NN_LOCATOR_KIND_UDPv4) + if (i == gv->n_interfaces && req.kind == NN_LOCATOR_KIND_UDPv4) { /* Try matching on network portion only, where the network portion is based on the netmask of the interface under consideration */ - for (i = 0; i < gv.n_interfaces; i++) + for (i = 0; i < gv->n_interfaces; i++) { uint32_t req1, ip1, nm1; memcpy (&req1, req.address + 12, sizeof (req1)); - memcpy (&ip1, gv.interfaces[i].loc.address + 12, sizeof (ip1)); - memcpy (&nm1, gv.interfaces[i].netmask.address + 12, sizeof (nm1)); + memcpy (&ip1, gv->interfaces[i].loc.address + 12, sizeof (ip1)); + memcpy (&nm1, gv->interfaces[i].netmask.address + 12, sizeof (nm1)); /* If the host portion of the requested address is non-zero, skip this interface */ @@ -628,33 +650,33 @@ int find_own_ip (const char *requested_address) } } - if (i < gv.n_interfaces) + if (i < gv->n_interfaces) selected_idx = i; else - DDS_ERROR("%s: does not match an available interface\n", config.networkAddressString); + GVERROR ("%s: does not match an available interface\n", gv->config.networkAddressString); } if (selected_idx < 0) return 0; else { - gv.ownloc = gv.interfaces[selected_idx].loc; - gv.selected_interface = selected_idx; - gv.interfaceNo = gv.interfaces[selected_idx].if_index; + gv->ownloc = gv->interfaces[selected_idx].loc; + gv->selected_interface = selected_idx; + gv->interfaceNo = gv->interfaces[selected_idx].if_index; #if DDSRT_HAVE_IPV6 - if (gv.extloc.kind == NN_LOCATOR_KIND_TCPv6 || gv.extloc.kind == NN_LOCATOR_KIND_UDPv6) + if (gv->extloc.kind == NN_LOCATOR_KIND_TCPv6 || gv->extloc.kind == NN_LOCATOR_KIND_UDPv6) { struct sockaddr_in6 addr; - memcpy(&addr.sin6_addr, gv.ownloc.address, sizeof(addr.sin6_addr)); - gv.ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&addr.sin6_addr) != 0; + memcpy(&addr.sin6_addr, gv->ownloc.address, sizeof(addr.sin6_addr)); + gv->ipv6_link_local = IN6_IS_ADDR_LINKLOCAL (&addr.sin6_addr) != 0; } else { - gv.ipv6_link_local = 0; + gv->ipv6_link_local = 0; } #endif - DDS_LOG(DDS_LC_CONFIG, "selected interface: %s (index %u)\n", - gv.interfaces[selected_idx].name, gv.interfaceNo); + GVLOG (DDS_LC_CONFIG, "selected interface: %s (index %u)\n", + gv->interfaces[selected_idx].name, gv->interfaceNo); return 1; } diff --git a/src/core/ddsi/src/q_pcap.c b/src/core/ddsi/src/q_pcap.c index c48e636..3fb0e68 100644 --- a/src/core/ddsi/src/q_pcap.c +++ b/src/core/ddsi/src/q_pcap.c @@ -77,15 +77,15 @@ static const ipv4_hdr_t ipv4_hdr_template = { #define IPV4_HDR_SIZE 20 #define UDP_HDR_SIZE 8 -DDSRT_WARNING_MSVC_OFF(4996); -FILE *new_pcap_file (const char *name) +FILE *new_pcap_file (const struct ddsrt_log_cfg *logcfg, const char *name) { + DDSRT_WARNING_MSVC_OFF(4996); FILE *fp; pcap_hdr_t hdr; if ((fp = fopen (name, "wb")) == NULL) { - DDS_WARNING ("packet capture disabled: file %s could not be opened for writing\n", name); + DDS_CWARNING (logcfg, "packet capture disabled: file %s could not be opened for writing\n", name); return NULL; } @@ -99,8 +99,8 @@ FILE *new_pcap_file (const char *name) fwrite (&hdr, sizeof (hdr), 1, fp); return fp; + DDSRT_WARNING_MSVC_ON(4996); } -DDSRT_WARNING_MSVC_ON(4996); static void write_data (FILE *fp, const ddsrt_msghdr_t *msghdr, size_t sz) { @@ -127,17 +127,9 @@ static uint16_t calc_ipv4_checksum (const uint16_t *x) return (uint16_t) ~s; } -void write_pcap_received -( - FILE * fp, - nn_wctime_t tstamp, - const struct sockaddr_storage * src, - const struct sockaddr_storage * dst, - unsigned char * buf, - size_t sz -) +void write_pcap_received (struct q_globals *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, const struct sockaddr_storage *dst, unsigned char *buf, size_t sz) { - if (config.transport_selector == TRANS_UDP) + if (gv->config.transport_selector == TRANS_UDP) { pcaprec_hdr_t pcap_hdr; union { @@ -147,37 +139,30 @@ void write_pcap_received udp_hdr_t udp_hdr; size_t sz_ud = sz + UDP_HDR_SIZE; size_t sz_iud = sz_ud + IPV4_HDR_SIZE; - ddsrt_mutex_lock (&gv.pcap_lock); + ddsrt_mutex_lock (&gv->pcap_lock); wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp); pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud; - fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, fp); + fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp); u.ipv4_hdr = ipv4_hdr_template; u.ipv4_hdr.totallength = toBE2u ((unsigned short) sz_iud); u.ipv4_hdr.ttl = 128; u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr; u.ipv4_hdr.dstip = ((struct sockaddr_in*) dst)->sin_addr.s_addr; u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x); - fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, fp); + fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp); udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port; udp_hdr.dstport = ((struct sockaddr_in*) dst)->sin_port; udp_hdr.length = toBE2u ((unsigned short) sz_ud); udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */ - fwrite (&udp_hdr, sizeof (udp_hdr), 1, fp); - fwrite (buf, sz, 1, fp); - ddsrt_mutex_unlock (&gv.pcap_lock); + fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp); + fwrite (buf, sz, 1, gv->pcap_fp); + ddsrt_mutex_unlock (&gv->pcap_lock); } } -void write_pcap_sent -( - FILE * fp, - nn_wctime_t tstamp, - const struct sockaddr_storage * src, - const ddsrt_msghdr_t * hdr, - size_t sz -) +void write_pcap_sent (struct q_globals *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, const ddsrt_msghdr_t *hdr, size_t sz) { - if (config.transport_selector == TRANS_UDP) + if (gv->config.transport_selector == TRANS_UDP) { pcaprec_hdr_t pcap_hdr; union { @@ -187,23 +172,23 @@ void write_pcap_sent udp_hdr_t udp_hdr; size_t sz_ud = sz + UDP_HDR_SIZE; size_t sz_iud = sz_ud + IPV4_HDR_SIZE; - ddsrt_mutex_lock (&gv.pcap_lock); + ddsrt_mutex_lock (&gv->pcap_lock); wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp); pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud; - fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, fp); + fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp); u.ipv4_hdr = ipv4_hdr_template; u.ipv4_hdr.totallength = toBE2u ((unsigned short) sz_iud); u.ipv4_hdr.ttl = 255; u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr; u.ipv4_hdr.dstip = ((struct sockaddr_in*) hdr->msg_name)->sin_addr.s_addr; u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x); - fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, fp); + fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp); udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port; udp_hdr.dstport = ((struct sockaddr_in*) hdr->msg_name)->sin_port; udp_hdr.length = toBE2u ((unsigned short) sz_ud); udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */ - fwrite (&udp_hdr, sizeof (udp_hdr), 1, fp); - write_data (fp, hdr, sz); - ddsrt_mutex_unlock (&gv.pcap_lock); + fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp); + write_data (gv->pcap_fp, hdr, sz); + ddsrt_mutex_unlock (&gv->pcap_lock); } } diff --git a/src/core/ddsi/src/q_plist.c b/src/core/ddsi/src/q_plist.c index a83f9f9..6714bda 100644 --- a/src/core/ddsi/src/q_plist.c +++ b/src/core/ddsi/src/q_plist.c @@ -17,25 +17,32 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/static_assert.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_xmsg.h" +#include "dds/ddsi/ddsi_vendor.h" +#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_globals.h" #include "dds/ddsi/q_protocol.h" /* for NN_STATUSINFO_... */ #include "dds/ddsi/q_radmin.h" /* for nn_plist_quickscan */ -#include "dds/ddsi/q_static_assert.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/q_misc.h" /* for vendor_is_... */ +/* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1 + supported for backwards compatibility) ... on the wire however + it must be -1 */ +DDSRT_STATIC_ASSERT(DDS_LENGTH_UNLIMITED == -1); + /* These are internal to the parameter list processing. We never generate them, and we never want to do see them anywhere outside the actual parsing of an incoming parameter list. (There are @@ -51,7 +58,7 @@ #define PPTMP_METATRAFFIC_MULTICAST_PORT (1 << 6) typedef struct nn_ipaddress_params_tmp { - unsigned present; + uint32_t present; nn_ipv4address_t multicast_ipaddress; nn_ipv4address_t default_unicast_ipaddress; @@ -68,538 +75,1486 @@ struct dd { unsigned bswap: 1; nn_protocol_version_t protocol_version; nn_vendorid_t vendorid; + ddsi_tran_factory_t factory; }; -struct cdroctetseq { - unsigned len; - unsigned char value[1]; +#define PDF_QOS 1 /* part of dds_qos_t */ +#define PDF_FUNCTION 2 /* use special functions */ +#define PDF_ALLOWMULTI 4 /* allow multiple copies -- do not use with Z or memory will leak */ + +struct flagset { + uint64_t *present; + uint64_t *aliased; + uint64_t wanted; }; -static void log_octetseq (uint32_t cat, unsigned n, const unsigned char *xs); +/* Instructions for the generic serializer (&c) that handles most parameters. + The "packed" attribute means single-byte instructions on GCC and Clang. */ +enum pserop { + XSTOP, + XO, /* octet sequence */ + XS, /* string */ + XZ, /* string sequence */ + XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */ + Xl, /* length, int32_t, -1 or >= 1 */ + Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */ + Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */ + XD, XDx2, /* duration, 1 .. 2 in a row */ + Xo, Xox2, /* octet, 1 .. 2 in a row */ + Xb, Xbx2, /* boolean, 1 .. 2 in a row */ + XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */ + XG, /* GUID */ + XK /* keyhash */ +} ddsrt_attribute_packed; -static size_t align4u (size_t x) +struct piddesc { + nn_parameterid_t pid; /* parameter id or PID_PAD if strictly local */ + uint16_t flags; /* see PDF_xxx flags */ + uint64_t present_flag; /* flag in plist.present / plist.qos.present */ + const char *name; /* name for reporting invalid input */ + size_t plist_offset; /* offset from start of nn_plist_t */ + size_t size; /* in-memory size for copying */ + union { + /* descriptor for generic code: 4 is enough for the current set of + parameters, compiler will warn if one ever tries to use more than + will fit; on non-GCC/Clang and 32-bits machines */ + const enum pserop desc[4]; + struct { + dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff); + dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff); + dds_return_t (*unalias) (void * __restrict dst, size_t * __restrict dstoff); + dds_return_t (*fini) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag); + dds_return_t (*valid) (const void *src, size_t srcoff); + bool (*equal) (const void *srcx, const void *srcy, size_t srcoff); + } f; + } op; + dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd); +}; + +static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs); +static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q); +static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q); +static dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr); +static dds_return_t validate_external_duration (const ddsi_duration_t *d); +static dds_return_t validate_durability_service_qospolicy_acceptzero (const dds_durability_service_qospolicy_t *q, bool acceptzero); +static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const struct dd *dd, const struct ddsi_tran_factory *factory); +static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero, bool strict); +static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b); +static dds_return_t nn_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos, bool strict); + +static size_t align4size (size_t x) { - return (x + 3u) & ~(size_t)3; + return (x + 3) & ~(size_t)3; } +static void *deser_generic_dst (void * __restrict dst, size_t *dstoff, size_t align) +{ + *dstoff = (*dstoff + align - 1) & ~(align - 1); + return (char *) dst + *dstoff; +} + +static const void *deser_generic_src (const void * __restrict src, size_t *srcoff, size_t align) +{ + *srcoff = (*srcoff + align - 1) & ~(align - 1); + return (const char *) src + *srcoff; +} + +static void *ser_generic_align4 (char * __restrict p, size_t * __restrict off) +{ + const size_t off1 = align4size (*off); + size_t pad = off1 - *off; + char *dst = p + *off; + *off = off1; + while (pad--) + *dst++ = 0; + return dst; +} + +static dds_return_t deser_uint32 (uint32_t *dst, const struct dd * __restrict dd, size_t * __restrict off) +{ + size_t off1 = (*off + 3) & ~(size_t)3; + uint32_t tmp; + if (off1 + 4 > dd->bufsz) + return DDS_RETCODE_BAD_PARAMETER; + tmp = *((uint32_t *) (dd->buf + off1)); + if (dd->bswap) + tmp = bswap4u (tmp); + *dst = tmp; + *off = off1 + 4; + return 0; +} + +#define alignof(type_) offsetof (struct { char c; type_ d; }, d) + +static dds_return_t deser_reliability (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + DDSRT_STATIC_ASSERT (DDS_EXTERNAL_RELIABILITY_BEST_EFFORT == 1 && DDS_EXTERNAL_RELIABILITY_RELIABLE == 2 && + DDS_RELIABILITY_BEST_EFFORT == 0 && DDS_RELIABILITY_RELIABLE == 1); + dds_reliability_qospolicy_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_reliability_qospolicy_t)); + uint32_t kind, mbtsec, mbtfrac; + ddsi_duration_t mbt; + if (deser_uint32 (&kind, dd, srcoff) < 0 || deser_uint32 (&mbtsec, dd, srcoff) < 0 || deser_uint32 (&mbtfrac, dd, srcoff) < 0) + return DDS_RETCODE_BAD_PARAMETER; + if (kind < 1 || kind > 2) + return DDS_RETCODE_BAD_PARAMETER; + mbt.seconds = (int32_t) mbtsec; + mbt.fraction = mbtfrac; + if (validate_external_duration (&mbt) < 0) + return DDS_RETCODE_BAD_PARAMETER; + x->kind = (enum dds_reliability_kind) (kind - 1); + x->max_blocking_time = nn_from_ddsi_duration (mbt); + *dstoff += sizeof (*x); + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_reliability (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + DDSRT_STATIC_ASSERT (DDS_EXTERNAL_RELIABILITY_BEST_EFFORT == 1 && DDS_EXTERNAL_RELIABILITY_RELIABLE == 2 && + DDS_RELIABILITY_BEST_EFFORT == 0 && DDS_RELIABILITY_RELIABLE == 1); + dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); + ddsi_duration_t mbt = nn_to_ddsi_duration (x->max_blocking_time); + uint32_t * const p = nn_xmsg_addpar (xmsg, pid, 3 * sizeof (uint32_t)); + p[0] = 1 + (uint32_t) x->kind; + p[1] = (uint32_t) mbt.seconds; + p[2] = mbt.fraction; + return 0; +} + +static dds_return_t valid_reliability (const void *src, size_t srcoff) +{ + dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); + if ((x->kind == DDS_RELIABILITY_BEST_EFFORT || x->kind == DDS_RELIABILITY_RELIABLE) && x->max_blocking_time >= 0) + return 0; + else + return DDS_RETCODE_BAD_PARAMETER; +} + +static bool equal_reliability (const void *srcx, const void *srcy, size_t srcoff) +{ + dds_reliability_qospolicy_t const * const x = deser_generic_src (srcx, &srcoff, alignof (dds_reliability_qospolicy_t)); + dds_reliability_qospolicy_t const * const y = deser_generic_src (srcy, &srcoff, alignof (dds_reliability_qospolicy_t)); + return x->kind == y->kind && x->max_blocking_time == y->max_blocking_time; +} + +static dds_return_t deser_statusinfo (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_reliability_qospolicy_t)); + size_t srcoff1 = (*srcoff + 3) & ~(size_t)3; + if (srcoff1 + 4 > dd->bufsz) + return DDS_RETCODE_BAD_PARAMETER; + /* status info is always in BE format (it is an array of 4 octets according to the spec) -- + fortunately we have 4 byte alignment anyway -- and can have bits set we don't grok + (which we discard) */ + *x = fromBE4u (*((uint32_t *) (dd->buf + srcoff1))) & NN_STATUSINFO_STANDARDIZED; + *dstoff += sizeof (*x); + *srcoff = srcoff1 + 4; + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_statusinfo (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + uint32_t * const p = nn_xmsg_addpar (xmsg, pid, sizeof (uint32_t)); + *p = toBE4u (*x); + return 0; +} + +static dds_return_t deser_locator (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + /* FIXME: don't want to modify do_locator just yet, and don't want to require that a + locator is the only thing in the descriptor string (even though it actually always is), + so do alignment explicitly, fake a temporary input buffer and advance the source buffer */ + *srcoff = (*srcoff + 3) & ~(size_t)3; + if (*srcoff > dd->bufsz || dd->bufsz - *srcoff < 24) + return DDS_RETCODE_BAD_PARAMETER; + struct dd tmpdd = *dd; + tmpdd.buf += *srcoff; + tmpdd.bufsz -= *srcoff; + if (do_locator (x, flagset->present, flagset->wanted, flag, &tmpdd, dd->factory) < 0) + return DDS_RETCODE_BAD_PARAMETER; + *srcoff += 24; + *dstoff += sizeof (*x); + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_locator (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + nn_locators_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_locators_t)); + for (const struct nn_locators_one *l = x->first; l != NULL; l = l->next) + { + char * const p = nn_xmsg_addpar (xmsg, pid, sizeof (nn_locator_t)); + memcpy (p, &l->loc, sizeof (nn_locator_t)); + } + return 0; +} + +static dds_return_t unalias_locator (void * __restrict dst, size_t * __restrict dstoff) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + nn_locators_t newlocs = { .n = x->n, .first = NULL, .last = NULL }; + struct nn_locators_one **pnext = &newlocs.first; + for (const struct nn_locators_one *lold = x->first; lold != NULL; lold = lold->next) + { + struct nn_locators_one *n = ddsrt_memdup (lold, sizeof (*n)); + *pnext = n; + pnext = &n->next; + } + newlocs.last = *pnext; + *pnext = NULL; + *x = newlocs; + *dstoff += sizeof (*x); + return 0; +} + +static dds_return_t fini_locator (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + if (!(*flagset->aliased &flag)) + { + while (x->first) + { + struct nn_locators_one *l = x->first; + x->first = l->next; + ddsrt_free (l); + } + } + return 0; +} + +static void fini_generic_partial (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased) +{ +#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \ + type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { \ + if (!aliased) do { cleanup_unaliased_; } while (0); \ + do { cleanup_always_; } while (0); \ + } \ + *dstoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_) COMPLEX (basecase_, type_, (void) 0, (void) 0) + while (desc != desc_end) + { + switch (*desc) + { + case XSTOP: return; + case XO: COMPLEX (XO, ddsi_octetseq_t, ddsrt_free (x->value), (void) 0); break; + case XS: COMPLEX (XS, char *, ddsrt_free (*x), (void) 0); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { for (uint32_t i = 0; i < x->n; i++) ddsrt_free (x->strs[i]); }, ddsrt_free (x->strs)); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0, (void) 0); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; + case XbCOND: SIMPLE (XbCOND, unsigned char); break; + case XG: SIMPLE (XG, nn_guid_t); break; + case XK: SIMPLE (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) +{ + enum pserop const * const desc_in = desc; + size_t dstoff_in = *dstoff; + /* very large buffers run a risk with alignment calculations; such buffers basically + do not occur for discovery data, so checking makes sense */ + if (dd->bufsz >= SIZE_MAX - 8) + return DDS_RETCODE_BAD_PARAMETER; + while (true) + { + assert (*srcoff <= dd->bufsz); + switch (*desc) + { + case XSTOP: + *flagset->present |= flag; + return 0; + case XO: { /* octet sequence */ + ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t)); + if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length) + goto fail; + x->value = x->length ? (unsigned char *) (dd->buf + *srcoff) : NULL; + *srcoff += x->length; + *dstoff += sizeof (*x); + *flagset->aliased |= flag; + break; + } + case XS: { /* string: alias as-if octet sequence, do additional checks and store as string */ + char ** const x = deser_generic_dst (dst, dstoff, alignof (char *)); + ddsi_octetseq_t tmp; + size_t tmpoff = 0; + if (deser_generic (&tmp, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XO, XSTOP }) < 0) + goto fail; + if (tmp.length < 1 || tmp.value[tmp.length - 1] != 0) + goto fail; + *x = (char *) tmp.value; + *dstoff += sizeof (*x); + break; + } + case XZ: { /* string sequence: repeatedly read a string */ + ddsi_stringseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_stringseq_t)); + /* sequence of string: length length ..., where each length is aligned + to a multiple of 4 bytes and the lengths are all at least 1, therefore all but the + last entry need 8 bytes and the final one at least 5; checking this protects us + against allocating large amount of memory */ + if (deser_uint32 (&x->n, dd, srcoff) < 0 || x->n > (dd->bufsz - *srcoff + 7) / 8) + goto fail; + x->strs = x->n ? ddsrt_malloc (x->n * sizeof (*x->strs)) : NULL; + size_t tmpoff = 0; + for (uint32_t i = 0; i < x->n; i++) + if (deser_generic (x->strs, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XS, XSTOP }) < 0) + goto fail; + *dstoff += sizeof (*x); + break; + } + case XE1: case XE2: case XE3: { /* enum with max allowed value */ + unsigned * const x = deser_generic_dst (dst, dstoff, alignof (int)); + const uint32_t maxval = 1 + (uint32_t) (*desc - XE1); + uint32_t tmp; + if (deser_uint32 (&tmp, dd, srcoff) < 0 || tmp > maxval) + goto fail; + *x = (unsigned) tmp; + *dstoff += sizeof (*x); + break; + } + case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xi); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 (&x[i], dd, srcoff) < 0) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: { /* uint32_t(s): treated the same */ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 (&x[i], dd, srcoff) < 0) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case Xl: { /* length(s): int32_t, -1 or >= 1 */ + int32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xl); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 ((uint32_t *) &x[i], dd, srcoff) < 0 || (x[i] < 1 && x[i] != DDS_LENGTH_UNLIMITED)) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ + dds_duration_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_duration_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - XD); + for (uint32_t i = 0; i < cnt; i++) + { + ddsi_duration_t tmp; + if (deser_uint32 ((uint32_t *) &tmp.seconds, dd, srcoff) < 0 || deser_uint32 (&tmp.fraction, dd, srcoff) < 0) + goto fail; + if (validate_external_duration (&tmp)) + goto fail; + x[i] = nn_from_ddsi_duration (tmp); + } + *dstoff += cnt * sizeof (*x); + break; + } + case Xo: case Xox2: { /* octet(s) */ + unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xo); + if (dd->bufsz - *srcoff < cnt) + goto fail; + memcpy (x, dd->buf + *srcoff, cnt); + *srcoff += cnt; + *dstoff += cnt * sizeof (*x); + break; + } + case Xb: case Xbx2: case XbCOND: { /* boolean(s) */ + unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char)); + const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */ + if (dd->bufsz - *srcoff < cnt) + goto fail; + memcpy (x, dd->buf + *srcoff, cnt); + for (uint32_t i = 0; i < cnt; i++) + if (x[i] > 1) + goto fail; + *srcoff += cnt; + *dstoff += cnt * sizeof (*x); + break; + } + case XG: { /* GUID */ + nn_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_guid_t)); + if (dd->bufsz - *srcoff < sizeof (*x)) + goto fail; + memcpy (x, dd->buf + *srcoff, sizeof (*x)); + *x = nn_ntoh_guid (*x); + *srcoff += sizeof (*x); + *dstoff += sizeof (*x); + break; + } + case XK: { /* keyhash */ + nn_keyhash_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_keyhash_t)); + if (dd->bufsz - *srcoff < sizeof (*x)) + goto fail; + memcpy (x, dd->buf + *srcoff, sizeof (*x)); + *srcoff += sizeof (*x); + *dstoff += sizeof (*x); + break; + } + } + desc++; + } + +fail: + fini_generic_partial (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag); + *flagset->present &= ~flag; + *flagset->aliased &= ~flag; + return DDS_RETCODE_BAD_PARAMETER; +} + +static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ + size_t dstoff = 0; +#define COMPLEX(basecase_, type_, dstoff_update_) do { \ + type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { dstoff_update_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, dstoff = dstoff + sizeof (*x)) +#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, dstoff = align4size (dstoff) + sizeof (*x)) + while (true) + { + switch (*desc) + { + case XSTOP: return dstoff; + case XO: COMPLEX (XO, ddsi_octetseq_t, dstoff = align4size (dstoff) + 4 + x->length); break; + case XS: COMPLEX (XS, const char *, dstoff = align4size (dstoff) + 4 + strlen (*x) + 1); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { + dstoff = align4size (dstoff) + 4; + for (uint32_t i = 0; i < x->n; i++) + dstoff = align4size (dstoff) + 4 + strlen (x->strs[i]) + 1; + }); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, dstoff = align4size (dstoff) + 4); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE4 (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE4 (Xu, uint32_t); break; + case Xl: SIMPLE4 (Xl, int32_t); break; + case XD: case XDx2: SIMPLE4 (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE1 (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE1 (Xb, unsigned char); break; + case XbCOND: SIMPLE1 (XbCOND, unsigned char); break; + case XG: SIMPLE1 (XG, nn_guid_t); break; + case XK: SIMPLE1 (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ + char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc)); + size_t dstoff = 0; + while (true) + { + switch (*desc) + { + case XSTOP: + return 0; + case XO: { /* octet sequence */ + ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = x->length; + if (x->length) memcpy (p + 4, x->value, x->length); + dstoff += 4 + x->length; + srcoff += sizeof (*x); + break; + } + case XS: { /* string */ + char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *)); + const uint32_t size = (uint32_t) (strlen (*x) + 1); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = size; + memcpy (p + 4, *x, size); + dstoff += 4 + size; + srcoff += sizeof (*x); + break; + } + case XZ: { /* string sequence */ + ddsi_stringseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_stringseq_t)); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = x->n; + dstoff += 4; + for (uint32_t i = 0; i < x->n; i++) + { + char * const q = ser_generic_align4 (data, &dstoff); + const uint32_t size = (uint32_t) (strlen (x->strs[i]) + 1); + *((uint32_t *) q) = size; + memcpy (q + 4, x->strs[i], size); + dstoff += 4 + size; + } + srcoff += sizeof (*x); + break; + } + case XE1: case XE2: case XE3: { /* enum */ + unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned)); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + *p = (uint32_t) *x; + dstoff += 4; + srcoff += sizeof (*x); + break; + } + case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */ + int32_t const * const x = deser_generic_src (src, &srcoff, alignof (int32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xi); + int32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: { /* uint32_t(s) */ + uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + + case Xl: { /* int32_t(s) */ + int32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + int32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ + dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - XD); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + { + ddsi_duration_t tmp = nn_to_ddsi_duration (x[i]); + p[2 * i + 0] = (uint32_t) tmp.seconds; + p[2 * i + 1] = tmp.fraction; + } + dstoff += 2 * cnt * sizeof (uint32_t); + srcoff += cnt * sizeof (*x); + break; + } + case Xo: case Xox2: { /* octet(s) */ + unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xo); + char * const p = data + dstoff; + memcpy (p, x, cnt); + dstoff += cnt; + srcoff += cnt * sizeof (*x); + break; + } + case Xb: case Xbx2: case XbCOND: { /* boolean(s) */ + unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char)); + const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */ + char * const p = data + dstoff; + memcpy (p, x, cnt); + dstoff += cnt; + srcoff += cnt * sizeof (*x); + break; + } + case XG: { /* GUID */ + nn_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_guid_t)); + const nn_guid_t xn = nn_hton_guid (*x); + char * const p = data + dstoff; + memcpy (p, &xn, sizeof (xn)); + dstoff += sizeof (xn); + srcoff += sizeof (*x); + break; + } + case XK: { /* keyhash */ + nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t)); + char * const p = data + dstoff; + memcpy (p, x, sizeof (*x)); + dstoff += sizeof (*x); + srcoff += sizeof (*x); + break; + } + } + desc++; + } +} + +static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, ...) do { \ + type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - basecase_); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { __VA_ARGS__; } \ + *dstoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_) COMPLEX (basecase_, type_, (void) 0) + while (true) + { + switch (*desc) + { + case XSTOP: + return 0; + case XO: COMPLEX (XO, ddsi_octetseq_t, if (x->value) { x->value = ddsrt_memdup (x->value, x->length); }); break; + case XS: COMPLEX (XS, char *, if (*x) { *x = ddsrt_strdup (*x); }); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, if (x->n) { + x->strs = ddsrt_memdup (x->strs, x->n * sizeof (*x->strs)); + for (uint32_t i = 0; i < x->n; i++) + x->strs[i] = ddsrt_strdup (x->strs[i]); + }); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; + case XbCOND: SIMPLE (XbCOND, unsigned char); break; + case XG: SIMPLE (XG, nn_guid_t); break; + case XK: SIMPLE (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static bool unalias_generic_required (const enum pserop * __restrict desc) +{ + while (*desc != XSTOP) + { + switch (*desc++) + { + case XO: case XS: case XZ: + return true; + default: + break; + } + } + return false; +} + +static bool fini_generic_required (const enum pserop * __restrict desc) +{ + /* the two happen to be the same */ + return unalias_generic_required (desc); +} + +static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const enum pserop * __restrict desc) +{ + fini_generic_partial (dst, dstoff, desc, NULL, *flagset->aliased & flag); + return 0; +} + +static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, cond_stmts_) do { \ + type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { cond_stmts_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_, cond_) COMPLEX (basecase_, type_, if (!(cond_)) return DDS_RETCODE_BAD_PARAMETER) +#define TRIVIAL(basecase_, type_) COMPLEX (basecase_, type_, (void) 0) + while (true) + { + switch (*desc) + { + case XSTOP: return 0; + case XO: SIMPLE (XO, ddsi_octetseq_t, (x->length == 0) == (x->value == NULL)); break; + case XS: SIMPLE (XS, const char *, *x != NULL); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { + if ((x->n == 0) != (x->strs == NULL)) + return DDS_RETCODE_BAD_PARAMETER; + for (uint32_t i = 0; i < x->n; i++) + if (x->strs[i] == NULL) + return DDS_RETCODE_BAD_PARAMETER; + }); break; + case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned, *x <= 1 + (unsigned) *desc - XE1); break; + case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t, *x == DDS_LENGTH_UNLIMITED || *x > 1); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t, *x >= 0); break; + case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char, *x == 0 || *x == 1); break; + case XbCOND: SIMPLE (XbCOND, unsigned char, *x == 0 || *x == 1); break; + case XG: TRIVIAL (XG, nn_guid_t); break; + case XK: TRIVIAL (XK, nn_keyhash_t); break; + } + desc++; + } +#undef TRIVIAL +#undef SIMPLE +#undef COMPLEX +} + +static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, cond_stmts_) do { \ + type_ const *x = deser_generic_src (srcx, &srcoff, alignof (type_)); \ + type_ const *y = deser_generic_src (srcy, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++, y++) { cond_stmts_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_, cond_) COMPLEX (basecase_, type_, if (!(cond_)) return false) +#define TRIVIAL(basecase_, type_) SIMPLE (basecase_, type_, *x == *y) + while (true) + { + switch (*desc) + { + case XSTOP: + return true; + case XO: + SIMPLE (XO, ddsi_octetseq_t, + (x->length == y->length) && + (x->length == 0 || memcmp (x->value, y->value, x->length) == 0)); + break; + case XS: + SIMPLE (XS, const char *, strcmp (*x, *y) == 0); + break; + case XZ: + COMPLEX (XZ, ddsi_stringseq_t, { + if (x->n != y->n) + return false; + for (uint32_t i = 0; i < x->n; i++) + if (strcmp (x->strs[i], y->strs[i]) != 0) + return false; + }); + break; + case XE1: case XE2: case XE3: TRIVIAL (*desc, unsigned); break; + case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: TRIVIAL (Xl, int32_t); break; + case XD: case XDx2: TRIVIAL (XD, dds_duration_t); break; + case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; + case Xb: case Xbx2: TRIVIAL (Xb, unsigned char); break; + case XbCOND: + COMPLEX (XbCOND, unsigned char, { + if (*x != *y) + return false; + if (*x == false) + return true; + }); + break; + case XG: SIMPLE (XG, nn_guid_t, memcmp (x, y, sizeof (*x))); break; + case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x))); break; + } + desc++; + } +#undef TRIVIAL +#undef SIMPLE +#undef COMPLEX +} + +#define membersize(type, member) sizeof (((type *) 0)->member) +#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \ + { PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_), \ + membersize (struct nn_plist, member_), { .desc = { __VA_ARGS__, XSTOP } }, validate_ \ + } +#define QPV(NAME_, name_, ...) ENTRY(QP, NAME_, qos.name_, PDF_QOS, dvx_##name_, __VA_ARGS__) +#define PPV(NAME_, name_, ...) ENTRY(PP, NAME_, name_, 0, dvx_##name_, __VA_ARGS__) +#define QP(NAME_, name_, ...) ENTRY(QP, NAME_, qos.name_, PDF_QOS, 0, __VA_ARGS__) +#define PP(NAME_, name_, ...) ENTRY(PP, NAME_, name_, 0, 0, __VA_ARGS__) +#define PPM(NAME_, name_, ...) ENTRY(PP, NAME_, name_, PDF_ALLOWMULTI, 0, __VA_ARGS__) + static int protocol_version_is_newer (nn_protocol_version_t pv) { return (pv.major < RTPS_MAJOR) ? 0 : (pv.major > RTPS_MAJOR) ? 1 : (pv.minor > RTPS_MINOR); } -static int validate_string (const struct dd *dd, size_t *len) +static dds_return_t dvx_durability_service (void * __restrict dst, const struct dd * __restrict dd) { - const struct cdrstring *x = (const struct cdrstring *) dd->buf; - if (dd->bufsz < sizeof (struct cdrstring)) - { - DDS_TRACE("plist/validate_string: buffer too small (header)\n"); - return Q_ERR_INVALID; - } - *len = dd->bswap ? bswap4u (x->length) : x->length; - if (*len < 1 || *len > dd->bufsz - offsetof (struct cdrstring, contents)) - { - DDS_TRACE("plist/validate_string: length %" PRIuSIZE " out of range\n", *len); - return Q_ERR_INVALID; - } - if (x->contents[*len-1] != 0) - { - DDS_TRACE("plist/validate_string: terminator missing\n"); - return Q_ERR_INVALID; - } - return 0; + /* Accept all zero durability because of CoreDX, final_validation is more strict */ + (void) dd; + return validate_durability_service_qospolicy_acceptzero (dst, true); } -static int alias_string (const unsigned char **ptr, const struct dd *dd, size_t *len) +static dds_return_t dvx_history (void * __restrict dst, const struct dd * __restrict dd) { - int rc; - if ((rc = validate_string (dd, len)) < 0) - return rc; + (void) dd; + return validate_history_qospolicy (dst); +} + +static dds_return_t dvx_resource_limits (void * __restrict dst, const struct dd * __restrict dd) +{ + (void) dd; + return validate_resource_limits_qospolicy (dst); +} + +static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd * __restrict dd) +{ + const nn_guid_t *g = dst; + (void) dd; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; else - { - const struct cdrstring *x = (const struct cdrstring *) dd->buf; - *ptr = x->contents; - return 0; - } + return (g->entityid.u == NN_ENTITYID_PARTICIPANT) ? 0 : DDS_RETCODE_BAD_PARAMETER; } -static void unalias_string (char **str, int bswap) +static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __restrict dd) { - const char *alias = *str; - unsigned len; - if (bswap == 0 || bswap == 1) - { - const unsigned *plen = (const unsigned *) alias - 1; - len = bswap ? bswap4u (*plen) : *plen; - } + const nn_guid_t *g = dst; + (void) dd; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; else - { - len = (unsigned) strlen (alias) + 1; - } - *str = ddsrt_malloc (len); - memcpy (*str, alias, len); + return (g->entityid.u != 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; } -static int validate_octetseq (const struct dd *dd, size_t *len) +static dds_return_t dvx_endpoint_guid (void * __restrict dst, const struct dd * __restrict dd) { - const struct cdroctetseq *x = (const struct cdroctetseq *) dd->buf; - if (dd->bufsz < offsetof (struct cdroctetseq, value)) - return Q_ERR_INVALID; - *len = dd->bswap ? bswap4u (x->len) : x->len; - if (*len > dd->bufsz - offsetof (struct cdroctetseq, value) || *len >= UINT32_MAX) - return Q_ERR_INVALID; + nn_guid_t *g = dst; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; + switch (g->entityid.u & NN_ENTITYID_KIND_MASK) + { + case NN_ENTITYID_KIND_WRITER_WITH_KEY: + case NN_ENTITYID_KIND_WRITER_NO_KEY: + case NN_ENTITYID_KIND_READER_NO_KEY: + case NN_ENTITYID_KIND_READER_WITH_KEY: + return 0; + default: + return (protocol_version_is_newer (dd->protocol_version) ? 0 : DDS_RETCODE_BAD_PARAMETER); + } +} + +#ifdef DDSI_INCLUDE_SSM +static dds_return_t dvx_reader_favours_ssm (void * __restrict dst, const struct dd * __restrict dd) +{ + uint32_t * const favours_ssm = dst; + (void) dd; + /* any unrecognized state: avoid SSM */ + if (*favours_ssm != 0 && *favours_ssm != 1) + *favours_ssm = 0; return 0; } - -static int alias_octetseq (nn_octetseq_t *oseq, const struct dd *dd) -{ - size_t len; - int rc; - if ((rc = validate_octetseq (dd, &len)) < 0) - return rc; - else - { - const struct cdroctetseq *x = (const struct cdroctetseq *) dd->buf; - assert(len < UINT32_MAX); /* it really is an uint32_t on the wire */ - oseq->length = (uint32_t)len; - oseq->value = (len == 0) ? NULL : (unsigned char *) x->value; - return 0; - } -} - -static int alias_blob (nn_octetseq_t *oseq, const struct dd *dd) -{ - assert (dd->bufsz < UINT32_MAX); - oseq->length = (uint32_t)dd->bufsz; - oseq->value = (oseq->length == 0) ? NULL : (unsigned char *) dd->buf; - return 0; -} - -static void unalias_octetseq (nn_octetseq_t *oseq, UNUSED_ARG (int bswap)) -{ - if (oseq->length != 0) - { - unsigned char *vs; - vs = ddsrt_malloc (oseq->length); - memcpy (vs, oseq->value, oseq->length); - oseq->value = vs; - } -} - -static int validate_stringseq (const struct dd *dd) -{ - const unsigned char *seq = dd->buf; - const unsigned char *seqend = seq + dd->bufsz; - struct dd dd1 = *dd; - int i, n; - if (dd->bufsz < sizeof (int)) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (header)\n"); - return Q_ERR_INVALID; - } - memcpy (&n, seq, sizeof (n)); - if (dd->bswap) - n = bswap4 (n); - seq += sizeof (int); - if (n < 0) - { - DDS_TRACE("plist/validate_stringseq: length %d out of range\n", n); - return Q_ERR_INVALID; - } - else if (n == 0) - { - return 0; - } - else - { - for (i = 0; i < n && seq <= seqend; i++) - { - size_t len1; - int rc; - dd1.buf = seq; - dd1.bufsz = (size_t) (seqend - seq); - if ((rc = validate_string (&dd1, &len1)) < 0) - { - DDS_TRACE("plist/validate_stringseq: invalid string\n"); - return rc; - } - seq += sizeof (uint32_t) + align4u (len1); - } - if (i < n) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (contents)\n"); - return Q_ERR_INVALID; - } - } - /* Should I worry about junk between the last string & the end of - the parameter? */ - return 0; -} - -static int alias_stringseq (nn_stringseq_t *strseq, const struct dd *dd) -{ - /* Not truly an alias: it allocates an array of pointers that alias - the individual null-terminated strings. Also: see - validate_stringseq */ - const unsigned char *seq = dd->buf; - const unsigned char *seqend = seq + dd->bufsz; - struct dd dd1 = *dd; - char **strs; - unsigned i; - int result; - if (dd->bufsz < sizeof (int)) - { - DDS_TRACE("plist/alias_stringseq: buffer too small (header)\n"); - return Q_ERR_INVALID; - } - memcpy (&strseq->n, seq, sizeof (strseq->n)); - if (dd->bswap) - strseq->n = bswap4u (strseq->n); - seq += sizeof (uint32_t); - if (strseq->n >= UINT_MAX / sizeof(*strs)) - { - DDS_TRACE("plist/alias_stringseq: length %"PRIu32" out of range\n", strseq->n); - return Q_ERR_INVALID; - } - else if (strseq->n == 0) - { - strseq->strs = NULL; - } - else - { - strs = ddsrt_malloc (strseq->n * sizeof (*strs)); - for (i = 0; i < strseq->n && seq <= seqend; i++) - { - size_t len1; - dd1.buf = seq; - dd1.bufsz = (size_t)(seqend - seq); - /* (const char **) to silence the compiler, unfortunately strseq - can't have a const char **strs, that would require a const - and a non-const version of it. */ - if ((result = alias_string ((const unsigned char **) &strs[i], &dd1, &len1)) < 0) - { - DDS_TRACE("plist/alias_stringseq: invalid string\n"); - goto fail; - } - seq += sizeof (uint32_t) + align4u (len1); - } - if (i != strseq->n) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (contents)\n"); - result = Q_ERR_INVALID; - goto fail; - } - strseq->strs = strs; - } - return 0; - fail: - ddsrt_free (strs); - return result; -} - -static void free_stringseq (nn_stringseq_t *strseq) -{ - unsigned i; - for (i = 0; i < strseq->n; i++) - { - if (strseq->strs[i]) - { - ddsrt_free (strseq->strs[i]); - } - } - ddsrt_free (strseq->strs); -} - -static int unalias_stringseq (nn_stringseq_t *strseq, int bswap) -{ - unsigned i; - char **strs; - if (strseq->n != 0) - { - strs = ddsrt_malloc (strseq->n * sizeof (*strs)); - for (i = 0; i < strseq->n; i++) - { - strs[i] = strseq->strs[i]; - unalias_string (&strs[i], bswap); - } - ddsrt_free (strseq->strs); - strseq->strs = strs; - } - return 0; -} - -static void duplicate_stringseq (nn_stringseq_t *dest, const nn_stringseq_t *src) -{ - unsigned i; - dest->n = src->n; -assert (dest->strs == NULL); - if (dest->n == 0) - { - dest->strs = NULL; - return; - } - dest->strs = ddsrt_malloc (dest->n * sizeof (*dest->strs)); - for (i = 0; i < dest->n; i++) - { - dest->strs[i] = src->strs[i]; - unalias_string (&dest->strs[i], -1); - } -} - -static void free_locators (nn_locators_t *locs) -{ - while (locs->first) - { - struct nn_locators_one *l = locs->first; - locs->first = l->next; - ddsrt_free (l); - } -} - -static void unalias_locators (nn_locators_t *locs, UNUSED_ARG (int bswap)) -{ - nn_locators_t newlocs; - struct nn_locators_one *lold; - /* Copy it, without reversing the order. On failure, free the copy, - on success overwrite *locs. */ - newlocs.n = locs->n; - newlocs.first = NULL; - newlocs.last = NULL; - for (lold = locs->first; lold != NULL; lold = lold->next) - { - struct nn_locators_one *n; - n = ddsrt_malloc (sizeof (*n)); - n->next = NULL; - n->loc = lold->loc; - if (newlocs.first == NULL) - newlocs.first = n; - else - newlocs.last->next = n; - newlocs.last = n; - } - *locs = newlocs; -} - -static void unalias_eotinfo (nn_prismtech_eotinfo_t *txnid, UNUSED_ARG (int bswap)) -{ - if (txnid->n > 0) - { - nn_prismtech_eotgroup_tid_t *vs; - vs = ddsrt_malloc (txnid->n * sizeof (*vs)); - memcpy (vs, txnid->tids, txnid->n * sizeof (*vs)); - txnid->tids = vs; - } -} - -void nn_plist_fini (nn_plist_t *ps) -{ - struct t { uint64_t fl; size_t off; }; - static const struct t simple[] = { - { PP_ENTITY_NAME, offsetof (nn_plist_t, entity_name) }, - { PP_PRISMTECH_NODE_NAME, offsetof (nn_plist_t, node_name) }, - { PP_PRISMTECH_EXEC_NAME, offsetof (nn_plist_t, exec_name) }, - { PP_PRISMTECH_PARTICIPANT_VERSION_INFO, offsetof (nn_plist_t, prismtech_participant_version_info.internals) }, - { PP_PRISMTECH_TYPE_DESCRIPTION, offsetof (nn_plist_t, type_description) }, - { PP_PRISMTECH_EOTINFO, offsetof (nn_plist_t, eotinfo.tids) } - }; - static const struct t locs[] = { - { PP_UNICAST_LOCATOR, offsetof (nn_plist_t, unicast_locators) }, - { PP_MULTICAST_LOCATOR, offsetof (nn_plist_t, multicast_locators) }, - { PP_DEFAULT_UNICAST_LOCATOR, offsetof (nn_plist_t, default_unicast_locators) }, - { PP_DEFAULT_MULTICAST_LOCATOR, offsetof (nn_plist_t, default_multicast_locators) }, - { PP_METATRAFFIC_UNICAST_LOCATOR, offsetof (nn_plist_t, metatraffic_unicast_locators) }, - { PP_METATRAFFIC_MULTICAST_LOCATOR, offsetof (nn_plist_t, metatraffic_multicast_locators) } - }; - int i; - nn_xqos_fini (&ps->qos); - -/* The compiler doesn't understand how offsetof is used in the arrays. */ -DDSRT_WARNING_MSVC_OFF(6001); - for (i = 0; i < (int) (sizeof (simple) / sizeof (*simple)); i++) - { - if ((ps->present & simple[i].fl) && !(ps->aliased & simple[i].fl)) - { - void **pp = (void **) ((char *) ps + simple[i].off); - ddsrt_free (*pp); - } - } - for (i = 0; i < (int) (sizeof (locs) / sizeof (*locs)); i++) - { - if ((ps->present & locs[i].fl) && !(ps->aliased & locs[i].fl)) - free_locators ((nn_locators_t *) ((char *) ps + locs[i].off)); - } -DDSRT_WARNING_MSVC_ON(6001); - - ps->present = 0; -} - -#if 0 /* not currently needed */ -void nn_plist_unalias (nn_plist_t *ps) -{ -#define P(name_, func_, field_) do { \ - if ((ps->present & PP_##name_) && (ps->aliased & PP_##name_)) { \ - unalias_##func_ (&ps->field_, -1); \ - ps->aliased &= ~PP_##name_; \ - } \ - } while (0) - nn_xqos_unalias (&ps->qos); - P (ENTITY_NAME, string, entity_name); - P (UNICAST_LOCATOR, locators, unicast_locators); - P (MULTICAST_LOCATOR, locators, multicast_locators); - P (DEFAULT_UNICAST_LOCATOR, locators, default_unicast_locators); - P (DEFAULT_MULTICAST_LOCATOR, locators, default_multicast_locators); - P (METATRAFFIC_UNICAST_LOCATOR, locators, metatraffic_unicast_locators); - P (METATRAFFIC_MULTICAST_LOCATOR, locators, metatraffic_multicast_locators); - P (PRISMTECH_NODE_NAME, string, node_name); - P (PRISMTECH_EXEC_NAME, string, exec_name); - P (PRISMTECH_TYPE_DESCRIPTION, string, type_description); - P (PRISMTECH_EOTINFO, eotinfo, eotinfo); -#undef P - if ((ps->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) && - (ps->aliased & PP_PRISMTECH_PARTICIPANT_VERSION_INFO)) - { - unalias_string (&ps->prismtech_participant_version_info.internals, -1); - ps->aliased &= ~PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - } - - assert (ps->aliased == 0); -} #endif -static int do_octetseq (nn_octetseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) +/* Standardized parameters -- QoS _MUST_ come first (nn_plist_init_tables verifies this) because + it allows early-out when processing a dds_qos_t instead of an nn_plist_t */ +static const struct piddesc piddesc_omg[] = { + QP (USER_DATA, user_data, XO), + QP (TOPIC_NAME, topic_name, XS), + QP (TYPE_NAME, type_name, XS), + QP (TOPIC_DATA, topic_data, XO), + QP (GROUP_DATA, group_data, XO), + QP (DURABILITY, durability, XE3), + /* CoreDX's use of all-zero durability service QoS means we can't use l; interdependencies between QoS + values means we must validate the combination anyway */ + QPV (DURABILITY_SERVICE, durability_service, XD, XE1, Xix4), + QP (DEADLINE, deadline, XD), + QP (LATENCY_BUDGET, latency_budget, XD), + QP (LIVELINESS, liveliness, XE2, XD), + /* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */ + { PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY", + offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability), + { .f = { .deser = deser_reliability, .ser = ser_reliability, .valid = valid_reliability, .equal = equal_reliability } }, 0 }, + QP (LIFESPAN, lifespan, XD), + QP (DESTINATION_ORDER, destination_order, XE1), + /* History depth is ignored when kind = KEEP_ALL, and must be >= 1 when KEEP_LAST, so can't use "l" */ + QPV (HISTORY, history, XE1, Xi), + QPV (RESOURCE_LIMITS, resource_limits, Xix3), + QP (OWNERSHIP, ownership, XE1), + QP (OWNERSHIP_STRENGTH, ownership_strength, Xi), + QP (PRESENTATION, presentation, XE2, Xbx2), + QP (PARTITION, partition, XZ), + QP (TIME_BASED_FILTER, time_based_filter, XD), + QP (TRANSPORT_PRIORITY, transport_priority, Xi), + PP (PROTOCOL_VERSION, protocol_version, Xox2), + PP (VENDORID, vendorid, Xox2), + PP (EXPECTS_INLINE_QOS, expects_inline_qos, Xb), + PP (PARTICIPANT_MANUAL_LIVELINESS_COUNT, participant_manual_liveliness_count, Xi), + PP (PARTICIPANT_BUILTIN_ENDPOINTS, participant_builtin_endpoints, Xu), + PP (PARTICIPANT_LEASE_DURATION, participant_lease_duration, XD), + PPV (PARTICIPANT_GUID, participant_guid, XG), + PPV (GROUP_GUID, group_guid, XG), + PP (BUILTIN_ENDPOINT_SET, builtin_endpoint_set, Xu), + PP (ENTITY_NAME, entity_name, XS), + PP (KEYHASH, keyhash, XK), + PPV (ENDPOINT_GUID, endpoint_guid, XG), +#ifdef DDSI_INCLUDE_SSM + PPV (READER_FAVOURS_SSM, reader_favours_ssm, Xu), +#endif + { PID_STATUSINFO, PDF_FUNCTION, PP_STATUSINFO, "STATUSINFO", + offsetof (struct nn_plist, statusinfo), membersize (struct nn_plist, statusinfo), + { .f = { .deser = deser_statusinfo, .ser = ser_statusinfo } }, 0 }, + /* Locators are difficult to deal with because they can occur multi times to represent a set; + that is manageable for deser, unalias and fini, but it breaks ser because that one only + generates a single parameter header */ + { PID_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_UNICAST_LOCATOR, "UNICAST_LOCATOR", + offsetof (struct nn_plist, unicast_locators), membersize (struct nn_plist, unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_MULTICAST_LOCATOR, "MULTICAST_LOCATOR", + offsetof (struct nn_plist, multicast_locators), membersize (struct nn_plist, multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_DEFAULT_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_DEFAULT_UNICAST_LOCATOR, "DEFAULT_UNICAST_LOCATOR", + offsetof (struct nn_plist, default_unicast_locators), membersize (struct nn_plist, default_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_DEFAULT_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_DEFAULT_MULTICAST_LOCATOR, "DEFAULT_MULTICAST_LOCATOR", + offsetof (struct nn_plist, default_multicast_locators), membersize (struct nn_plist, default_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_METATRAFFIC_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_METATRAFFIC_UNICAST_LOCATOR, "METATRAFFIC_UNICAST_LOCATOR", + offsetof (struct nn_plist, metatraffic_unicast_locators), membersize (struct nn_plist, metatraffic_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_METATRAFFIC_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_METATRAFFIC_MULTICAST_LOCATOR, "METATRAFFIC_MULTICAST_LOCATOR", + offsetof (struct nn_plist, metatraffic_multicast_locators), membersize (struct nn_plist, metatraffic_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + /* PID_..._{IPADDRESS,PORT} is impossible to deal with and are never generated, only accepted. + The problem is that there one needs additional state (and even then there is no clear + interpretation) ... So they'll have to be special-cased */ + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +/* Understood parameters for Eclipse Foundation (Cyclone DDS) vendor code */ +static const struct piddesc piddesc_eclipse[] = { + QP (PRISMTECH_ENTITY_FACTORY, entity_factory, Xb), + QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD), + QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb), + QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2), + QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ), + { PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL", + offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal), + { .desc = { XE2, XSTOP } }, 0 }, + PP (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, Xu), + PP (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, Xux5, XS), + PP (PRISMTECH_EXEC_NAME, exec_name, XS), + PP (PRISMTECH_PROCESS_ID, process_id, Xu), + PP (PRISMTECH_NODE_NAME, node_name, XS), + PP (PRISMTECH_TYPE_DESCRIPTION, type_description, XS), + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +/* Understood parameters for PrismTech vendor code */ +static const struct piddesc piddesc_prismtech[] = { + QP (PRISMTECH_ENTITY_FACTORY, entity_factory, Xb), + QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD), + QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb), + QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2), + QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ), + PP (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, Xu), + PP (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, Xux5, XS), + PP (PRISMTECH_EXEC_NAME, exec_name, XS), + PP (PRISMTECH_PROCESS_ID, process_id, Xu), + PP (PRISMTECH_NODE_NAME, node_name, XS), + PP (PRISMTECH_TYPE_DESCRIPTION, type_description, XS), + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +#undef PPM +#undef PP +#undef QP +#undef PPV +#undef QPV +#undef ENTRY +#undef membersize + +/* Parameters to be included in messages we generate */ +static const struct piddesc *piddesc_tables_output[] = { + piddesc_omg, + piddesc_eclipse +}; + +/* All known parameters -- this can potentially include + parameters from other vendors that we never generate + but that we do recognize on input and store for some + purpose other than the internal workings of Cyclone, + and that require fini/unalias processing */ +static const struct piddesc *piddesc_tables_all[] = { + piddesc_omg, + piddesc_eclipse +}; + +struct piddesc_index { + size_t index_max; + const struct piddesc **index; + /* include source table for generating the index -- + it's easier to generate the index at startup then + to maintain in the source */ + const struct piddesc *table; +}; + +/* Vendor code to vendor-specific table mapping, with index + vendor codes are currently of the form 1.x with x a small + number > 0 (and that's not likely to change) so we have + a table for major = 1 and use index 0 for the standard + ones. + + Sizes are such that the highest PID (without flags) in + table are the last entry in the array. Checked by + nn_plist_init_tables. + + FIXME: should compute them at build-time */ +#ifdef DDSI_INCLUDE_SSM +static const struct piddesc *piddesc_omg_index[115]; +#else /* status info is the highest */ +static const struct piddesc *piddesc_omg_index[114]; +#endif +static const struct piddesc *piddesc_eclipse_index[19]; +static const struct piddesc *piddesc_prismtech_index[19]; + +#define INDEX_ANY(vendorid_, tab_) [vendorid_] = { \ + .index_max = sizeof (piddesc_##tab_##_index) / sizeof (piddesc_##tab_##_index[0]) - 1, \ + .index = (const struct piddesc **) piddesc_##tab_##_index, \ + .table = piddesc_##tab_ } +#define INDEX(VENDOR_, tab_) INDEX_ANY (NN_VENDORID_MINOR_##VENDOR_, tab_) + +static const struct piddesc_index piddesc_vendor_index[] = { + INDEX_ANY (0, omg), + INDEX (ECLIPSE, eclipse), + INDEX (PRISMTECH_OSPL, prismtech), + INDEX (PRISMTECH_JAVA, prismtech), + INDEX (PRISMTECH_LITE, prismtech), + INDEX (PRISMTECH_GATEWAY, prismtech), + INDEX (PRISMTECH_CLOUD, prismtech) +}; + +#undef INDEX +#undef INDEX_ANY + +/* List of entries that require unalias, fini processing; + initialized by nn_plist_init_tables; will assert when + table too small or too large */ +static const struct piddesc *piddesc_unalias[18]; +static const struct piddesc *piddesc_fini[18]; +static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT; + +static nn_parameterid_t pid_without_flags (nn_parameterid_t pid) { - int res; - size_t len; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_octetseq (dd, &len) : 0; - if ((res = alias_octetseq (dst, dd)) >= 0) + return (nn_parameterid_t) (pid & ~(PID_VENDORSPECIFIC_FLAG | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)); +} + +static int piddesc_cmp_qos_addr (const void *va, const void *vb) +{ + struct piddesc const * const *a = (struct piddesc const * const *) va; + struct piddesc const * const *b = (struct piddesc const * const *) vb; + /* QoS go first, then address */ + if (((*a)->flags & PDF_QOS) != ((*b)->flags & PDF_QOS)) + return ((*a)->flags & PDF_QOS) ? -1 : 1; + else + return ((uintptr_t) *a == (uintptr_t) *b) ? 0 : ((uintptr_t) *a < (uintptr_t) *b) ? -1 : 1; +} + +static void nn_plist_init_tables_real (void) +{ + /* make index of pid -> entry */ + for (size_t i = 0; i < sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0]); i++) { - *present |= fl; - *aliased |= fl; + const struct piddesc *table = piddesc_vendor_index[i].table; + if (table == NULL) + continue; + struct piddesc const **index = piddesc_vendor_index[i].index; +#ifndef NDEBUG + nn_parameterid_t maxpid = 0; + bool only_qos_seen = true; +#endif + for (size_t j = 0; table[j].pid != PID_SENTINEL; j++) + { + nn_parameterid_t pid = pid_without_flags (table[j].pid); +#ifndef NDEBUG + /* Table must first list QoS, then other parameters */ + assert (only_qos_seen || !(table[j].flags & PDF_QOS)); + if (!(table[j].flags & PDF_QOS)) + only_qos_seen = false; + /* Track max PID so we can verify the table is no larger + than necessary */ + if (pid > maxpid) + maxpid = pid; +#endif + /* PAD is used for entries that are never visible on the wire + and the decoder assumes the PAD entries will be skipped + because they don't map to an entry */ + if (pid == PID_PAD) + continue; + assert (pid <= piddesc_vendor_index[i].index_max); + assert (index[pid] == NULL || index[pid] == &table[j]); + index[pid] = &table[j]; + } + assert (maxpid == piddesc_vendor_index[i].index_max); } - return res; -} -static int do_blob (nn_octetseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) -{ - int res; - if (!(wanted & fl)) - return 0; - if ((res = alias_blob (dst, dd)) >= 0) + /* PIDs requiring unalias; there is overlap between the tables + (because of different vendor codes mapping to the same entry + in qos/plist). Use the "present" flags to filter out + duplicates. */ + uint64_t pf = 0, qf = 0; + size_t unalias_index = 0; + size_t fini_index = 0; + for (size_t i = 0; i < sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0]); i++) { - *present |= fl; - *aliased |= fl; + const struct piddesc *table = piddesc_vendor_index[i].table; + if (table == NULL) + continue; + for (size_t j = 0; table[j].pid != PID_SENTINEL; j++) + { + uint64_t * const f = (table[j].flags & PDF_QOS) ? &qf : &pf; + if (*f & table[j].present_flag) + continue; + *f |= table[j].present_flag; + if (((table[j].flags & PDF_FUNCTION) && table[j].op.f.unalias) || + (!(table[j].flags & PDF_FUNCTION) && unalias_generic_required (table[j].op.desc))) + { + assert (unalias_index < sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0])); + piddesc_unalias[unalias_index++] = &table[j]; + } + if (((table[j].flags & PDF_FUNCTION) && table[j].op.f.fini) || + (!(table[j].flags & PDF_FUNCTION) && fini_generic_required (table[j].op.desc))) + { + assert (fini_index < sizeof (piddesc_fini) / sizeof (piddesc_fini[0])); + piddesc_fini[fini_index++] = &table[j]; + } + } } - return res; -} - -static int do_string (char **dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) -{ - int res; - size_t len; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_string (dd, &len) : 0; - if ((res = alias_string ((const unsigned char **) dst, dd, &len)) >= 0) + assert (unalias_index == sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0]) && + fini_index == sizeof (piddesc_fini) / sizeof (piddesc_fini[0])); + qsort ((void *) piddesc_unalias, unalias_index, sizeof (piddesc_unalias[0]), piddesc_cmp_qos_addr); + qsort ((void *) piddesc_fini, fini_index, sizeof (piddesc_fini[0]), piddesc_cmp_qos_addr); +#ifndef NDEBUG { - *present |= fl; - *aliased |= fl; + size_t i; + for (i = 0; i < unalias_index; i++) + if (!(piddesc_unalias[i]->flags & PDF_QOS)) + break; + for (; i < unalias_index; i++) + assert (!(piddesc_unalias[i]->flags & PDF_QOS)); + for (i = 0; i < fini_index; i++) + if (!(piddesc_fini[i]->flags & PDF_QOS)) + break; + for (; i < fini_index; i++) + assert (!(piddesc_fini[i]->flags & PDF_QOS)); } - return res; +#endif } -static int do_stringseq (nn_stringseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) +void nn_plist_init_tables (void) { - int res; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_stringseq (dd) : 0; - if ((res = alias_stringseq (dst, dd)) >= 0) + ddsrt_once (&table_init_control, nn_plist_init_tables_real); +} + +static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pmask, uint64_t qmask) +{ + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs, qfs; + /* DDS manipulation can be done without creating a participant, so we may + have to initialize tables just-in-time */ + if (piddesc_fini[0] == NULL) + nn_plist_init_tables (); + if (shift > 0) { - *present |= fl; - *aliased |= fl; + dds_qos_t *qos = dst; + pfs = (struct flagset) { 0 }; + qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased }; } - return res; -} - -static void bswap_time (nn_ddsi_time_t *t) -{ - t->seconds = bswap4 (t->seconds); - t->fraction = bswap4u (t->fraction); -} - -static int validate_time (const nn_ddsi_time_t *t) -{ - /* Accepter are zero, positive, infinite or invalid as defined in - the DDS 2.1 spec, table 9.4. */ - if (t->seconds >= 0) - return 0; - else if (t->seconds == -1 && t->fraction == UINT32_MAX) - return 0; else { - DDS_TRACE("plist/validate_time: invalid timestamp (%08x.%08x)\n", t->seconds, t->fraction); - return Q_ERR_INVALID; + nn_plist_t *plist = dst; + pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; + qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; } -} - -static void bswap_duration (nn_duration_t *d) -{ - bswap_time (d); -} - -int validate_duration (const nn_duration_t *d) -{ - return validate_time (d); -} - -static int do_duration (nn_duration_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - int res; - if (dd->bufsz < sizeof (*q)) + for (size_t i = 0; i < sizeof (piddesc_fini) / sizeof (piddesc_fini[0]); i++) { - DDS_TRACE("plist/do_duration: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - bswap_duration (q); - if ((res = validate_duration (q)) < 0) - return res; - *present |= fl; - return 0; -} - -static void bswap_durability_qospolicy (nn_durability_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -int validate_durability_qospolicy (const nn_durability_qospolicy_t *q) -{ - switch (q->kind) - { - case NN_VOLATILE_DURABILITY_QOS: - case NN_TRANSIENT_LOCAL_DURABILITY_QOS: - case NN_TRANSIENT_DURABILITY_QOS: - case NN_PERSISTENT_DURABILITY_QOS: + struct piddesc const * const entry = piddesc_fini[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) break; - default: - DDS_TRACE("plist/validate_durability_qospolicy: invalid kind (%d)\n", (int) q->kind); - return Q_ERR_INVALID; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs = (entry->flags & PDF_QOS) ? &qfs : &pfs; + uint64_t mask = (entry->flags & PDF_QOS) ? qmask : pmask; + if (*fs->present & entry->present_flag & mask) + { + if (!(entry->flags & PDF_FUNCTION)) + fini_generic (dst, &dstoff, fs, entry->present_flag, entry->op.desc); + else if (entry->op.f.fini) + entry->op.f.fini (dst, &dstoff, fs, entry->present_flag); + } } - return 0; + if (pfs.present) { *pfs.present &= ~pmask; *pfs.aliased &= ~pmask; } + *qfs.present &= ~qmask; *qfs.aliased &= ~qmask; } -static void bswap_history_qospolicy (nn_history_qospolicy_t *q) +static void plist_or_xqos_unalias (void * __restrict dst, size_t shift) { - q->kind = bswap4u (q->kind); - q->depth = bswap4 (q->depth); + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs, qfs; + /* DDS manipulation can be done without creating a participant, so we may + have to initialize tables just-in-time */ + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + if (shift > 0) + { + dds_qos_t *qos = dst; + pfs = (struct flagset) { 0 }; + qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased }; + } + else + { + nn_plist_t *plist = dst; + pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; + qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; + } + for (size_t i = 0; i < sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0]); i++) + { + struct piddesc const * const entry = piddesc_unalias[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) + break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs = (entry->flags & PDF_QOS) ? &qfs : &pfs; + if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag)) + { + if (!(entry->flags & PDF_FUNCTION)) + unalias_generic (dst, &dstoff, entry->op.desc); + else if (entry->op.f.unalias) + entry->op.f.unalias (dst, &dstoff); + *fs->aliased &= ~entry->present_flag; + } + } + assert (pfs.aliased == NULL || *pfs.aliased == 0); + assert (*qfs.aliased == 0); } -static int history_qospolicy_allzero (const nn_history_qospolicy_t *q) +static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * __restrict src, size_t shift, uint64_t pmask, uint64_t qmask) { - return q->kind == NN_KEEP_LAST_HISTORY_QOS && q->depth == 0; + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs_src, qfs_src; + struct flagset pfs_dst, qfs_dst; +#ifndef NDEBUG + const uint64_t aliased_dst_inp = (shift == 0) ? ((nn_plist_t *) dst)->aliased : 0; + const uint64_t aliased_dst_inq = (shift == 0) ? ((nn_plist_t *) dst)->qos.aliased : ((dds_qos_t *) dst)->aliased; +#endif + if (shift > 0) + { + dds_qos_t *qos_dst = dst; + const dds_qos_t *qos_src = src; + pfs_dst = (struct flagset) { 0 }; + qfs_dst = (struct flagset) { .present = &qos_dst->present, .aliased = &qos_dst->aliased }; + pfs_src = (struct flagset) { 0 }; + qfs_src = (struct flagset) { .present = (uint64_t *) &qos_src->present, .aliased = (uint64_t *) &qos_src->aliased }; + } + else + { + nn_plist_t *plist_dst = dst; + const nn_plist_t *plist_src = src; + pfs_dst = (struct flagset) { .present = &plist_dst->present, .aliased = &plist_dst->aliased }; + qfs_dst = (struct flagset) { .present = &plist_dst->qos.present, .aliased = &plist_dst->qos.aliased }; + pfs_src = (struct flagset) { .present = (uint64_t *) &plist_src->present, .aliased = (uint64_t *) &plist_src->aliased }; + qfs_src = (struct flagset) { .present = (uint64_t *) &plist_src->qos.present, .aliased = (uint64_t *) &plist_src->qos.aliased }; + } + /* aliased may never have any bits set that are clear in present */ + assert (pfs_dst.present == NULL || (aliased_dst_inp & ~ *pfs_dst.present) == 0); + assert ((aliased_dst_inq & ~ *qfs_dst.present) == 0); + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) + break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs_dst = (entry->flags & PDF_QOS) ? &qfs_dst : &pfs_dst; + struct flagset * const fs_src = (entry->flags & PDF_QOS) ? &qfs_src : &pfs_src; + uint64_t const mask = (entry->flags & PDF_QOS) ? qmask : pmask; + /* skip if already present in dst or absent in src */ + if (!(*fs_dst->present & entry->present_flag) && (*fs_src->present & mask & entry->present_flag)) + { + /* bitwise copy, mark as aliased & unalias; have to unalias fields one-by-one rather than + do this for all fields and call "unalias" on the entire object because fields that are + already present may be aliased, and it would be somewhat impolite to change that. + + Note: dst & src have the same type, so offset in src is the same; + Note: unalias may have to look at */ + memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size); + *fs_dst->present |= entry->present_flag; + if (!(entry->flags & PDF_FUNCTION)) + unalias_generic (dst, &dstoff, entry->op.desc); + else if (entry->op.f.unalias) + entry->op.f.unalias (dst, &dstoff); + } + } + } + /* all entries in src should be present in dst (but there may be more) */ + assert (pfs_dst.present == NULL || (*pfs_src.present & pmask & ~ *pfs_dst.present) == 0); + assert ((*qfs_src.present & qmask & ~ *qfs_dst.present) == 0); + /* the only aliased entries in dst may be ones that were aliased on input */ + assert (pfs_dst.aliased == NULL || (*pfs_dst.aliased & ~ aliased_dst_inp) == 0); + assert ((*qfs_dst.aliased & ~ aliased_dst_inq) == 0); } -int validate_history_qospolicy (const nn_history_qospolicy_t *q) +static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted) +{ + /* shift == 0: plist, shift > 0: just qos */ + uint64_t pw, qw; + if (shift > 0) + { + const dds_qos_t *qos = src; + pw = 0; + qw = qos->present & qwanted; + } + else + { + const nn_plist_t *plist = src; + pw = plist->present & pwanted; + qw = plist->qos.present & qwanted; + } + for (size_t k = 0; k < sizeof (piddesc_tables_output) / sizeof (piddesc_tables_output[0]); k++) + { + struct piddesc const * const table = piddesc_tables_output[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (entry->pid == PID_PAD) + continue; + if (((entry->flags & PDF_QOS) ? qw : pw) & entry->present_flag) + { + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t srcoff = entry->plist_offset - shift; + if (!(entry->flags & PDF_FUNCTION)) + ser_generic (xmsg, entry->pid, src, srcoff, entry->op.desc); + else + entry->op.f.ser (xmsg, entry->pid, src, srcoff); + } + } + } +} + +void nn_plist_fini (nn_plist_t *plist) +{ + plist_or_xqos_fini (plist, 0, ~(uint64_t)0, ~(uint64_t)0); +} + +void nn_plist_unalias (nn_plist_t *plist) +{ + plist_or_xqos_unalias (plist, 0); +} + +static dds_return_t nn_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos, bool strict) +{ + dds_return_t ret; + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (!(entry->flags & PDF_QOS)) + break; + if (xqos->present & entry->present_flag) + { + const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + if (!(entry->flags & PDF_FUNCTION)) + ret = valid_generic (xqos, srcoff, entry->op.desc); + else + ret = entry->op.f.valid (xqos, srcoff); + if (ret < 0) + { + DDS_CLOG (DDS_LC_PLIST, logcfg, "nn_xqos_valid: %s invalid\n", entry->name); + return ret; + } + } + } + } + if ((ret = final_validation_qos (xqos, (nn_protocol_version_t) { RTPS_MAJOR, RTPS_MINOR }, NN_VENDORID_ECLIPSE, NULL, strict)) < 0) + { + DDS_CLOG (DDS_LC_PLIST, logcfg, "nn_xqos_valid: final validation failed\n"); + } + return ret; +} + +dds_return_t nn_xqos_valid (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos) +{ + return nn_xqos_valid_strictness (logcfg, xqos, true); +} + +uint64_t nn_xqos_delta (const dds_qos_t *x, const dds_qos_t *y, uint64_t mask) +{ + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + /* Returns QP_... set for settings where x differs from y; if + present in x but not in y (or in y but not in x) it counts as a + difference. */ + uint64_t delta = (x->present ^ y->present) & mask; + const uint64_t check = (x->present & y->present) & mask; + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (!(entry->flags & PDF_QOS)) + break; + if (check & entry->present_flag) + { + const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + bool equal; + /* Partition is special-cased because it is a set (with a special rules + for empty sets and empty strings to boot), and normal string sequence + comparison requires the ordering to be the same */ + if (entry->pid == PID_PARTITION) + equal = partitions_equal (&x->partition, &y->partition); + else if (!(entry->flags & PDF_FUNCTION)) + equal = equal_generic (x, y, srcoff, entry->op.desc); + else + equal = entry->op.f.equal (x, y, srcoff); + if (!equal) + delta |= entry->present_flag; + } + } + } + return delta; +} + +static dds_return_t validate_external_duration (const ddsi_duration_t *d) +{ + /* Accepted are zero, positive, infinite or invalid as defined in + the DDS 2.1 spec, table 9.4. */ + if (d->seconds >= 0) + return 0; + else if (d->seconds == -1 && d->fraction == UINT32_MAX) + return 0; + else + return DDS_RETCODE_BAD_PARAMETER; +} + +static int history_qospolicy_allzero (const dds_history_qospolicy_t *q) +{ + return q->kind == DDS_HISTORY_KEEP_LAST && q->depth == 0; +} + +static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q) { /* Validity of history setting and of resource limits are dependent, but we don't have access to the resource limits here ... the @@ -610,304 +1565,87 @@ int validate_history_qospolicy (const nn_history_qospolicy_t *q) n possibly unlimited. */ switch (q->kind) { - case NN_KEEP_LAST_HISTORY_QOS: - case NN_KEEP_ALL_HISTORY_QOS: + case DDS_HISTORY_KEEP_LAST: + case DDS_HISTORY_KEEP_ALL: break; default: - DDS_TRACE("plist/validate_history_qospolicy: invalid kind (%d)\n", (int) q->kind); - return Q_ERR_INVALID; + return DDS_RETCODE_BAD_PARAMETER; } /* Accept all values for depth if kind = ALL */ - if (q->kind == NN_KEEP_LAST_HISTORY_QOS) - { - if (q->depth < 1) - { - DDS_TRACE("plist/validate_history_qospolicy: invalid depth (%d)\n", (int) q->depth); - return Q_ERR_INVALID; - } - } + if (q->kind == DDS_HISTORY_KEEP_LAST && q->depth < 1) + return DDS_RETCODE_BAD_PARAMETER; return 0; } -static void bswap_resource_limits_qospolicy (nn_resource_limits_qospolicy_t *q) -{ - q->max_samples = bswap4 (q->max_samples); - q->max_instances = bswap4 (q->max_instances); - q->max_samples_per_instance = bswap4 (q->max_samples_per_instance); -} - -static int resource_limits_qospolicy_allzero (const nn_resource_limits_qospolicy_t *q) +static int resource_limits_qospolicy_allzero (const dds_resource_limits_qospolicy_t *q) { return q->max_samples == 0 && q->max_instances == 0 && q->max_samples_per_instance == 0; } -int validate_resource_limits_qospolicy (const nn_resource_limits_qospolicy_t *q) +static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q) { - const int unlimited = NN_DDS_LENGTH_UNLIMITED; /* Note: dependent on history setting as well (see validate_history_qospolicy). Verifying only the internal consistency of the resource limits. */ - if (q->max_samples < 1 && q->max_samples != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples invalid (%d)\n", (int) q->max_samples); - return Q_ERR_INVALID; - } - if (q->max_instances < 1 && q->max_instances != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_instances invalid (%d)\n", (int) q->max_instances); - return Q_ERR_INVALID; - } - if (q->max_samples_per_instance < 1 && q->max_samples_per_instance != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples_per_instance invalid (%d)\n", (int) q->max_samples_per_instance); - return Q_ERR_INVALID; - } - if (q->max_samples != unlimited && q->max_samples_per_instance != unlimited) + if (q->max_samples < 1 && q->max_samples != DDS_LENGTH_UNLIMITED) + return DDS_RETCODE_BAD_PARAMETER; + if (q->max_instances < 1 && q->max_instances != DDS_LENGTH_UNLIMITED) + return DDS_RETCODE_BAD_PARAMETER; + if (q->max_samples_per_instance < 1 && q->max_samples_per_instance != DDS_LENGTH_UNLIMITED) + return DDS_RETCODE_BAD_PARAMETER; + if (q->max_samples != DDS_LENGTH_UNLIMITED && q->max_samples_per_instance != DDS_LENGTH_UNLIMITED) { /* Interpreting 7.1.3.19 as if "unlimited" is meant to mean "don't care" and any conditions related to it must be ignored. */ if (q->max_samples < q->max_samples_per_instance) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples (%d) and max_samples_per_instance (%d) incompatible\n", (int) q->max_samples, (int) q->max_samples_per_instance); - return Q_ERR_INVALID; - } + return DDS_RETCODE_INCONSISTENT_POLICY; } return 0; } -int validate_history_and_resource_limits (const nn_history_qospolicy_t *qh, const nn_resource_limits_qospolicy_t *qr) +static dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr) { - const int unlimited = NN_DDS_LENGTH_UNLIMITED; - int res; + dds_return_t res; if ((res = validate_history_qospolicy (qh)) < 0) - { - DDS_TRACE("plist/validate_history_and_resource_limits: history policy invalid\n"); return res; - } if ((res = validate_resource_limits_qospolicy (qr)) < 0) - { - DDS_TRACE("plist/validate_history_and_resource_limits: resource_limits policy invalid\n"); return res; - } switch (qh->kind) { - case NN_KEEP_ALL_HISTORY_QOS: + case DDS_HISTORY_KEEP_ALL: #if 0 /* See comment in validate_resource_limits, ref'ing 7.1.3.19 */ - if (qr->max_samples_per_instance != unlimited) - { - DDS_TRACE("plist/validate_history_and_resource_limits: max_samples_per_instance (%d) incompatible with KEEP_ALL policy\n", (int) qr->max_samples_per_instance); - return Q_ERR_INVALID; - } + if (qr->max_samples_per_instance != DDS_LENGTH_UNLIMITED) + return DDS_RETCODE_BAD_PARAMETER; #endif break; - case NN_KEEP_LAST_HISTORY_QOS: - if (qr->max_samples_per_instance != unlimited && qh->depth > qr->max_samples_per_instance) - { - DDS_TRACE("plist/validate_history_and_resource_limits: depth (%d) and max_samples_per_instance (%d) incompatible with KEEP_LAST policy\n", (int) qh->depth, (int) qr->max_samples_per_instance); - return Q_ERR_INVALID; - } + case DDS_HISTORY_KEEP_LAST: + if (qr->max_samples_per_instance != DDS_LENGTH_UNLIMITED && qh->depth > qr->max_samples_per_instance) + return DDS_RETCODE_INCONSISTENT_POLICY; break; } return 0; } -static void bswap_durability_service_qospolicy (nn_durability_service_qospolicy_t *q) -{ - bswap_duration (&q->service_cleanup_delay); - bswap_history_qospolicy (&q->history); - bswap_resource_limits_qospolicy (&q->resource_limits); -} - -static int durability_service_qospolicy_allzero (const nn_durability_service_qospolicy_t *q) +static int durability_service_qospolicy_allzero (const dds_durability_service_qospolicy_t *q) { return (history_qospolicy_allzero (&q->history) && resource_limits_qospolicy_allzero (&q->resource_limits) && - q->service_cleanup_delay.seconds == 0 && q->service_cleanup_delay.fraction == 0); + q->service_cleanup_delay == 0); } -static int validate_durability_service_qospolicy_acceptzero (const nn_durability_service_qospolicy_t *q, bool acceptzero) +static dds_return_t validate_durability_service_qospolicy_acceptzero (const dds_durability_service_qospolicy_t *q, bool acceptzero) { - int res; + dds_return_t res; if (acceptzero && durability_service_qospolicy_allzero (q)) return 0; - if ((res = validate_duration (&q->service_cleanup_delay)) < 0) - { - DDS_TRACE("plist/validate_durability_service_qospolicy: duration invalid\n"); - return res; - } + if (q->service_cleanup_delay < 0) + return DDS_RETCODE_BAD_PARAMETER; if ((res = validate_history_and_resource_limits (&q->history, &q->resource_limits)) < 0) - { - DDS_TRACE("plist/validate_durability_service_qospolicy: invalid history and/or resource limits\n"); return res; - } return 0; } -int validate_durability_service_qospolicy (const nn_durability_service_qospolicy_t *q) -{ - return validate_durability_service_qospolicy_acceptzero (q, false); -} - -static void bswap_liveliness_qospolicy (nn_liveliness_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); - bswap_duration (&q->lease_duration); -} - -int validate_liveliness_qospolicy (const nn_liveliness_qospolicy_t *q) -{ - int res; - switch (q->kind) - { - case NN_AUTOMATIC_LIVELINESS_QOS: - case NN_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS: - case NN_MANUAL_BY_TOPIC_LIVELINESS_QOS: - if ((res = validate_duration (&q->lease_duration)) < 0) - DDS_TRACE("plist/validate_liveliness_qospolicy: invalid lease duration\n"); - return res; - default: - DDS_TRACE("plist/validate_liveliness_qospolicy: invalid kind (%d)\n", (int) q->kind); - return Q_ERR_INVALID; - } -} - -static void bswap_external_reliability_qospolicy (nn_external_reliability_qospolicy_t *qext) -{ - qext->kind = bswap4u (qext->kind); - bswap_duration (&qext->max_blocking_time); -} - -static int validate_xform_reliability_qospolicy (nn_reliability_qospolicy_t *qdst, const nn_external_reliability_qospolicy_t *qext) -{ - int res; - qdst->max_blocking_time = qext->max_blocking_time; - if (NN_PEDANTIC_P) - { - switch (qext->kind) - { - case NN_PEDANTIC_BEST_EFFORT_RELIABILITY_QOS: - qdst->kind = NN_BEST_EFFORT_RELIABILITY_QOS; - return 0; - case NN_PEDANTIC_RELIABLE_RELIABILITY_QOS: - qdst->kind = NN_RELIABLE_RELIABILITY_QOS; - if ((res = validate_duration (&qdst->max_blocking_time)) < 0) - DDS_TRACE("plist/validate_xform_reliability_qospolicy[pedantic]: max_blocking_time invalid\n"); - return res; - default: - DDS_TRACE("plist/validate_xform_reliability_qospolicy[pedantic]: invalid kind (%d)\n", (int) qext->kind); - return Q_ERR_INVALID; - } - } - else - { - switch (qext->kind) - { - case NN_INTEROP_BEST_EFFORT_RELIABILITY_QOS: - qdst->kind = NN_BEST_EFFORT_RELIABILITY_QOS; - return 0; - case NN_INTEROP_RELIABLE_RELIABILITY_QOS: - qdst->kind = NN_RELIABLE_RELIABILITY_QOS; - if ((res = validate_duration (&qdst->max_blocking_time)) < 0) - DDS_TRACE("plist/validate_xform_reliability_qospolicy[!pedantic]: max_blocking time invalid\n"); - return res; - default: - DDS_TRACE("plist/validate_xform_reliability_qospolicy[!pedantic]: invalid kind (%d)\n", (int) qext->kind); - return Q_ERR_INVALID; - } - } -} - -static void bswap_destination_order_qospolicy (nn_destination_order_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -int validate_destination_order_qospolicy (const nn_destination_order_qospolicy_t *q) -{ - switch (q->kind) - { - case NN_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS: - case NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS: - return 0; - default: - DDS_TRACE("plist/validate_destination_order_qospolicy: invalid kind (%d)\n", (int) q->kind); - return Q_ERR_INVALID; - } -} - -static void bswap_ownership_qospolicy (nn_ownership_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -int validate_ownership_qospolicy (const nn_ownership_qospolicy_t *q) -{ - switch (q->kind) - { - case NN_SHARED_OWNERSHIP_QOS: - case NN_EXCLUSIVE_OWNERSHIP_QOS: - return 0; - default: - DDS_TRACE("plist/validate_ownership_qospolicy: invalid kind (%d)\n", (int) q->kind); - return Q_ERR_INVALID; - } -} - -static void bswap_ownership_strength_qospolicy (nn_ownership_strength_qospolicy_t *q) -{ - q->value = bswap4 (q->value); -} - -int validate_ownership_strength_qospolicy (UNUSED_ARG (const nn_ownership_strength_qospolicy_t *q)) -{ - return 1; -} - -static void bswap_presentation_qospolicy (nn_presentation_qospolicy_t *q) -{ - q->access_scope = bswap4u (q->access_scope); -} - -int validate_presentation_qospolicy (const nn_presentation_qospolicy_t *q) -{ - switch (q->access_scope) - { - case NN_INSTANCE_PRESENTATION_QOS: - case NN_TOPIC_PRESENTATION_QOS: - case NN_GROUP_PRESENTATION_QOS: - break; - default: - DDS_TRACE("plist/validate_presentation_qospolicy: invalid access_scope (%d)\n", (int) q->access_scope); - return Q_ERR_INVALID; - } - /* Bools must be 0 or 1, i.e., only the lsb may be set */ - if (q->coherent_access & ~1) - { - DDS_TRACE("plist/validate_presentation_qospolicy: coherent_access invalid (%d)\n", (int) q->coherent_access); - return Q_ERR_INVALID; - } - if (q->ordered_access & ~1) - { - DDS_TRACE("plist/validate_presentation_qospolicy: ordered_access invalid (%d)\n", (int) q->ordered_access); - return Q_ERR_INVALID; - } - /* coherent_access & ordered_access are a bit irrelevant for - instance presentation qos, but it appears as if their values are - not prescribed in that case. */ - return 0; -} - -static void bswap_transport_priority_qospolicy (nn_transport_priority_qospolicy_t *q) -{ - q->value = bswap4 (q->value); -} - -int validate_transport_priority_qospolicy (UNUSED_ARG (const nn_transport_priority_qospolicy_t *q)) -{ - return 1; -} - -static int add_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const nn_locator_t *loc) +static dds_return_t add_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const nn_locator_t *loc) { if (wanted & fl) { @@ -940,33 +1678,24 @@ static int locator_address_prefix12_zero (const nn_locator_t *loc) /* loc has has 32 bit ints preceding the address, hence address is 4-byte aligned; reading char* as unsigneds isn't illegal type punning */ - const unsigned *u = (const unsigned *) loc->address; + const uint32_t *u = (const uint32_t *) loc->address; return (u[0] == 0 && u[1] == 0 && u[2] == 0); } static int locator_address_zero (const nn_locator_t *loc) { /* see locator_address_prefix12_zero */ - const unsigned *u = (const unsigned *) loc->address; + const uint32_t *u = (const uint32_t *) loc->address; return (u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0); } -static int do_locator -( - nn_locators_t *ls, - uint64_t *present, - uint64_t wanted, - uint64_t fl, - const struct dd *dd -) +static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const struct dd *dd, const struct ddsi_tran_factory *factory) { nn_locator_t loc; if (dd->bufsz < sizeof (loc)) - { - DDS_TRACE("plist/do_locator: buffer too small\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; + memcpy (&loc, dd->buf, sizeof (loc)); if (dd->bswap) { @@ -978,83 +1707,58 @@ static int do_locator case NN_LOCATOR_KIND_UDPv4: case NN_LOCATOR_KIND_TCPv4: if (loc.port <= 0 || loc.port > 65535) - { - DDS_TRACE("plist/do_locator[kind=IPv4]: invalid port (%d)\n", (int) loc.port); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; if (!locator_address_prefix12_zero (&loc)) - { - DDS_TRACE("plist/do_locator[kind=IPv4]: junk in address prefix\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; break; case NN_LOCATOR_KIND_UDPv6: case NN_LOCATOR_KIND_TCPv6: if (loc.port <= 0 || loc.port > 65535) - { - DDS_TRACE("plist/do_locator[kind=IPv6]: invalid port (%d)\n", (int) loc.port); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; break; case NN_LOCATOR_KIND_UDPv4MCGEN: { const nn_udpv4mcgen_address_t *x = (const nn_udpv4mcgen_address_t *) loc.address; - if (!ddsi_factory_supports(gv.m_factory, NN_LOCATOR_KIND_UDPv4)) + if (!ddsi_factory_supports (factory, NN_LOCATOR_KIND_UDPv4)) return 0; if (loc.port <= 0 || loc.port > 65536) - { - DDS_TRACE("plist/do_locator[kind=IPv4MCGEN]: invalid port (%d)\n", (int) loc.port); - return Q_ERR_INVALID; - } - if ((int)x->base + x->count >= 28 || x->count == 0 || x->idx >= x->count) - { - DDS_TRACE("plist/do_locator[kind=IPv4MCGEN]: invalid base/count/idx (%u,%u,%u)\n", x->base, x->count, x->idx); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; + if ((uint32_t) x->base + x->count >= 28 || x->count == 0 || x->idx >= x->count) + return DDS_RETCODE_BAD_PARAMETER; break; } case NN_LOCATOR_KIND_INVALID: if (!locator_address_zero (&loc)) - { - DDS_TRACE("plist/do_locator[kind=INVALID]: junk in address\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; if (loc.port != 0) - { - DDS_TRACE("plist/do_locator[kind=INVALID]: junk in port\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; /* silently dropped correctly formatted "invalid" locators. */ return 0; case NN_LOCATOR_KIND_RESERVED: /* silently dropped "reserved" locators. */ return 0; default: - DDS_TRACE("plist/do_locator: invalid kind (%d)\n", (int) loc.kind); - return NN_PEDANTIC_P ? Q_ERR_INVALID : 0; + return 0; } return add_locator (ls, present, wanted, fl, &loc); } -static void locator_from_ipv4address_port (nn_locator_t *loc, const nn_ipv4address_t *a, const nn_port_t *p) +static void locator_from_ipv4address_port (nn_locator_t *loc, const nn_ipv4address_t *a, const nn_port_t *p, ddsi_tran_factory_t factory) { - loc->kind = gv.m_factory->m_connless ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_TCPv4; + loc->kind = factory->m_connless ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_TCPv4; loc->port = *p; memset (loc->address, 0, 12); memcpy (loc->address + 12, a, 4); } -static int do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t wanted, unsigned fl_tmp, const struct dd *dd) +static dds_return_t do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t wanted, uint32_t fl_tmp, const struct dd *dd, ddsi_tran_factory_t factory) { nn_ipv4address_t *a; nn_port_t *p; nn_locators_t *ls; - unsigned fl1_tmp; + uint32_t fl1_tmp; uint64_t fldest; if (dd->bufsz < sizeof (*a)) - { - DDS_TRACE("plist/do_ipv4address: buffer too small\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; switch (fl_tmp) { case PPTMP_MULTICAST_IPADDRESS: @@ -1103,7 +1807,7 @@ static int do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp allows adding another pair. */ nn_locator_t loc; - locator_from_ipv4address_port (&loc, a, p); + locator_from_ipv4address_port (&loc, a, p, factory); dest_tmp->present &= ~(fl_tmp | fl1_tmp); return add_locator (ls, &dest->present, wanted, fldest, &loc); } @@ -1113,18 +1817,15 @@ static int do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp } } -static int do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t wanted, unsigned fl_tmp, const struct dd *dd) +static dds_return_t do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t wanted, uint32_t fl_tmp, const struct dd *dd, ddsi_tran_factory_t factory) { nn_ipv4address_t *a; nn_port_t *p; nn_locators_t *ls; uint64_t fldest; - unsigned fl1_tmp; + uint32_t fl1_tmp; if (dd->bufsz < sizeof (*p)) - { - DDS_TRACE("plist/do_port: buffer too small\n"); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; switch (fl_tmp) { case PPTMP_DEFAULT_UNICAST_PORT: @@ -1155,10 +1856,7 @@ static int do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint6 if (dd->bswap) *p = bswap4u (*p); if (*p <= 0 || *p > 65535) - { - DDS_TRACE("plist/do_port: invalid port (%d)\n", (int) *p); - return Q_ERR_INVALID; - } + return DDS_RETCODE_BAD_PARAMETER; dest_tmp->present |= fl_tmp; if ((dest_tmp->present & (fl_tmp | fl1_tmp)) == (fl_tmp | fl1_tmp)) { @@ -1166,7 +1864,7 @@ static int do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint6 both address & port from the set of present plist: this allows adding another pair. */ nn_locator_t loc; - locator_from_ipv4address_port (&loc, a, p); + locator_from_ipv4address_port (&loc, a, p, factory); dest_tmp->present &= ~(fl_tmp | fl1_tmp); return add_locator (ls, &dest->present, wanted, fldest, &loc); } @@ -1176,1118 +1874,133 @@ static int do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_tmp, uint6 } } -static int valid_participant_guid (const nn_guid_t *g, UNUSED_ARG (const struct dd *dd)) +static dds_return_t return_unrecognized_pid (nn_plist_t *plist, nn_parameterid_t pid) { - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_participant_guid: prefix is 0 but entityid is not (%"PRIu32")\n", g->entityid.u); - return Q_ERR_INVALID; - } - } - else if (g->entityid.u == NN_ENTITYID_PARTICIPANT) - { + if (!(pid & PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)) return 0; - } else { - DDS_TRACE("plist/valid_participant_guid: entityid not a participant entityid (%"PRIu32")\n", g->entityid.u); - return Q_ERR_INVALID; + plist->present |= PP_INCOMPATIBLE; + return DDS_RETCODE_UNSUPPORTED; } } -static int valid_group_guid (const nn_guid_t *g, UNUSED_ARG (const struct dd *dd)) +static dds_return_t init_one_parameter (nn_plist_t *plist, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t pwanted, uint64_t qwanted, uint16_t pid, const struct dd *dd, ddsi_tran_factory_t factory, const ddsrt_log_cfg_t *logcfg) { - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_group_guid: prefix is 0 but entityid is not (%"PRIu32")\n", g->entityid.u); - return Q_ERR_INVALID; - } - } - else if (g->entityid.u != 0) - { - /* accept any entity id */ - return 0; - } - else - { - DDS_TRACE("plist/valid_group_guid: entityid is 0\n"); - return Q_ERR_INVALID; - } -} - -static int valid_endpoint_guid (const nn_guid_t *g, const struct dd *dd) -{ - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid: prefix is 0 but entityid is not (%"PRIx32")\n", g->entityid.u); - return Q_ERR_INVALID; - } - } - switch (g->entityid.u & NN_ENTITYID_SOURCE_MASK) - { - case NN_ENTITYID_SOURCE_USER: - switch (g->entityid.u & NN_ENTITYID_KIND_MASK) - { - case NN_ENTITYID_KIND_WRITER_WITH_KEY: - case NN_ENTITYID_KIND_WRITER_NO_KEY: - case NN_ENTITYID_KIND_READER_NO_KEY: - case NN_ENTITYID_KIND_READER_WITH_KEY: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=USER,proto=%u.%u]: invalid kind (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, - g->entityid.u & NN_ENTITYID_KIND_MASK); - return Q_ERR_INVALID; - } - } - case NN_ENTITYID_SOURCE_BUILTIN: - switch (g->entityid.u) - { - case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_TOPIC_READER: - case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER: - case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER: - case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER: - case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: - case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=BUILTIN,proto=%u.%u]: invalid entityid (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, g->entityid.u); - return Q_ERR_INVALID; - } - } - case NN_ENTITYID_SOURCE_VENDOR: - if (!vendor_is_eclipse (dd->vendorid)) - return 0; - else - { - switch (g->entityid.u) - { - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=VENDOR,proto=%u.%u]: unexpected entityid (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, g->entityid.u); - return 0; - } - } - } - default: - DDS_TRACE("plist/valid_endpoint_guid: invalid source (%"PRIx32")\n", g->entityid.u); - return Q_ERR_INVALID; - } -} - -static int do_guid (nn_guid_t *dst, uint64_t *present, uint64_t fl, int (*valid) (const nn_guid_t *g, const struct dd *dd), const struct dd *dd) -{ - if (dd->bufsz < sizeof (*dst)) - { - DDS_TRACE("plist/do_guid: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (dst, dd->buf, sizeof (*dst)); - *dst = nn_ntoh_guid (*dst); - if (valid (dst, dd) < 0) - { - /* CoreDX once upon a time used to send out PARTICIPANT_GUID parameters with a 0 entity id, but it - that has long since changed (even if I don't know exactly when) */ - if (fl == PP_PARTICIPANT_GUID && vendor_is_twinoaks (dd->vendorid) && dst->entityid.u == 0 && ! NN_STRICT_P) - { - DDS_LOG(DDS_LC_DISCOVERY, "plist(vendor %u.%u): rewriting invalid participant guid "PGUIDFMT, - dd->vendorid.id[0], dd->vendorid.id[1], PGUID (*dst)); - dst->entityid.u = NN_ENTITYID_PARTICIPANT; - } - else - { - return Q_ERR_INVALID; - } - } - *present |= fl; - return 0; -} - - -static void bswap_prismtech_participant_version_info (nn_prismtech_participant_version_info_t *pvi) -{ - int i; - pvi->version = bswap4u (pvi->version); - pvi->flags = bswap4u (pvi->flags); - for (i = 0; i < 3; i++) - pvi->unused[i] = bswap4u (pvi->unused[i]); -} - -static int do_prismtech_participant_version_info (nn_prismtech_participant_version_info_t *pvi, uint64_t *present, uint64_t *aliased, const struct dd *dd) -{ - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE) - { - DDS_TRACE("plist/do_prismtech_participant_version_info[pid=PRISMTECH_PARTICIPANT_VERSION_INFO]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - int res; - unsigned sz = NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE - sizeof(uint32_t); - uint32_t *pu = (uint32_t *)dd->buf; - size_t len; - struct dd dd1 = *dd; - - memcpy (pvi, dd->buf, sz); - if (dd->bswap) - bswap_prismtech_participant_version_info(pvi); - - dd1.buf = (unsigned char *) &pu[5]; - dd1.bufsz = dd->bufsz - sz; - if ((res = alias_string ((const unsigned char **) &pvi->internals, &dd1, &len)) >= 0) { - *present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - *aliased |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - res = 0; - } - - return res; - } -} - - - -static int do_subscription_keys_qospolicy (nn_subscription_keys_qospolicy_t *q, uint64_t *present, uint64_t *aliased, uint64_t fl, const struct dd *dd) -{ - struct dd dd1; - int res; - if (dd->bufsz < 4) - { - DDS_TRACE("plist/do_subscription_keys: buffer too small\n"); - return Q_ERR_INVALID; - } - q->use_key_list = (unsigned char) dd->buf[0]; - if (q->use_key_list != 0 && q->use_key_list != 1) - { - DDS_TRACE("plist/do_subscription_keys: invalid use_key_list (%d)\n", (int) q->use_key_list); - return Q_ERR_INVALID; - } - dd1 = *dd; - dd1.buf += 4; - dd1.bufsz -= 4; - if ((res = alias_stringseq (&q->key_list, &dd1)) >= 0) - { - *present |= fl; - *aliased |= fl; - } - return res; -} - -static int unalias_subscription_keys_qospolicy (nn_subscription_keys_qospolicy_t *q, int bswap) -{ - return unalias_stringseq (&q->key_list, bswap); -} - -static int do_reader_lifespan_qospolicy (nn_reader_lifespan_qospolicy_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - int res; - if (dd->bufsz < sizeof (*q)) - { - DDS_TRACE("plist/do_reader_lifespan: buffer too small\n"); - return Q_ERR_INVALID; - } - *q = *((nn_reader_lifespan_qospolicy_t *) dd->buf); - if (dd->bswap) - bswap_duration (&q->duration); - if (q->use_lifespan != 0 && q->use_lifespan != 1) - { - DDS_TRACE("plist/do_reader_lifespan: invalid use_lifespan (%d)\n", (int) q->use_lifespan); - return Q_ERR_INVALID; - } - if ((res = validate_duration (&q->duration)) >= 0) - *present |= fl; - return res; -} - -static int do_entity_factory_qospolicy (nn_entity_factory_qospolicy_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - if (dd->bufsz < sizeof (*q)) - { - DDS_TRACE("plist/do_entity_factory: buffer too small\n"); - return Q_ERR_INVALID; - } - q->autoenable_created_entities = dd->buf[0]; - if (q->autoenable_created_entities != 0 && q->autoenable_created_entities != 1) - { - DDS_TRACE("plist/do_entity_factory: invalid autoenable_created_entities (%d)\n", (int) q->autoenable_created_entities); - return Q_ERR_INVALID; - } - *present |= fl; - return 0; -} - -int validate_reader_data_lifecycle (const nn_reader_data_lifecycle_qospolicy_t *q) -{ - if (validate_duration (&q->autopurge_nowriter_samples_delay) < 0 || - validate_duration (&q->autopurge_disposed_samples_delay) < 0) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: invalid autopurge_nowriter_sample_delay or autopurge_disposed_samples_delay\n"); - return Q_ERR_INVALID; - } - if (q->autopurge_dispose_all != 0 && q->autopurge_dispose_all != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: invalid autopurge_dispose_all\n"); - return Q_ERR_INVALID; - } - if (q->enable_invalid_samples != 0 && q->enable_invalid_samples != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: invalid enable_invalid_samples\n"); - return Q_ERR_INVALID; - } - /* Don't check consistency between enable_invalid_samples and invalid_samples_mode (yet) */ - switch (q->invalid_sample_visibility) - { - case NN_NO_INVALID_SAMPLE_VISIBILITY_QOS: - case NN_MINIMUM_INVALID_SAMPLE_VISIBILITY_QOS: - case NN_ALL_INVALID_SAMPLE_VISIBILITY_QOS: - break; - default: - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: invalid invalid_sample_visibility\n"); - return Q_ERR_INVALID; - } - return 0; -} - -static int do_reader_data_lifecycle_v0 (nn_reader_data_lifecycle_qospolicy_t *q, const struct dd *dd) -{ - memcpy (q, dd->buf, 2 * sizeof (nn_duration_t)); - q->autopurge_dispose_all = 0; - q->enable_invalid_samples = 1; - q->invalid_sample_visibility = NN_MINIMUM_INVALID_SAMPLE_VISIBILITY_QOS; - if (dd->bswap) - { - bswap_duration (&q->autopurge_nowriter_samples_delay); - bswap_duration (&q->autopurge_disposed_samples_delay); - } - return validate_reader_data_lifecycle (q); -} - -static int do_reader_data_lifecycle_v1 (nn_reader_data_lifecycle_qospolicy_t *q, const struct dd *dd) -{ - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - { - bswap_duration (&q->autopurge_nowriter_samples_delay); - bswap_duration (&q->autopurge_disposed_samples_delay); - q->invalid_sample_visibility = (nn_invalid_sample_visibility_kind_t) bswap4u ((unsigned) q->invalid_sample_visibility); - } - return validate_reader_data_lifecycle (q); -} - -static int init_one_parameter -( - nn_plist_t *dest, - nn_ipaddress_params_tmp_t *dest_tmp, - uint64_t pwanted, - uint64_t qwanted, - unsigned short pid, - const struct dd *dd -) -{ - int res; + /* special-cased ipv4address and port, because they have state beyond that what gets + passed into the generic code */ switch (pid) { - case PID_PAD: - case PID_SENTINEL: - return 0; - - /* Extended QoS data: */ -#define Q(NAME_, name_) case PID_##NAME_: \ - if (dd->bufsz < sizeof (nn_##name_##_qospolicy_t)) \ - { \ - DDS_TRACE("plist/init_one_parameter[pid=%s]: buffer too small\n", #NAME_); \ - return Q_ERR_INVALID; \ - } \ - else \ - { \ - nn_##name_##_qospolicy_t *q = &dest->qos.name_; \ - memcpy (q, dd->buf, sizeof (*q)); \ - if (dd->bswap) bswap_##name_##_qospolicy (q); \ - if ((res = validate_##name_##_qospolicy (q)) < 0) \ - return res; \ - dest->qos.present |= QP_##NAME_; \ - } \ - return 0 - Q (DURABILITY, durability); - Q (LIVELINESS, liveliness); - Q (DESTINATION_ORDER, destination_order); - Q (HISTORY, history); - Q (RESOURCE_LIMITS, resource_limits); - Q (OWNERSHIP, ownership); - Q (OWNERSHIP_STRENGTH, ownership_strength); - Q (PRESENTATION, presentation); - Q (TRANSPORT_PRIORITY, transport_priority); -#undef Q - - case PID_DURABILITY_SERVICE: - if (dd->bufsz < sizeof (nn_durability_service_qospolicy_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=DURABILITY_SERVICE]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_durability_service_qospolicy_t *q = &dest->qos.durability_service; - /* All-zero durability service is illegal, but at least CoreDX sometimes advertises - it in some harmless cases. So accept all-zero durability service, then handle it - in final_validation, where we can determine whether it really is harmless or not */ - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - bswap_durability_service_qospolicy (q); - if ((res = validate_durability_service_qospolicy_acceptzero (q, true)) < 0) - return res; - dest->qos.present |= QP_DURABILITY_SERVICE; - } - return 0; - - /* PID_RELIABILITY handled differently because it (formally, for - static typing reasons) has a different type on the network - than internally, with the transformation between the two - dependent on wheter we are being pedantic. If that weren't - the case, it would've been an ordinary Q (RELIABILITY, - reliability). */ - case PID_RELIABILITY: - if (dd->bufsz < sizeof (nn_external_reliability_qospolicy_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=RELIABILITY]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_reliability_qospolicy_t *q = &dest->qos.reliability; - nn_external_reliability_qospolicy_t qext; - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - bswap_external_reliability_qospolicy (&qext); - if ((res = validate_xform_reliability_qospolicy (q, &qext)) < 0) - return res; - dest->qos.present |= QP_RELIABILITY; - } - return 0; - - case PID_TOPIC_NAME: - return do_string (&dest->qos.topic_name, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TOPIC_NAME, dd); - case PID_TYPE_NAME: - return do_string (&dest->qos.type_name, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TYPE_NAME, dd); - - case PID_USER_DATA: - return do_octetseq (&dest->qos.user_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_USER_DATA, dd); - case PID_GROUP_DATA: - return do_octetseq (&dest->qos.group_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_GROUP_DATA, dd); - case PID_TOPIC_DATA: - return do_octetseq (&dest->qos.topic_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TOPIC_DATA, dd); - - case PID_DEADLINE: - return do_duration (&dest->qos.deadline.deadline, &dest->qos.present, QP_DEADLINE, dd); - case PID_LATENCY_BUDGET: - return do_duration (&dest->qos.latency_budget.duration, &dest->qos.present, QP_LATENCY_BUDGET, dd); - case PID_LIFESPAN: - return do_duration (&dest->qos.lifespan.duration, &dest->qos.present, QP_LIFESPAN, dd); - case PID_TIME_BASED_FILTER: - return do_duration (&dest->qos.time_based_filter.minimum_separation, &dest->qos.present, QP_TIME_BASED_FILTER, dd); - - case PID_PARTITION: - return do_stringseq (&dest->qos.partition, &dest->qos.present, &dest->qos.aliased, qwanted, QP_PARTITION, dd); - - case PID_PRISMTECH_READER_DATA_LIFECYCLE: /* PrismTech specific */ - { - int ret; - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz >= sizeof (nn_reader_data_lifecycle_qospolicy_t)) - ret = do_reader_data_lifecycle_v1 (&dest->qos.reader_data_lifecycle, dd); - else if (dd->bufsz >= 2 * sizeof (nn_duration_t)) - ret = do_reader_data_lifecycle_v0 (&dest->qos.reader_data_lifecycle, dd); - else - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: buffer too small\n"); - ret = Q_ERR_INVALID; - } - if (ret >= 0) - dest->qos.present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - return ret; - } - case PID_PRISMTECH_WRITER_DATA_LIFECYCLE: /* PrismTech specific */ - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else - { - nn_writer_data_lifecycle_qospolicy_t *q = &dest->qos.writer_data_lifecycle; - if (dd->bufsz < 1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_WRITER_DATA_LIFECYCLE]: buffer too small\n"); - return Q_ERR_INVALID; - } - else if (dd->bufsz < sizeof (*q)) - { - /* Spec form, with just autodispose_unregistered_instances */ - q->autodispose_unregistered_instances = dd->buf[0]; - q->autounregister_instance_delay = nn_to_ddsi_duration (T_NEVER); - q->autopurge_suspended_samples_delay = nn_to_ddsi_duration (T_NEVER); - } - else - { - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - { - bswap_duration (&q->autounregister_instance_delay); - bswap_duration (&q->autopurge_suspended_samples_delay); - } - } - if (q->autodispose_unregistered_instances & ~1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_WRITER_DATA_LIFECYCLE]: invalid autodispose_unregistered_instances (%d)\n", (int) q->autodispose_unregistered_instances); - return Q_ERR_INVALID; - } - if (validate_duration (&q->autounregister_instance_delay) < 0 || - validate_duration (&q->autopurge_suspended_samples_delay) < 0) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_WRITER_DATA_LIFECYCLE]: invalid autounregister_instance_delay or autopurge_suspended_samples_delay\n"); - return Q_ERR_INVALID; - } - dest->qos.present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - return 0; - } - - case PID_PRISMTECH_RELAXED_QOS_MATCHING: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < sizeof (dest->qos.relaxed_qos_matching)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_RELAXED_QOS_MATCHING]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_relaxed_qos_matching_qospolicy_t *rqm = &dest->qos.relaxed_qos_matching; - memcpy (rqm, dd->buf, sizeof (*rqm)); - if (rqm->value != 0 && rqm->value != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_RELAXED_QOS_MATCHING]: invalid\n"); - return Q_ERR_INVALID; - } - dest->qos.present |= QP_PRISMTECH_RELAXED_QOS_MATCHING; - return 0; - } - - case PID_PRISMTECH_SYNCHRONOUS_ENDPOINT: /* PrismTech specific */ - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < sizeof (dest->qos.synchronous_endpoint)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_SYNCHRONOUS_ENDPOINT]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_synchronous_endpoint_qospolicy_t *q = &dest->qos.synchronous_endpoint; - memcpy (q, dd->buf, sizeof (*q)); - if (q->value != 0 && q->value != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_SYNCHRONOUS_ENDPOINT]: invalid value for synchronous flag\n"); - return Q_ERR_INVALID; - } - dest->qos.present |= QP_PRISMTECH_SYNCHRONOUS_ENDPOINT; - return 0; - } - - /* Other plist */ - case PID_PROTOCOL_VERSION: - if (dd->bufsz < sizeof (nn_protocol_version_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PROTOCOL_VERSION]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->protocol_version, dd->buf, sizeof (dest->protocol_version)); - if (NN_STRICT_P && - (dest->protocol_version.major != dd->protocol_version.major || - dest->protocol_version.minor != dd->protocol_version.minor)) - { - /* Not accepting a submessage advertising a protocol version - other than that advertised by the message header, unless I - have good reason to, at least not when being strict. */ - DDS_TRACE("plist/init_one_parameter[pid=PROTOCOL_VERSION,mode=STRICT]: version (%u.%u) mismatch with message (%u.%u)\n", - dest->protocol_version.major, dest->protocol_version.minor, - dd->protocol_version.major, dd->protocol_version.minor); - return Q_ERR_INVALID; - } - dest->present |= PP_PROTOCOL_VERSION; - return 0; - - case PID_VENDORID: - if (dd->bufsz < sizeof (nn_vendorid_t)) - return Q_ERR_INVALID; - memcpy (&dest->vendorid, dd->buf, sizeof (dest->vendorid)); - if (NN_STRICT_P && - (dest->vendorid.id[0] != dd->vendorid.id[0] || - dest->vendorid.id[1] != dd->vendorid.id[1])) - { - /* see PROTOCOL_VERSION */ - DDS_TRACE("plist/init_one_parameter[pid=VENDORID,mode=STRICT]: vendor (%u.%u) mismatch with message (%u.%u)\n", - dest->vendorid.id[0], dest->vendorid.id[1], dd->vendorid.id[0], dd->vendorid.id[1]); - return Q_ERR_INVALID; - } - dest->present |= PP_VENDORID; - return 0; - - /* Locators: there may be lists, so we have to allocate memory for them */ -#define XL(NAME_, name_) case PID_##NAME_##_LOCATOR: return do_locator (&dest->name_##_locators, &dest->present, pwanted, PP_##NAME_##_LOCATOR, dd) - XL (UNICAST, unicast); - XL (MULTICAST, multicast); - XL (DEFAULT_UNICAST, default_unicast); - XL (DEFAULT_MULTICAST, default_multicast); - XL (METATRAFFIC_UNICAST, metatraffic_unicast); - XL (METATRAFFIC_MULTICAST, metatraffic_multicast); -#undef XL - - /* IPADDRESS + PORT entries are a nuisance ... I'd prefer - converting them to locators right away, so that the rest of - the code only has to deal with locators, but that is - impossible because the locators require both the address & - the port to be known. - - The wireshark dissector suggests IPvAdress_t is just the 32 - bits of the IP address but it doesn't say so anywhere - ... Similarly for ports, but contrary to the expections they - seem to be 32-bits, too. Apparently in host-endianness. - - And, to be honest, I have no idea what port to use for - MULTICAST_IPADDRESS ... */ -#define XA(NAME_) case PID_##NAME_##_IPADDRESS: return do_ipv4address (dest, dest_tmp, pwanted, PPTMP_##NAME_##_IPADDRESS, dd) -#define XP(NAME_) case PID_##NAME_##_PORT: return do_port (dest, dest_tmp, pwanted, PPTMP_##NAME_##_PORT, dd) - XA (MULTICAST); - XA (DEFAULT_UNICAST); - XP (DEFAULT_UNICAST); - XA (METATRAFFIC_UNICAST); - XP (METATRAFFIC_UNICAST); - XA (METATRAFFIC_MULTICAST); - XP (METATRAFFIC_MULTICAST); +#define XA(NAME_) case PID_##NAME_##_IPADDRESS: return do_ipv4address (plist, dest_tmp, pwanted, PPTMP_##NAME_##_IPADDRESS, dd, factory) +#define XP(NAME_) case PID_##NAME_##_PORT: return do_port (plist, dest_tmp, pwanted, PPTMP_##NAME_##_PORT, dd, factory) + XA (MULTICAST); + XA (DEFAULT_UNICAST); + XP (DEFAULT_UNICAST); + XA (METATRAFFIC_UNICAST); + XP (METATRAFFIC_UNICAST); + XA (METATRAFFIC_MULTICAST); + XP (METATRAFFIC_MULTICAST); #undef XP #undef XA - - case PID_EXPECTS_INLINE_QOS: - if (dd->bufsz < sizeof (dest->expects_inline_qos)) - { - DDS_TRACE("plist/init_one_parameter[pid=EXPECTS_INLINE_QOS]: buffer too small\n"); - return Q_ERR_INVALID; - } - dest->expects_inline_qos = dd->buf[0]; - /* boolean: only lsb may be set */ - if (dest->expects_inline_qos & ~1) - { - DDS_TRACE("plist/init_one_parameter[pid=EXPECTS_INLINE_QOS]: invalid expects_inline_qos (%d)\n", - (int) dest->expects_inline_qos); - return Q_ERR_INVALID; - } - dest->present |= PP_EXPECTS_INLINE_QOS; - return 0; - - case PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT: - /* Spec'd as "incremented monotonically" (DDSI 2.1, table 8.13), - but 32 bits signed is not such a smart choice for that. We'll - simply accept any value. */ - if (dd->bufsz < sizeof (dest->participant_manual_liveliness_count)) - { - DDS_TRACE("plist/init_one_parameter[pid=PARTICIPANT_MANUAL_LIVELINESS_COUNT]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->participant_manual_liveliness_count, dd->buf, sizeof (dest->participant_manual_liveliness_count)); - if (dd->bswap) - dest->participant_manual_liveliness_count = bswap4 (dest->participant_manual_liveliness_count); - dest->present |= PP_PARTICIPANT_MANUAL_LIVELINESS_COUNT; - return 0; - - case PID_PARTICIPANT_LEASE_DURATION: - return do_duration (&dest->participant_lease_duration, &dest->present, PP_PARTICIPANT_LEASE_DURATION, dd); - - case PID_CONTENT_FILTER_PROPERTY: - /* FIXME */ - return 0; - - case PID_PARTICIPANT_GUID: - return do_guid (&dest->participant_guid, &dest->present, PP_PARTICIPANT_GUID, valid_participant_guid, dd); - - case PID_GROUP_GUID: - return do_guid (&dest->group_guid, &dest->present, PP_GROUP_GUID, valid_group_guid, dd); - - case PID_PARTICIPANT_ENTITYID: - case PID_GROUP_ENTITYID: - /* DDSI 2.1 table 9.13: reserved for future use */ - return 0; - - case PID_PARTICIPANT_BUILTIN_ENDPOINTS: - /* FIXME: I assume it is the same as the BUILTIN_ENDPOINT_SET, - which is the set that DDSI2 has been using so far. */ - /* FALLS THROUGH */ - case PID_BUILTIN_ENDPOINT_SET: - if (dd->bufsz < sizeof (dest->builtin_endpoint_set)) - { - DDS_TRACE("plist/init_one_parameter[pid=BUILTIN_ENDPOINT_SET(%u)]: buffer too small\n", pid); - return Q_ERR_INVALID; - } - memcpy (&dest->builtin_endpoint_set, dd->buf, sizeof (dest->builtin_endpoint_set)); - if (dd->bswap) - dest->builtin_endpoint_set = bswap4u (dest->builtin_endpoint_set); - if (NN_STRICT_P && !protocol_version_is_newer (dd->protocol_version) && - (dest->builtin_endpoint_set & ~(NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR | - /* undefined ones: */ - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_DETECTOR | - /* defined ones again: */ - NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER | - NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER)) != 0) - { - DDS_TRACE("plist/init_one_parameter[pid=BUILTIN_ENDPOINT_SET(%u),mode=STRICT,proto=%u.%u]: invalid set (0x%x)\n", - pid, dd->protocol_version.major, dd->protocol_version.minor, dest->builtin_endpoint_set); - return Q_ERR_INVALID; - } - dest->present |= PP_BUILTIN_ENDPOINT_SET; - return 0; - - case PID_PRISMTECH_BUILTIN_ENDPOINT_SET: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < sizeof (dest->prismtech_builtin_endpoint_set)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_BUILTIN_ENDPOINT_SET(%u)]: buffer too small\n", pid); - return Q_ERR_INVALID; - } - else - { - memcpy (&dest->prismtech_builtin_endpoint_set, dd->buf, sizeof (dest->prismtech_builtin_endpoint_set)); - if (dd->bswap) - dest->prismtech_builtin_endpoint_set = bswap4u (dest->prismtech_builtin_endpoint_set); - dest->present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET; - } - return 0; - - case PID_PROPERTY_LIST: - case PID_TYPE_MAX_SIZE_SERIALIZED: - /* FIXME */ - return 0; - - case PID_ENTITY_NAME: - return do_string (&dest->entity_name, &dest->present, &dest->aliased, pwanted, PP_ENTITY_NAME, dd); - - case PID_KEYHASH: - if (dd->bufsz < sizeof (dest->keyhash)) - { - DDS_TRACE("plist/init_one_parameter[pid=KEYHASH]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->keyhash, dd->buf, sizeof (dest->keyhash)); - dest->present |= PP_KEYHASH; - return 0; - - case PID_STATUSINFO: - if (dd->bufsz < sizeof (dest->statusinfo)) - { - DDS_TRACE("plist/init_one_parameter[pid=STATUSINFO]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->statusinfo, dd->buf, sizeof (dest->statusinfo)); - dest->statusinfo = fromBE4u (dest->statusinfo); - if (NN_STRICT_P && !protocol_version_is_newer (dd->protocol_version) && - (dest->statusinfo & ~NN_STATUSINFO_STANDARDIZED)) - { - /* Spec says I may not interpret the reserved bits. But no-one - may use them in this version of the specification */ - DDS_TRACE("plist/init_one_parameter[pid=STATUSINFO,mode=STRICT,proto=%u.%u]: invalid statusinfo (0x%x)\n", - dd->protocol_version.major, dd->protocol_version.minor, dest->statusinfo); - return Q_ERR_INVALID; - } - /* Clear all bits we don't understand, then add the extended bits if present */ - dest->statusinfo &= NN_STATUSINFO_STANDARDIZED; - if (dd->bufsz >= 2 * sizeof (dest->statusinfo) && vendor_is_eclipse_or_opensplice(dd->vendorid)) - { - uint32_t statusinfox; - Q_STATIC_ASSERT_CODE (sizeof(statusinfox) == sizeof(dest->statusinfo)); - memcpy (&statusinfox, dd->buf + sizeof (dest->statusinfo), sizeof (statusinfox)); - statusinfox = fromBE4u (statusinfox); - if (statusinfox & NN_STATUSINFOX_OSPL_AUTO) - dest->statusinfo |= NN_STATUSINFO_OSPL_AUTO; - } - dest->present |= PP_STATUSINFO; - return 0; - - case PID_COHERENT_SET: - if (dd->bufsz < sizeof (dest->coherent_set_seqno)) - { - DDS_TRACE("plist/init_one_parameter[pid=COHERENT_SET]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_sequence_number_t *q = &dest->coherent_set_seqno; - seqno_t seqno; - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - { - q->high = bswap4 (q->high); - q->low = bswap4u (q->low); - } - seqno = fromSN(dest->coherent_set_seqno); - if (seqno <= 0 && seqno != NN_SEQUENCE_NUMBER_UNKNOWN) - { - DDS_TRACE("plist/init_one_parameter[pid=COHERENT_SET]: invalid sequence number (%" PRId64 ")\n", seqno); - return Q_ERR_INVALID; - } - dest->present |= PP_COHERENT_SET; - return 0; - } - - case PID_CONTENT_FILTER_INFO: - case PID_DIRECTED_WRITE: - case PID_ORIGINAL_WRITER_INFO: - /* FIXME */ - return 0; - - case PID_ENDPOINT_GUID: - if (NN_PEDANTIC_P && !protocol_version_is_newer (dd->protocol_version)) - { - /* ENDPOINT_GUID is not specified in the 2.1 standard, so - reject it: in (really) strict mode we do not accept - undefined things, even though we are -arguably- supposed to - ignore it. */ - DDS_TRACE("plist/init_one_parameter[pid=ENDPOINT_GUID,mode=PEDANTIC,proto=%u.%u]: undefined pid\n", - dd->protocol_version.major, dd->protocol_version.minor); - return Q_ERR_INVALID; - } - return do_guid (&dest->endpoint_guid, &dest->present, PP_ENDPOINT_GUID, valid_endpoint_guid, dd); - - case PID_PRISMTECH_ENDPOINT_GUID: /* case PID_RTI_TYPECODE: */ - if (vendor_is_eclipse_or_prismtech (dd->vendorid)) - { - /* PrismTech specific variant of ENDPOINT_GUID, for strict compliancy */ - return do_guid (&dest->endpoint_guid, &dest->present, PP_ENDPOINT_GUID, valid_endpoint_guid, dd); - } - else if (vendor_is_rti (dd->vendorid)) - { - /* For RTI it is a typecode */ - return do_blob (&dest->qos.rti_typecode, &dest->qos.present, &dest->qos.aliased, qwanted, QP_RTI_TYPECODE, dd); - - } - else - { - return 0; - } - - - case PID_PRISMTECH_PARTICIPANT_VERSION_INFO: - return do_prismtech_participant_version_info(&dest->prismtech_participant_version_info, &dest->present, &dest->aliased, dd); - - case PID_PRISMTECH_SUBSCRIPTION_KEYS: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_subscription_keys_qospolicy (&dest->qos.subscription_keys, &dest->qos.present, &dest->qos.aliased, QP_PRISMTECH_SUBSCRIPTION_KEYS, dd); - - case PID_PRISMTECH_READER_LIFESPAN: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_reader_lifespan_qospolicy (&dest->qos.reader_lifespan, &dest->qos.present, QP_PRISMTECH_READER_LIFESPAN, dd); - - - case PID_PRISMTECH_ENTITY_FACTORY: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_entity_factory_qospolicy (&dest->qos.entity_factory, &dest->qos.present, QP_PRISMTECH_ENTITY_FACTORY, dd); - - case PID_PRISMTECH_NODE_NAME: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->node_name, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_NODE_NAME, dd); - - case PID_PRISMTECH_EXEC_NAME: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->exec_name, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_EXEC_NAME, dd); - - case PID_PRISMTECH_SERVICE_TYPE: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz < sizeof (dest->service_type)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_SERVICE_TYPE]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->service_type, dd->buf, sizeof (dest->service_type)); - if (dd->bswap) - dest->service_type = bswap4u (dest->service_type); - dest->present |= PP_PRISMTECH_SERVICE_TYPE; - return 0; - - case PID_PRISMTECH_PROCESS_ID: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz < sizeof (dest->process_id)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_PROCESS_ID]: buffer too small\n"); - return Q_ERR_INVALID; - } - memcpy (&dest->process_id, dd->buf, sizeof (dest->process_id)); - if (dd->bswap) - dest->process_id = bswap4u (dest->process_id); - dest->present |= PP_PRISMTECH_PROCESS_ID; - return 0; - - case PID_PRISMTECH_TYPE_DESCRIPTION: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->type_description, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_TYPE_DESCRIPTION, dd); - - case PID_PRISMTECH_EOTINFO: - if (!vendor_is_eclipse_or_opensplice (dd->vendorid)) - return 0; - else if (dd->bufsz < 2*sizeof (uint32_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_EOTINFO]: buffer too small (1)\n"); - return Q_ERR_INVALID; - } - else - { - nn_prismtech_eotinfo_t *q = &dest->eotinfo; - uint32_t i; - q->transactionId = ((const uint32_t *) dd->buf)[0]; - q->n = ((const uint32_t *) dd->buf)[1]; - if (dd->bswap) - { - q->n = bswap4u (q->n); - q->transactionId = bswap4u (q->transactionId); - } - if (q->n > (dd->bufsz - 2*sizeof (uint32_t)) / sizeof (nn_prismtech_eotgroup_tid_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_EOTINFO]: buffer too small (2)\n"); - return Q_ERR_INVALID; - } - if (q->n == 0) - q->tids = NULL; - else - q->tids = (nn_prismtech_eotgroup_tid_t *) (dd->buf + 2*sizeof (uint32_t)); - for (i = 0; i < q->n; i++) - { - q->tids[i].writer_entityid.u = fromBE4u (q->tids[i].writer_entityid.u); - if (dd->bswap) - q->tids[i].transactionId = bswap4u (q->tids[i].transactionId); - } - dest->present |= PP_PRISMTECH_EOTINFO; - dest->aliased |= PP_PRISMTECH_EOTINFO; - if (dds_get_log_mask() & DDS_LC_PLIST) - { - DDS_LOG(DDS_LC_PLIST, "eotinfo: txn %"PRIu32" {", q->transactionId); - for (i = 0; i < q->n; i++) - DDS_LOG(DDS_LC_PLIST, " %"PRIx32":%"PRIu32, q->tids[i].writer_entityid.u, q->tids[i].transactionId); - DDS_LOG(DDS_LC_PLIST, " }\n"); - } - return 0; - } - -#ifdef DDSI_INCLUDE_SSM - case PID_READER_FAVOURS_SSM: - if (dd->bufsz < sizeof (dest->reader_favours_ssm)) - { - DDS_TRACE("plist/init_one_parameter[pid=READER_FAVOURS_SSM]: buffer too small\n"); - return Q_ERR_INVALID; - } - else - { - nn_reader_favours_ssm_t *rfssm = &dest->reader_favours_ssm; - memcpy (rfssm, dd->buf, sizeof (*rfssm)); - if (dd->bswap) - rfssm->state = bswap4u (rfssm->state); - if (rfssm->state != 0 && rfssm->state != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=READER_FAVOURS_SSM]: unsupported value: %u\n", rfssm->state); - rfssm->state = 0; - } - dest->present |= PP_READER_FAVOURS_SSM; - return 0; - } -#endif - - /* Deprecated ones (used by RTI, but not relevant to DDSI) */ - case PID_PERSISTENCE: - case PID_TYPE_CHECKSUM: - case PID_TYPE2_NAME: - case PID_TYPE2_CHECKSUM: - case PID_EXPECTS_ACK: - case PID_MANAGER_KEY: - case PID_SEND_QUEUE_SIZE: - case PID_RELIABILITY_ENABLED: - case PID_VARGAPPS_SEQUENCE_NUMBER_LAST: - case PID_RECV_QUEUE_SIZE: - case PID_RELIABILITY_OFFERED: - return 0; - - default: - /* Ignore unrecognised parameters (disregarding vendor-specific - ones, of course) if the protocol version is newer than the - one implemented, and fail it if it isn't. I know all RFPs say - to be tolerant in what is accepted, but that is where the - bugs & the buffer overflows originate! */ - if (pid & PID_UNRECOGNIZED_INCOMPATIBLE_FLAG) { - dest->present |= PP_INCOMPATIBLE; - return Q_ERR_INCOMPATIBLE; - } else if (pid & PID_VENDORSPECIFIC_FLAG) { - return 0; - } else if (!protocol_version_is_newer (dd->protocol_version) && NN_STRICT_P) { - DDS_TRACE("plist/init_one_parameter[pid=%u,mode=STRICT,proto=%u.%u]: undefined paramter id\n", - pid, dd->protocol_version.major, dd->protocol_version.minor); - return Q_ERR_INVALID; - } else { - return 0; - } } - assert (0); - DDS_TRACE("plist/init_one_parameter: can't happen\n"); - return Q_ERR_INVALID; -} + const struct piddesc_index *index; + if (!(pid & PID_VENDORSPECIFIC_FLAG)) + index = &piddesc_vendor_index[0]; + else if (dd->vendorid.id[0] != 1 || dd->vendorid.id[1] < 1) + return return_unrecognized_pid (plist, pid); + else if (dd->vendorid.id[1] >= sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0])) + return return_unrecognized_pid (plist, pid); + else if (piddesc_vendor_index[dd->vendorid.id[1]].index == NULL) + return return_unrecognized_pid (plist, pid); + else + index = &piddesc_vendor_index[dd->vendorid.id[1]]; -static void default_resource_limits (nn_resource_limits_qospolicy_t *q) -{ - q->max_instances = NN_DDS_LENGTH_UNLIMITED; - q->max_samples = NN_DDS_LENGTH_UNLIMITED; - q->max_samples_per_instance = NN_DDS_LENGTH_UNLIMITED; -} - -static void default_history (nn_history_qospolicy_t *q) -{ - q->kind = NN_KEEP_LAST_HISTORY_QOS; - q->depth = 1; -} - -void nn_plist_init_empty (nn_plist_t *dest) -{ -#ifndef NDEBUG - memset (dest, 0, sizeof (*dest)); -#endif - dest->present = dest->aliased = 0; - nn_xqos_init_empty (&dest->qos); -} - -void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b) -{ - /* Adds entries's from B to A (duplicating memory) (only those not - present in A, obviously) */ - - /* Simple ones (that don't need memory): everything but topic, type, - partition, {group,topic|user} data */ -#define CQ(fl_, name_) do { \ - if (!(a->present & PP_##fl_) && (b->present & PP_##fl_)) { \ - a->name_ = b->name_; \ - a->present |= PP_##fl_; \ - } \ - } while (0) - CQ (PROTOCOL_VERSION, protocol_version); - CQ (VENDORID, vendorid); - CQ (EXPECTS_INLINE_QOS, expects_inline_qos); - CQ (PARTICIPANT_MANUAL_LIVELINESS_COUNT, participant_manual_liveliness_count); - CQ (PARTICIPANT_BUILTIN_ENDPOINTS, participant_builtin_endpoints); - CQ (PARTICIPANT_LEASE_DURATION, participant_lease_duration); - CQ (PARTICIPANT_GUID, participant_guid); - CQ (ENDPOINT_GUID, endpoint_guid); - CQ (GROUP_GUID, group_guid); - CQ (BUILTIN_ENDPOINT_SET, builtin_endpoint_set); - CQ (KEYHASH, keyhash); - CQ (STATUSINFO, statusinfo); - CQ (COHERENT_SET, coherent_set_seqno); - CQ (PRISMTECH_SERVICE_TYPE, service_type); - CQ (PRISMTECH_PROCESS_ID, process_id); - CQ (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set); -#ifdef DDSI_INCLUDE_SSM - CQ (READER_FAVOURS_SSM, reader_favours_ssm); -#endif -#undef CQ - - /* For allocated ones it is Not strictly necessary to use tmp, as - a->name_ may only be interpreted if the present flag is set, but - this keeps a clean on failure and may thereby save us from a - nasty surprise. */ -#define CQ(fl_, name_, type_, tmp_type_) do { \ - if (!(a->present & PP_##fl_) && (b->present & PP_##fl_)) { \ - tmp_type_ tmp = b->name_; \ - unalias_##type_ (&tmp, -1); \ - a->name_ = tmp; \ - a->present |= PP_##fl_; \ - } \ - } while (0) - CQ (UNICAST_LOCATOR, unicast_locators, locators, nn_locators_t); - CQ (MULTICAST_LOCATOR, unicast_locators, locators, nn_locators_t); - CQ (DEFAULT_UNICAST_LOCATOR, default_unicast_locators, locators, nn_locators_t); - CQ (DEFAULT_MULTICAST_LOCATOR, default_multicast_locators, locators, nn_locators_t); - CQ (METATRAFFIC_UNICAST_LOCATOR, metatraffic_unicast_locators, locators, nn_locators_t); - CQ (METATRAFFIC_MULTICAST_LOCATOR, metatraffic_multicast_locators, locators, nn_locators_t); - CQ (ENTITY_NAME, entity_name, string, char *); - CQ (PRISMTECH_NODE_NAME, node_name, string, char *); - CQ (PRISMTECH_EXEC_NAME, exec_name, string, char *); - CQ (PRISMTECH_TYPE_DESCRIPTION, type_description, string, char *); - CQ (PRISMTECH_EOTINFO, eotinfo, eotinfo, nn_prismtech_eotinfo_t); -#undef CQ - if (!(a->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) && - (b->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO)) + const struct piddesc *entry; + if (pid_without_flags (pid) > index->index_max || (entry = index->index[pid_without_flags (pid)]) == NULL) + return return_unrecognized_pid (plist, pid); + assert (pid_without_flags (pid) == pid_without_flags (entry->pid)); + if (pid != entry->pid) { - nn_prismtech_participant_version_info_t tmp = b->prismtech_participant_version_info; - unalias_string (&tmp.internals, -1); - a->prismtech_participant_version_info = tmp; - a->present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; + DDS_CERROR (logcfg, "error processing parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" mapped to pid %"PRIx16"\n", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->pid); + return return_unrecognized_pid (plist, pid); + } + assert (pid != PID_PAD); + + struct flagset flagset; + if (entry->flags & PDF_QOS) + { + flagset.present = &plist->qos.present; + flagset.aliased = &plist->qos.aliased; + flagset.wanted = qwanted; + } + else + { + flagset.present = &plist->present; + flagset.aliased = &plist->aliased; + flagset.wanted = pwanted; } - nn_xqos_mergein_missing (&a->qos, &b->qos); + /* Disallow multiple copies of the same parameter unless explicit allowed + (which is needed for handling locators). String sequences will leak + memory if deserialized repeatedly */ + if ((*flagset.present & entry->present_flag) && !(entry->flags & PDF_ALLOWMULTI)) + { + DDS_CWARNING (logcfg, "invalid parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" (%s) multiply defined\n", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->name); + return DDS_RETCODE_BAD_PARAMETER; + } + if (!(flagset.wanted & entry->present_flag)) + { + /* skip don't cares -- the point of skipping them is performance and + avoiding unnecessary allocations, so validating them would be silly */ + return 0; + } + + /* String sequences are not allowed in parameters that may occur multiple + times because they will leak the arrays of pointers. Fixing this is + not worth the bother as long as such parameters don't exist. */ + dds_return_t ret; + void * const dst = (char *) plist + entry->plist_offset; + size_t dstoff = 0; + size_t srcoff = 0; + if (entry->flags & PDF_FUNCTION) + ret = entry->op.f.deser (dst, &dstoff, &flagset, entry->present_flag, dd, &srcoff); + else + ret = deser_generic (dst, &dstoff, &flagset, entry->present_flag, dd, &srcoff, entry->op.desc); + if (ret == 0 && entry->deser_validate_xform) + ret = entry->deser_validate_xform (dst, dd); + if (ret < 0) + { + DDS_CWARNING (logcfg, "invalid parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" (%s) invalid, input = ", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->name); + log_octetseq (DDS_LC_WARNING, logcfg, (uint32_t) dd->bufsz, dd->buf); + DDS_CWARNING (logcfg, "\n"); + } + return ret; +} + +void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b, uint64_t pmask, uint64_t qmask) +{ + plist_or_xqos_mergein_missing (a, b, 0, pmask, qmask); +} + +void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask) +{ + plist_or_xqos_mergein_missing (a, b, offsetof (nn_plist_t, qos), 0, mask); } void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src) { nn_plist_init_empty (dst); - nn_plist_mergein_missing (dst, src); + nn_plist_mergein_missing (dst, src, ~(uint64_t)0, ~(uint64_t)0); } nn_plist_t *nn_plist_dup (const nn_plist_t *src) @@ -2299,28 +2012,45 @@ nn_plist_t *nn_plist_dup (const nn_plist_t *src) return dst; } -static int final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid) +void nn_plist_init_empty (nn_plist_t *dest) { +#ifndef NDEBUG + memset (dest, 0, sizeof (*dest)); +#endif + dest->present = dest->aliased = 0; + nn_xqos_init_empty (&dest->qos); +} + +static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero, bool strict) +{ + /* input is const, but we need to validate the combination of + history & resource limits: so use a copy of those two policies */ + dds_history_qospolicy_t tmphist = { + .kind = DDS_HISTORY_KEEP_LAST, + .depth = 1 + }; + dds_resource_limits_qospolicy_t tmpreslim = { + .max_samples = DDS_LENGTH_UNLIMITED, + .max_instances = DDS_LENGTH_UNLIMITED, + .max_samples_per_instance = DDS_LENGTH_UNLIMITED + }; + dds_return_t res; + /* Resource limits & history are related, so if only one is given, set the other to the default, claim it has been provided & validate the combination. They can't be changed afterward, so this is a reasonable interpretation. */ - if ((dest->qos.present & QP_HISTORY) && !(dest->qos.present & QP_RESOURCE_LIMITS)) + if (dest->present & QP_HISTORY) + tmphist = dest->history; + if (dest->present & QP_RESOURCE_LIMITS) + tmpreslim = dest->resource_limits; + if ((res = validate_history_and_resource_limits (&tmphist, &tmpreslim)) < 0) + return res; + + if ((dest->present & QP_DEADLINE) && (dest->present & QP_TIME_BASED_FILTER)) { - default_resource_limits (&dest->qos.resource_limits); - dest->qos.present |= QP_RESOURCE_LIMITS; - } - if (!(dest->qos.present & QP_HISTORY) && (dest->qos.present & QP_RESOURCE_LIMITS)) - { - default_history (&dest->qos.history); - dest->qos.present |= QP_HISTORY; - } - if (dest->qos.present & (QP_HISTORY | QP_RESOURCE_LIMITS)) - { - int res; - assert ((dest->qos.present & (QP_HISTORY | QP_RESOURCE_LIMITS)) == (QP_HISTORY | QP_RESOURCE_LIMITS)); - if ((res = validate_history_and_resource_limits (&dest->qos.history, &dest->qos.resource_limits)) < 0) - return res; + if (dest->deadline.deadline < dest->time_based_filter.minimum_separation) + return DDS_RETCODE_INCONSISTENT_POLICY; } /* Durability service is sort-of accepted if all zeros, but only @@ -2329,50 +2059,51 @@ static int final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_ve parsed we know the setting of the durability QoS (the default is always VOLATILE), and hence we can verify that the setting is valid or delete it if irrelevant. */ - if (dest->qos.present & QP_DURABILITY_SERVICE) + if (dursvc_accepted_allzero) + *dursvc_accepted_allzero = false; + if (dest->present & QP_DURABILITY_SERVICE) { - const nn_durability_kind_t durkind = (dest->qos.present & QP_DURABILITY) ? dest->qos.durability.kind : NN_VOLATILE_DURABILITY_QOS; + const dds_durability_kind_t durkind = (dest->present & QP_DURABILITY) ? dest->durability.kind : DDS_DURABILITY_VOLATILE; bool acceptzero; + bool check_dursvc = true; /* Use a somewhat convoluted rule to decide whether or not to "accept" an all-zero durability service setting, to find a reasonable mix of strictness and compatibility */ - if (protocol_version_is_newer (protocol_version)) + if (dursvc_accepted_allzero == NULL) + acceptzero = false; + else if (protocol_version_is_newer (protocol_version)) acceptzero = true; - else if (NN_STRICT_P) + else if (strict) acceptzero = vendor_is_twinoaks (vendorid); else acceptzero = !vendor_is_eclipse (vendorid); switch (durkind) { - case NN_VOLATILE_DURABILITY_QOS: - case NN_TRANSIENT_LOCAL_DURABILITY_QOS: - /* pretend we never saw it if it is all zero */ - if (acceptzero && durability_service_qospolicy_allzero (&dest->qos.durability_service)) - dest->qos.present &= ~QP_DURABILITY_SERVICE; + case DDS_DURABILITY_VOLATILE: + case DDS_DURABILITY_TRANSIENT_LOCAL: + /* let caller now if we accepted all-zero: our input is const and we can't patch it out */ + if (acceptzero && durability_service_qospolicy_allzero (&dest->durability_service) && dursvc_accepted_allzero) + { + *dursvc_accepted_allzero = true; + check_dursvc = false; + } break; - case NN_TRANSIENT_DURABILITY_QOS: - case NN_PERSISTENT_DURABILITY_QOS: + case DDS_DURABILITY_TRANSIENT: + case DDS_DURABILITY_PERSISTENT: break; } - /* if it is still present, it must be valid */ - if (dest->qos.present & QP_DURABILITY_SERVICE) - { - int res; - if ((res = validate_durability_service_qospolicy (&dest->qos.durability_service)) < 0) - return res; - } + if (check_dursvc && (res = validate_durability_service_qospolicy_acceptzero (&dest->durability_service, false)) < 0) + return res; } return 0; } -int nn_plist_init_frommsg -( - nn_plist_t *dest, - char **nextafterplist, - uint64_t pwanted, - uint64_t qwanted, - const nn_plist_src_t *src -) +static dds_return_t final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero, bool strict) +{ + return final_validation_qos (&dest->qos, protocol_version, vendorid, dursvc_accepted_allzero, strict); +} + +dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const nn_plist_src_t *src) { const unsigned char *pl; struct dd dd; @@ -2386,6 +2117,7 @@ int nn_plist_init_frommsg *nextafterplist = NULL; dd.protocol_version = src->protocol_version; dd.vendorid = src->vendorid; + dd.factory = src->factory; switch (src->encoding) { case PL_CDR_LE: @@ -2403,73 +2135,77 @@ int nn_plist_init_frommsg #endif break; default: - DDS_WARNING ("plist(vendor %u.%u): unknown encoding (%d)\n", - src->vendorid.id[0], src->vendorid.id[1], src->encoding); - return Q_ERR_INVALID; + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): unknown encoding (%d)\n", + src->vendorid.id[0], src->vendorid.id[1], src->encoding); + return DDS_RETCODE_BAD_PARAMETER; } nn_plist_init_empty (dest); - dest->unalias_needs_bswap = dd.bswap; dest_tmp.present = 0; - DDS_LOG(DDS_LC_PLIST, "NN_PLIST_INIT (bswap %d)\n", dd.bswap); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "NN_PLIST_INIT (bswap %d)\n", dd.bswap); pl = src->buf; while (pl + sizeof (nn_parameter_t) <= src->buf + src->bufsz) { nn_parameter_t *par = (nn_parameter_t *) pl; nn_parameterid_t pid; - unsigned short length; - int res; + uint16_t length; + dds_return_t res; /* swapping header partially based on wireshark dissector output, partially on intuition, and in a small part based on the spec */ pid = (nn_parameterid_t) (dd.bswap ? bswap2u (par->parameterid) : par->parameterid); - length = (unsigned short) (dd.bswap ? bswap2u (par->length) : par->length); + length = (uint16_t) (dd.bswap ? bswap2u (par->length) : par->length); if (pid == PID_SENTINEL) { /* Sentinel terminates list, the length is ignored, DDSI 9.4.2.11. */ - DDS_LOG(DDS_LC_PLIST, "%4x PID %x\n", (unsigned) (pl - src->buf), pid); - if ((res = final_validation (dest, src->protocol_version, src->vendorid)) < 0) + bool dursvc_accepted_allzero; + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "%4"PRIx32" PID %"PRIx16"\n", (uint32_t) (pl - src->buf), pid); + if ((res = final_validation (dest, src->protocol_version, src->vendorid, &dursvc_accepted_allzero, src->strict)) < 0) { nn_plist_fini (dest); - return Q_ERR_INVALID; + return res; } else { + /* If we accepted an all-zero durability service, that's awfully friendly of ours, + but we'll pretend we never saw it */ + if (dursvc_accepted_allzero) + dest->qos.present &= ~QP_DURABILITY_SERVICE; pl += sizeof (*par); if (nextafterplist) *nextafterplist = (char *) pl; return 0; } } - if (length > src->bufsz - sizeof (*par) - (unsigned) (pl - src->buf)) + if (length > src->bufsz - sizeof (*par) - (uint32_t) (pl - src->buf)) { - DDS_WARNING("plist(vendor %u.%u): parameter length %u out of bounds\n", - src->vendorid.id[0], src->vendorid.id[1], length); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): parameter length %"PRIu16" out of bounds\n", + src->vendorid.id[0], src->vendorid.id[1], length); nn_plist_fini (dest); - return Q_ERR_INVALID; + return DDS_RETCODE_BAD_PARAMETER; } if ((length % 4) != 0) /* DDSI 9.4.2.11 */ { - DDS_WARNING("plist(vendor %u.%u): parameter length %u mod 4 != 0\n", - src->vendorid.id[0], src->vendorid.id[1], length); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): parameter length %"PRIu16" mod 4 != 0\n", + src->vendorid.id[0], src->vendorid.id[1], length); nn_plist_fini (dest); - return Q_ERR_INVALID; + return DDS_RETCODE_BAD_PARAMETER; } - if (dds_get_log_mask() & DDS_LC_PLIST) + if (src->logconfig->c.mask & DDS_LC_PLIST) { - DDS_LOG(DDS_LC_PLIST, "%4x PID %x len %u ", (unsigned) (pl - src->buf), pid, length); - log_octetseq(DDS_LC_PLIST, length, (const unsigned char *) (par + 1)); - DDS_LOG(DDS_LC_PLIST, "\n"); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "%4"PRIx32" PID %"PRIx16" len %"PRIu16" ", (uint32_t) (pl - src->buf), pid, length); + log_octetseq (DDS_LC_PLIST, src->logconfig, length, (const unsigned char *) (par + 1)); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "\n"); } dd.buf = (const unsigned char *) (par + 1); dd.bufsz = length; - if ((res = init_one_parameter (dest, &dest_tmp, pwanted, qwanted, pid, &dd)) < 0) + if ((res = init_one_parameter (dest, &dest_tmp, pwanted, qwanted, pid, &dd, src->factory, src->logconfig)) < 0) { /* make sure we print a trace message on error */ - DDS_TRACE("plist(vendor %u.%u): failed at pid=%u\n", src->vendorid.id[0], src->vendorid.id[1], pid); + DDS_CTRACE (src->logconfig, "plist(vendor %u.%u): failed at pid=%"PRIx16"\n", src->vendorid.id[0], src->vendorid.id[1], pid); nn_plist_fini (dest); return res; } @@ -2477,10 +2213,10 @@ int nn_plist_init_frommsg } /* If we get here, that means we reached the end of the message without encountering a sentinel. That is an error */ - DDS_WARNING("plist(vendor %u.%u): invalid parameter list: sentinel missing\n", - src->vendorid.id[0], src->vendorid.id[1]); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): invalid parameter list: sentinel missing\n", + src->vendorid.id[0], src->vendorid.id[1]); nn_plist_fini (dest); - return Q_ERR_INVALID; + return DDS_RETCODE_BAD_PARAMETER; } const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid) @@ -2526,11 +2262,11 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn #endif break; default: - DDS_WARNING("plist(vendor %u.%u): quickscan: unknown encoding (%d)\n", - src->vendorid.id[0], src->vendorid.id[1], src->encoding); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): quickscan: unknown encoding (%d)\n", + src->vendorid.id[0], src->vendorid.id[1], src->encoding); return NULL; } - DDS_LOG(DDS_LC_PLIST, "NN_PLIST_QUICKSCAN (bswap %d)\n", dest->bswap); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "NN_PLIST_QUICKSCAN (bswap %d)\n", dest->bswap); pl = src->buf; while (pl + sizeof (nn_parameter_t) <= src->buf + src->bufsz) { @@ -2544,14 +2280,14 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn return (unsigned char *) pl; if (length > src->bufsz - (size_t)(pl - src->buf)) { - DDS_WARNING("plist(vendor %u.%u): quickscan: parameter length %u out of bounds\n", - src->vendorid.id[0], src->vendorid.id[1], length); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): quickscan: parameter length %"PRIu16" out of bounds\n", + src->vendorid.id[0], src->vendorid.id[1], length); return NULL; } if ((length % 4) != 0) /* DDSI 9.4.2.11 */ { - DDS_WARNING("plist(vendor %u.%u): quickscan: parameter length %u mod 4 != 0\n", - src->vendorid.id[0], src->vendorid.id[1], length); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): quickscan: parameter length %"PRIu16" mod 4 != 0\n", + src->vendorid.id[0], src->vendorid.id[1], length); return NULL; } switch (pid) @@ -2561,24 +2297,24 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn case PID_STATUSINFO: if (length < 4) { - DDS_TRACE("plist(vendor %u.%u): quickscan(PID_STATUSINFO): buffer too small\n", - src->vendorid.id[0], src->vendorid.id[1]); + DDS_CTRACE (src->logconfig, "plist(vendor %u.%u): quickscan(PID_STATUSINFO): buffer too small\n", + src->vendorid.id[0], src->vendorid.id[1]); return NULL; } else { - unsigned stinfo = fromBE4u (*((unsigned *) pl)); - unsigned stinfox = (length < 8 || !vendor_is_eclipse_or_opensplice(src->vendorid)) ? 0 : fromBE4u (*((unsigned *) pl + 1)); -#if (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER) != 3 -#error "expected dispose/unregister to be in lowest 2 bits" -#endif + /* can only represent 2 LSBs of statusinfo in "dest", so if others are set, + mark it as a "complex_qos" and accept the hit of parsing the data completely. */ + uint32_t stinfo = fromBE4u (*((uint32_t *) pl)); dest->statusinfo = stinfo & 3u; - if ((stinfo & ~3u) || stinfox) + if ((stinfo & ~3u)) dest->complex_qos = 1; } break; + case PID_KEYHASH: + break; default: - DDS_LOG(DDS_LC_PLIST, "(pid=%x complex_qos=1)", pid); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "(pid=%"PRIx16" complex_qos=1)", pid); dest->complex_qos = 1; break; } @@ -2586,13 +2322,12 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn } /* If we get here, that means we reached the end of the message without encountering a sentinel. That is an error */ - DDS_WARNING("plist(vendor %u.%u): quickscan: invalid parameter list: sentinel missing\n", - src->vendorid.id[0], src->vendorid.id[1]); + DDS_CWARNING (src->logconfig, "plist(vendor %u.%u): quickscan: invalid parameter list: sentinel missing\n", + src->vendorid.id[0], src->vendorid.id[1]); return NULL; } - -void nn_xqos_init_empty (nn_xqos_t *dest) +void nn_xqos_init_empty (dds_qos_t *dest) { #ifndef NDEBUG memset (dest, 0, sizeof (*dest)); @@ -2600,89 +2335,100 @@ void nn_xqos_init_empty (nn_xqos_t *dest) dest->present = dest->aliased = 0; } -int nn_plist_init_default_participant (nn_plist_t *plist) +void nn_plist_init_default_participant (nn_plist_t *plist) { nn_plist_init_empty (plist); + plist->qos.present |= QP_PRISMTECH_ENTITY_FACTORY; plist->qos.entity_factory.autoenable_created_entities = 0; - return 0; + + plist->qos.present |= QP_USER_DATA; + plist->qos.user_data.length = 0; + plist->qos.user_data.value = NULL; } -static void xqos_init_default_common (nn_xqos_t *xqos) +static void xqos_init_default_common (dds_qos_t *xqos) { nn_xqos_init_empty (xqos); - xqos->present |= QP_PARTITION; - xqos->partition.n = 0; - xqos->partition.strs = NULL; - xqos->present |= QP_PRESENTATION; - xqos->presentation.access_scope = NN_INSTANCE_PRESENTATION_QOS; + xqos->presentation.access_scope = DDS_PRESENTATION_INSTANCE; xqos->presentation.coherent_access = 0; xqos->presentation.ordered_access = 0; xqos->present |= QP_DURABILITY; - xqos->durability.kind = NN_VOLATILE_DURABILITY_QOS; + xqos->durability.kind = DDS_DURABILITY_VOLATILE; xqos->present |= QP_DEADLINE; - xqos->deadline.deadline = nn_to_ddsi_duration (T_NEVER); + xqos->deadline.deadline = T_NEVER; xqos->present |= QP_LATENCY_BUDGET; - xqos->latency_budget.duration = nn_to_ddsi_duration (0); + xqos->latency_budget.duration = 0; xqos->present |= QP_LIVELINESS; - xqos->liveliness.kind = NN_AUTOMATIC_LIVELINESS_QOS; - xqos->liveliness.lease_duration = nn_to_ddsi_duration (T_NEVER); + xqos->liveliness.kind = DDS_LIVELINESS_AUTOMATIC; + xqos->liveliness.lease_duration = T_NEVER; xqos->present |= QP_DESTINATION_ORDER; - xqos->destination_order.kind = NN_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS; + xqos->destination_order.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP; xqos->present |= QP_HISTORY; - xqos->history.kind = NN_KEEP_LAST_HISTORY_QOS; + xqos->history.kind = DDS_HISTORY_KEEP_LAST; xqos->history.depth = 1; xqos->present |= QP_RESOURCE_LIMITS; - xqos->resource_limits.max_samples = NN_DDS_LENGTH_UNLIMITED; - xqos->resource_limits.max_instances = NN_DDS_LENGTH_UNLIMITED; - xqos->resource_limits.max_samples_per_instance = NN_DDS_LENGTH_UNLIMITED; + xqos->resource_limits.max_samples = DDS_LENGTH_UNLIMITED; + xqos->resource_limits.max_instances = DDS_LENGTH_UNLIMITED; + xqos->resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; xqos->present |= QP_TRANSPORT_PRIORITY; xqos->transport_priority.value = 0; xqos->present |= QP_OWNERSHIP; - xqos->ownership.kind = NN_SHARED_OWNERSHIP_QOS; - - xqos->present |= QP_PRISMTECH_RELAXED_QOS_MATCHING; - xqos->relaxed_qos_matching.value = 0; - - xqos->present |= QP_PRISMTECH_SYNCHRONOUS_ENDPOINT; - xqos->synchronous_endpoint.value = 0; + xqos->ownership.kind = DDS_OWNERSHIP_SHARED; xqos->present |= QP_CYCLONE_IGNORELOCAL; - xqos->ignorelocal.value = NN_NONE_IGNORELOCAL_QOS; + xqos->ignorelocal.value = DDS_IGNORELOCAL_NONE; } -void nn_xqos_init_default_reader (nn_xqos_t *xqos) +static void nn_xqos_init_default_endpoint (dds_qos_t *xqos) { xqos_init_default_common (xqos); + xqos->present |= QP_TOPIC_DATA; + xqos->topic_data.length = 0; + xqos->topic_data.value = NULL; + + xqos->present |= QP_GROUP_DATA; + xqos->group_data.length = 0; + xqos->group_data.value = NULL; + + xqos->present |= QP_USER_DATA; + xqos->user_data.length = 0; + xqos->user_data.value = NULL; + + xqos->present |= QP_PARTITION; + xqos->partition.n = 0; + xqos->partition.strs = NULL; +} + +void nn_xqos_init_default_reader (dds_qos_t *xqos) +{ + nn_xqos_init_default_endpoint (xqos); + xqos->present |= QP_RELIABILITY; - xqos->reliability.kind = NN_BEST_EFFORT_RELIABILITY_QOS; + xqos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT; xqos->present |= QP_TIME_BASED_FILTER; - xqos->time_based_filter.minimum_separation = nn_to_ddsi_duration (0); + xqos->time_based_filter.minimum_separation = 0; xqos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - xqos->reader_data_lifecycle.autopurge_nowriter_samples_delay = nn_to_ddsi_duration (T_NEVER); - xqos->reader_data_lifecycle.autopurge_disposed_samples_delay = nn_to_ddsi_duration (T_NEVER); - xqos->reader_data_lifecycle.autopurge_dispose_all = 0; - xqos->reader_data_lifecycle.enable_invalid_samples = 1; - xqos->reader_data_lifecycle.invalid_sample_visibility = NN_MINIMUM_INVALID_SAMPLE_VISIBILITY_QOS; + xqos->reader_data_lifecycle.autopurge_nowriter_samples_delay = T_NEVER; + xqos->reader_data_lifecycle.autopurge_disposed_samples_delay = T_NEVER; xqos->present |= QP_PRISMTECH_READER_LIFESPAN; xqos->reader_lifespan.use_lifespan = 0; - xqos->reader_lifespan.duration = nn_to_ddsi_duration (T_NEVER); - + xqos->reader_lifespan.duration = T_NEVER; xqos->present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; xqos->subscription_keys.use_key_list = 0; @@ -2690,21 +2436,21 @@ void nn_xqos_init_default_reader (nn_xqos_t *xqos) xqos->subscription_keys.key_list.strs = NULL; } -void nn_xqos_init_default_writer (nn_xqos_t *xqos) +void nn_xqos_init_default_writer (dds_qos_t *xqos) { - xqos_init_default_common (xqos); + nn_xqos_init_default_endpoint (xqos); xqos->present |= QP_DURABILITY_SERVICE; - xqos->durability_service.service_cleanup_delay = nn_to_ddsi_duration (0); - xqos->durability_service.history.kind = NN_KEEP_LAST_HISTORY_QOS; + xqos->durability_service.service_cleanup_delay = 0; + xqos->durability_service.history.kind = DDS_HISTORY_KEEP_LAST; xqos->durability_service.history.depth = 1; - xqos->durability_service.resource_limits.max_samples = NN_DDS_LENGTH_UNLIMITED; - xqos->durability_service.resource_limits.max_instances = NN_DDS_LENGTH_UNLIMITED; - xqos->durability_service.resource_limits.max_samples_per_instance = NN_DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_samples = DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_instances = DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; xqos->present |= QP_RELIABILITY; - xqos->reliability.kind = NN_RELIABLE_RELIABILITY_QOS; - xqos->reliability.max_blocking_time = nn_to_ddsi_duration (100 * T_MILLISECOND); + xqos->reliability.kind = DDS_RELIABILITY_RELIABLE; + xqos->reliability.max_blocking_time = 100 * T_MILLISECOND; xqos->present |= QP_OWNERSHIP_STRENGTH; xqos->ownership_strength.value = 0; @@ -2713,41 +2459,39 @@ void nn_xqos_init_default_writer (nn_xqos_t *xqos) xqos->transport_priority.value = 0; xqos->present |= QP_LIFESPAN; - xqos->lifespan.duration = nn_to_ddsi_duration (T_NEVER); + xqos->lifespan.duration = T_NEVER; xqos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; xqos->writer_data_lifecycle.autodispose_unregistered_instances = 1; - xqos->writer_data_lifecycle.autounregister_instance_delay = nn_to_ddsi_duration (T_NEVER); - xqos->writer_data_lifecycle.autopurge_suspended_samples_delay = nn_to_ddsi_duration (T_NEVER); } -void nn_xqos_init_default_writer_noautodispose (nn_xqos_t *xqos) +void nn_xqos_init_default_writer_noautodispose (dds_qos_t *xqos) { nn_xqos_init_default_writer (xqos); xqos->writer_data_lifecycle.autodispose_unregistered_instances = 0; } -void nn_xqos_init_default_topic (nn_xqos_t *xqos) +void nn_xqos_init_default_topic (dds_qos_t *xqos) { xqos_init_default_common (xqos); xqos->present |= QP_DURABILITY_SERVICE; - xqos->durability_service.service_cleanup_delay = nn_to_ddsi_duration (0); - xqos->durability_service.history.kind = NN_KEEP_LAST_HISTORY_QOS; + xqos->durability_service.service_cleanup_delay = 0; + xqos->durability_service.history.kind = DDS_HISTORY_KEEP_LAST; xqos->durability_service.history.depth = 1; - xqos->durability_service.resource_limits.max_samples = NN_DDS_LENGTH_UNLIMITED; - xqos->durability_service.resource_limits.max_instances = NN_DDS_LENGTH_UNLIMITED; - xqos->durability_service.resource_limits.max_samples_per_instance = NN_DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_samples = DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_instances = DDS_LENGTH_UNLIMITED; + xqos->durability_service.resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; xqos->present |= QP_RELIABILITY; - xqos->reliability.kind = NN_BEST_EFFORT_RELIABILITY_QOS; - xqos->reliability.max_blocking_time = nn_to_ddsi_duration (100 * T_MILLISECOND); + xqos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT; + xqos->reliability.max_blocking_time = 100 * T_MILLISECOND; xqos->present |= QP_TRANSPORT_PRIORITY; xqos->transport_priority.value = 0; xqos->present |= QP_LIFESPAN; - xqos->lifespan.duration = nn_to_ddsi_duration (T_NEVER); + xqos->lifespan.duration = T_NEVER; xqos->present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; xqos->subscription_keys.use_key_list = 0; @@ -2755,22 +2499,13 @@ void nn_xqos_init_default_topic (nn_xqos_t *xqos) xqos->subscription_keys.key_list.strs = NULL; } -void nn_xqos_init_default_subscriber (nn_xqos_t *xqos) +static void nn_xqos_init_default_publisher_subscriber (dds_qos_t *xqos) { nn_xqos_init_empty (xqos); - xqos->present |= QP_PRISMTECH_ENTITY_FACTORY; - xqos->entity_factory.autoenable_created_entities = 1; - - - xqos->present |= QP_PARTITION; - xqos->partition.n = 0; - xqos->partition.strs = NULL; -} - -void nn_xqos_init_default_publisher (nn_xqos_t *xqos) -{ - nn_xqos_init_empty (xqos); + xqos->present |= QP_GROUP_DATA; + xqos->group_data.length = 0; + xqos->group_data.value = NULL; xqos->present |= QP_PRISMTECH_ENTITY_FACTORY; xqos->entity_factory.autoenable_created_entities = 1; @@ -2780,203 +2515,57 @@ void nn_xqos_init_default_publisher (nn_xqos_t *xqos) xqos->partition.strs = NULL; } -void nn_xqos_mergein_missing (nn_xqos_t *a, const nn_xqos_t *b) +void nn_xqos_init_default_subscriber (dds_qos_t *xqos) { - /* Adds QoS's from B to A (duplicating memory) (only those not - present in A, obviously) */ - - /* Simple ones (that don't need memory): everything but topic, type, - partition, {group,topic|user} data */ -#define CQ(fl_, name_) do { \ - if (!(a->present & QP_##fl_) && (b->present & QP_##fl_)) { \ - a->name_ = b->name_; \ - a->present |= QP_##fl_; \ - } \ - } while (0) - CQ (PRESENTATION, presentation); - CQ (DURABILITY, durability); - CQ (DURABILITY_SERVICE, durability_service); - CQ (DEADLINE, deadline); - CQ (LATENCY_BUDGET, latency_budget); - CQ (LIVELINESS, liveliness); - CQ (RELIABILITY, reliability); - CQ (DESTINATION_ORDER, destination_order); - CQ (HISTORY, history); - CQ (RESOURCE_LIMITS, resource_limits); - CQ (TRANSPORT_PRIORITY, transport_priority); - CQ (LIFESPAN, lifespan); - CQ (OWNERSHIP, ownership); - CQ (OWNERSHIP_STRENGTH, ownership_strength); - CQ (TIME_BASED_FILTER, time_based_filter); - CQ (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle); - CQ (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle); - CQ (PRISMTECH_RELAXED_QOS_MATCHING, relaxed_qos_matching); - CQ (PRISMTECH_READER_LIFESPAN, reader_lifespan); - CQ (PRISMTECH_ENTITY_FACTORY, entity_factory); - CQ (PRISMTECH_SYNCHRONOUS_ENDPOINT, synchronous_endpoint); - CQ (CYCLONE_IGNORELOCAL, ignorelocal); -#undef CQ - - /* For allocated ones it is Not strictly necessary to use tmp, as - a->name_ may only be interpreted if the present flag is set, but - this keeps a clean on failure and may thereby save us from a - nasty surprise. */ -#define CQ(fl_, name_, type_, tmp_type_) do { \ - if (!(a->present & QP_##fl_) && (b->present & QP_##fl_)) { \ - tmp_type_ tmp = b->name_; \ - unalias_##type_ (&tmp, -1); \ - a->name_ = tmp; \ - a->present |= QP_##fl_; \ - } \ - } while (0) - CQ (GROUP_DATA, group_data, octetseq, nn_octetseq_t); - CQ (TOPIC_DATA, topic_data, octetseq, nn_octetseq_t); - CQ (USER_DATA, user_data, octetseq, nn_octetseq_t); - CQ (TOPIC_NAME, topic_name, string, char *); - CQ (TYPE_NAME, type_name, string, char *); - CQ (RTI_TYPECODE, rti_typecode, octetseq, nn_octetseq_t); -#undef CQ - if (!(a->present & QP_PRISMTECH_SUBSCRIPTION_KEYS) && (b->present & QP_PRISMTECH_SUBSCRIPTION_KEYS)) - { - a->subscription_keys.use_key_list = b->subscription_keys.use_key_list; - duplicate_stringseq (&a->subscription_keys.key_list, &b->subscription_keys.key_list); - a->present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; - } - if (!(a->present & QP_PARTITION) && (b->present & QP_PARTITION)) - { - duplicate_stringseq (&a->partition, &b->partition); - a->present |= QP_PARTITION; - } + nn_xqos_init_default_publisher_subscriber (xqos); } -void nn_xqos_copy (nn_xqos_t *dst, const nn_xqos_t *src) +void nn_xqos_init_default_publisher (dds_qos_t *xqos) +{ + nn_xqos_init_default_publisher_subscriber (xqos); +} + +void nn_xqos_copy (dds_qos_t *dst, const dds_qos_t *src) { nn_xqos_init_empty (dst); - nn_xqos_mergein_missing (dst, src); + nn_xqos_mergein_missing (dst, src, ~(uint64_t)0); } -void nn_xqos_unalias (nn_xqos_t *xqos) +void nn_xqos_fini (dds_qos_t *xqos) { - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_UNALIAS\n"); -#define Q(name_, func_, field_) do { \ - if ((xqos->present & QP_##name_) && (xqos->aliased & QP_##name_)) { \ - unalias_##func_ (&xqos->field_, -1); \ - xqos->aliased &= ~QP_##name_; \ - } \ - } while (0) - Q (GROUP_DATA, octetseq, group_data); - Q (TOPIC_DATA, octetseq, topic_data); - Q (USER_DATA, octetseq, user_data); - Q (TOPIC_NAME, string, topic_name); - Q (TYPE_NAME, string, type_name); - Q (PARTITION, stringseq, partition); - Q (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys_qospolicy, subscription_keys); - Q (RTI_TYPECODE, octetseq, rti_typecode); -#undef Q - assert (xqos->aliased == 0); + plist_or_xqos_fini (xqos, offsetof (nn_plist_t, qos), ~(uint64_t)0, ~(uint64_t)0); } -void nn_xqos_fini (nn_xqos_t *xqos) +void nn_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask) { - struct t { uint64_t fl; size_t off; }; - static const struct t qos_simple[] = { - { QP_GROUP_DATA, offsetof (nn_xqos_t, group_data.value) }, - { QP_TOPIC_DATA, offsetof (nn_xqos_t, topic_data.value) }, - { QP_USER_DATA, offsetof (nn_xqos_t, user_data.value) }, - { QP_TOPIC_NAME, offsetof (nn_xqos_t, topic_name) }, - { QP_TYPE_NAME, offsetof (nn_xqos_t, type_name) }, - { QP_RTI_TYPECODE, offsetof (nn_xqos_t, rti_typecode.value) } - }; - int i; - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI\n"); - for (i = 0; i < (int) (sizeof (qos_simple) / sizeof (*qos_simple)); i++) - { - if ((xqos->present & qos_simple[i].fl) && !(xqos->aliased & qos_simple[i].fl)) - { - void **pp = (void **) ((char *) xqos + qos_simple[i].off); - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", *pp); - ddsrt_free (*pp); - } - } - if (xqos->present & QP_PARTITION) - { - if (!(xqos->aliased & QP_PARTITION)) - { - free_stringseq (&xqos->partition); - } - else - { - /* until proper message buffers arrive */ - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", (void *) xqos->partition.strs); - ddsrt_free (xqos->partition.strs); - } - } - if (xqos->present & QP_PRISMTECH_SUBSCRIPTION_KEYS) - { - if (!(xqos->aliased & QP_PRISMTECH_SUBSCRIPTION_KEYS)) - free_stringseq (&xqos->subscription_keys.key_list); - else - { - /* until proper message buffers arrive */ - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", (void *) xqos->subscription_keys.key_list.strs); - ddsrt_free (xqos->subscription_keys.key_list.strs); - } - } - xqos->present = 0; + plist_or_xqos_fini (xqos, offsetof (nn_plist_t, qos), ~(uint64_t)0, mask); } -nn_xqos_t * nn_xqos_dup (const nn_xqos_t *src) +void nn_xqos_unalias (dds_qos_t *xqos) { - nn_xqos_t *dst = ddsrt_malloc (sizeof (*dst)); + plist_or_xqos_unalias (xqos, offsetof (nn_plist_t, qos)); +} + +dds_qos_t * nn_xqos_dup (const dds_qos_t *src) +{ + dds_qos_t *dst = ddsrt_malloc (sizeof (*dst)); nn_xqos_copy (dst, src); assert (dst->aliased == 0); return dst; } -static int octetseqs_differ (const nn_octetseq_t *a, const nn_octetseq_t *b) +static int partition_is_default (const dds_partition_qospolicy_t *a) { - return (a->length != b->length || memcmp (a->value, b->value, a->length) != 0); -} - -static int durations_differ (const nn_duration_t *a, const nn_duration_t *b) -{ - return (a->seconds != b->seconds || a->fraction != b->fraction); -} - -static int stringseqs_differ (const nn_stringseq_t *a, const nn_stringseq_t *b) -{ - unsigned i; - if (a->n != b->n) - return 1; - for (i = 0; i < a->n; i++) - if (strcmp (a->strs[i], b->strs[i])) - return 1; - return 0; -} - -static int histories_differ (const nn_history_qospolicy_t *a, const nn_history_qospolicy_t *b) -{ - return (a->kind != b->kind || (a->kind == NN_KEEP_LAST_HISTORY_QOS && a->depth != b->depth)); -} - -static int resource_limits_differ (const nn_resource_limits_qospolicy_t *a, const nn_resource_limits_qospolicy_t *b) -{ - return (a->max_samples != b->max_samples || a->max_instances != b->max_instances || - a->max_samples_per_instance != b->max_samples_per_instance); -} - -static int partition_is_default (const nn_partition_qospolicy_t *a) -{ - unsigned i; + uint32_t i; for (i = 0; i < a->n; i++) if (strcmp (a->strs[i], "") != 0) return 0; return 1; } -static int partitions_equal_n2 (const nn_partition_qospolicy_t *a, const nn_partition_qospolicy_t *b) +static int partitions_equal_n2 (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b) { - unsigned i, j; + uint32_t i, j; for (i = 0; i < a->n; i++) { for (j = 0; j < b->n; j++) @@ -2988,22 +2577,29 @@ static int partitions_equal_n2 (const nn_partition_qospolicy_t *a, const nn_part return 1; } -static int partitions_equal_nlogn (const nn_partition_qospolicy_t *a, const nn_partition_qospolicy_t *b) +static int strcmp_wrapper (const void *va, const void *vb) +{ + char const * const *a = va; + char const * const *b = vb; + return strcmp (*a, *b); +} + +static int partitions_equal_nlogn (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b) { char *statictab[8], **tab; int equal = 1; - unsigned i; + uint32_t i; - if (a->n <= (int) (sizeof (statictab) / sizeof (*statictab))) + if (a->n <= sizeof (statictab) / sizeof (*statictab)) tab = statictab; else tab = ddsrt_malloc (a->n * sizeof (*tab)); for (i = 0; i < a->n; i++) tab[i] = a->strs[i]; - qsort (tab, a->n, sizeof (*tab), (int (*) (const void *, const void *)) strcmp); + qsort (tab, a->n, sizeof (*tab), strcmp_wrapper); for (i = 0; i < b->n; i++) - if (bsearch (b->strs[i], tab, a->n, sizeof (*tab), (int (*) (const void *, const void *)) strcmp) == NULL) + if (bsearch (&b->strs[i], tab, a->n, sizeof (*tab), strcmp_wrapper) == NULL) { equal = 0; break; @@ -3013,7 +2609,7 @@ static int partitions_equal_nlogn (const nn_partition_qospolicy_t *a, const nn_p return equal; } -static int partitions_equal (const nn_partition_qospolicy_t *a, const nn_partition_qospolicy_t *b) +static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b) { /* Return true iff (the set a->strs) equals (the set b->strs); that is, order doesn't matter. One could argue that "**" and "*" are @@ -3034,7 +2630,7 @@ static int partitions_equal (const nn_partition_qospolicy_t *a, const nn_partiti assuming that |A| >= |B|. */ if (a->n < b->n) { - const nn_partition_qospolicy_t *x = a; + const dds_partition_qospolicy_t *x = a; a = b; b = x; } @@ -3051,333 +2647,38 @@ static int partitions_equal (const nn_partition_qospolicy_t *a, const nn_partiti } } -uint64_t nn_xqos_delta (const nn_xqos_t *a, const nn_xqos_t *b, uint64_t mask) -{ - /* Returns QP_... set for RxO settings where a differs from b; if - present in a but not in b (or in b but not in a) it counts as a - difference. */ - uint64_t delta = (a->present ^ b->present) & mask; - uint64_t check = (a->present & b->present) & mask; - if (check & QP_TOPIC_NAME) { - if (strcmp (a->topic_name, b->topic_name)) - delta |= QP_TOPIC_NAME; - } - if (check & QP_TYPE_NAME) { - if (strcmp (a->type_name, b->type_name)) - delta |= QP_TYPE_NAME; - } - if (check & QP_PRESENTATION) { - if (a->presentation.access_scope != b->presentation.access_scope || - a->presentation.coherent_access != b->presentation.coherent_access || - a->presentation.ordered_access != b->presentation.ordered_access) - delta |= QP_PRESENTATION; - } - if (check & QP_PARTITION) { - if (!partitions_equal (&a->partition, &b->partition)) - delta |= QP_PARTITION; - } - if (check & QP_GROUP_DATA) { - if (octetseqs_differ (&a->group_data, &b->group_data)) - delta |= QP_GROUP_DATA; - } - if (check & QP_TOPIC_DATA) { - if (octetseqs_differ (&a->topic_data, &b->topic_data)) - delta |= QP_TOPIC_DATA; - } - if (check & QP_DURABILITY) { - if (a->durability.kind != b->durability.kind) - delta |= QP_DURABILITY; - } - if (check & QP_DURABILITY_SERVICE) - { - const nn_durability_service_qospolicy_t *qa = &a->durability_service; - const nn_durability_service_qospolicy_t *qb = &b->durability_service; - if (durations_differ (&qa->service_cleanup_delay, &qb->service_cleanup_delay) || - histories_differ (&qa->history, &qb->history) || - resource_limits_differ (&qa->resource_limits, &qb->resource_limits)) - delta |= QP_DURABILITY_SERVICE; - } - if (check & QP_DEADLINE) { - if (durations_differ (&a->deadline.deadline, &b->deadline.deadline)) - delta |= QP_DEADLINE; - } - if (check & QP_LATENCY_BUDGET) { - if (durations_differ (&a->latency_budget.duration, &b->latency_budget.duration)) - delta |= QP_LATENCY_BUDGET; - } - if (check & QP_LIVELINESS) { - if (a->liveliness.kind != b->liveliness.kind || - durations_differ (&a->liveliness.lease_duration, &b->liveliness.lease_duration)) - delta |= QP_LIVELINESS; - } - if (check & QP_RELIABILITY) { - if (a->reliability.kind != b->reliability.kind || - durations_differ (&a->reliability.max_blocking_time, &b->reliability.max_blocking_time)) - delta |= QP_RELIABILITY; - } - if (check & QP_DESTINATION_ORDER) { - if (a->destination_order.kind != b->destination_order.kind) - delta |= QP_DESTINATION_ORDER; - } - if (check & QP_HISTORY) { - if (histories_differ (&a->history, &b->history)) - delta |= QP_HISTORY; - } - if (check & QP_RESOURCE_LIMITS) { - if (resource_limits_differ (&a->resource_limits, &b->resource_limits)) - delta |= QP_RESOURCE_LIMITS; - } - if (check & QP_TRANSPORT_PRIORITY) { - if (a->transport_priority.value != b->transport_priority.value) - delta |= QP_TRANSPORT_PRIORITY; - } - if (check & QP_LIFESPAN) { - if (durations_differ (&a->lifespan.duration, &b->lifespan.duration)) - delta |= QP_LIFESPAN; - } - if (check & QP_USER_DATA) { - if (octetseqs_differ (&a->user_data, &b->user_data)) - delta |= QP_USER_DATA; - } - if (check & QP_OWNERSHIP) { - if (a->ownership.kind != b->ownership.kind) - delta |= QP_OWNERSHIP; - } - if (check & QP_OWNERSHIP_STRENGTH) { - if (a->ownership_strength.value != b->ownership_strength.value) - delta |= QP_OWNERSHIP_STRENGTH; - } - if (check & QP_TIME_BASED_FILTER) { - if (durations_differ (&a->time_based_filter.minimum_separation, &b->time_based_filter.minimum_separation)) - delta |= QP_TIME_BASED_FILTER; - } - if (check & QP_PRISMTECH_READER_DATA_LIFECYCLE) { - if (durations_differ (&a->reader_data_lifecycle.autopurge_disposed_samples_delay, - &b->reader_data_lifecycle.autopurge_disposed_samples_delay) || - durations_differ (&a->reader_data_lifecycle.autopurge_nowriter_samples_delay, - &b->reader_data_lifecycle.autopurge_nowriter_samples_delay) || - a->reader_data_lifecycle.autopurge_dispose_all != b->reader_data_lifecycle.autopurge_dispose_all || - a->reader_data_lifecycle.enable_invalid_samples != b->reader_data_lifecycle.enable_invalid_samples || - a->reader_data_lifecycle.invalid_sample_visibility != b->reader_data_lifecycle.invalid_sample_visibility) - delta |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - } - if (check & QP_PRISMTECH_WRITER_DATA_LIFECYCLE) { - if (a->writer_data_lifecycle.autodispose_unregistered_instances != - b->writer_data_lifecycle.autodispose_unregistered_instances || - durations_differ (&a->writer_data_lifecycle.autopurge_suspended_samples_delay, - &b->writer_data_lifecycle.autopurge_suspended_samples_delay) || - durations_differ (&a->writer_data_lifecycle.autounregister_instance_delay, - &b->writer_data_lifecycle.autounregister_instance_delay)) - delta |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - } - if (check & QP_PRISMTECH_RELAXED_QOS_MATCHING) { - if (a->relaxed_qos_matching.value != - b->relaxed_qos_matching.value) - delta |= QP_PRISMTECH_RELAXED_QOS_MATCHING; - } - if (check & QP_PRISMTECH_READER_LIFESPAN) { - /* Note: the conjunction need not test both a & b for having use_lifespan set */ - if (a->reader_lifespan.use_lifespan != b->reader_lifespan.use_lifespan || - (a->reader_lifespan.use_lifespan && b->reader_lifespan.use_lifespan && - durations_differ (&a->reader_lifespan.duration, &b->reader_lifespan.duration))) - delta |= QP_PRISMTECH_READER_LIFESPAN; - } - if (check & QP_PRISMTECH_SUBSCRIPTION_KEYS) { - /* Note: the conjunction need not test both a & b for having use_lifespan set */ - if (a->subscription_keys.use_key_list != b->subscription_keys.use_key_list || - (a->subscription_keys.use_key_list && b->subscription_keys.use_key_list && - stringseqs_differ (&a->subscription_keys.key_list, &b->subscription_keys.key_list))) - delta |= QP_PRISMTECH_SUBSCRIPTION_KEYS; - } - if (check & QP_PRISMTECH_ENTITY_FACTORY) { - if (a->entity_factory.autoenable_created_entities != - b->entity_factory.autoenable_created_entities) - delta |= QP_PRISMTECH_ENTITY_FACTORY; - } - if (check & QP_PRISMTECH_SYNCHRONOUS_ENDPOINT) { - if (a->synchronous_endpoint.value != b->synchronous_endpoint.value) - delta |= QP_PRISMTECH_SYNCHRONOUS_ENDPOINT; - } - if (check & QP_RTI_TYPECODE) { - if (octetseqs_differ (&a->rti_typecode, &b->rti_typecode)) - delta |= QP_RTI_TYPECODE; - } - if (check & QP_CYCLONE_IGNORELOCAL) { - if (a->ignorelocal.value != b->ignorelocal.value) - delta |= QP_CYCLONE_IGNORELOCAL; - } - return delta; -} - /*************************/ -void nn_xqos_addtomsg (struct nn_xmsg *m, const nn_xqos_t *xqos, uint64_t wanted) +void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted) { - /* Returns new nn_xmsg pointer (currently, reallocs may happen) */ - - uint64_t w = xqos->present & wanted; - char *tmp; -#define SIMPLE(name_, field_) \ - do { \ - if (w & QP_##name_) { \ - tmp = nn_xmsg_addpar (m, PID_##name_, sizeof (xqos->field_)); \ - *((nn_##field_##_qospolicy_t *) tmp) = xqos->field_; \ - } \ - } while (0) -#define FUNC_BY_REF(name_, field_, func_) \ - do { \ - if (w & QP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, &xqos->field_); \ - } \ - } while (0) -#define FUNC_BY_VAL(name_, field_, func_) \ - do { \ - if (w & QP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, xqos->field_); \ - } \ - } while (0) - - FUNC_BY_VAL (TOPIC_NAME, topic_name, string); - FUNC_BY_VAL (TYPE_NAME, type_name, string); - SIMPLE (PRESENTATION, presentation); - FUNC_BY_REF (PARTITION, partition, stringseq); - FUNC_BY_REF (GROUP_DATA, group_data, octetseq); - FUNC_BY_REF (TOPIC_DATA, topic_data, octetseq); - SIMPLE (DURABILITY, durability); - SIMPLE (DURABILITY_SERVICE, durability_service); - SIMPLE (DEADLINE, deadline); - SIMPLE (LATENCY_BUDGET, latency_budget); - SIMPLE (LIVELINESS, liveliness); - FUNC_BY_REF (RELIABILITY, reliability, reliability); - SIMPLE (DESTINATION_ORDER, destination_order); - SIMPLE (HISTORY, history); - SIMPLE (RESOURCE_LIMITS, resource_limits); - SIMPLE (TRANSPORT_PRIORITY, transport_priority); - SIMPLE (LIFESPAN, lifespan); - FUNC_BY_REF (USER_DATA, user_data, octetseq); - SIMPLE (OWNERSHIP, ownership); - SIMPLE (OWNERSHIP_STRENGTH, ownership_strength); - SIMPLE (TIME_BASED_FILTER, time_based_filter); - SIMPLE (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle); - SIMPLE (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle); - SIMPLE (PRISMTECH_RELAXED_QOS_MATCHING, relaxed_qos_matching); - SIMPLE (PRISMTECH_READER_LIFESPAN, reader_lifespan); - FUNC_BY_REF (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, subscription_keys); - SIMPLE (PRISMTECH_ENTITY_FACTORY, entity_factory); - SIMPLE (PRISMTECH_SYNCHRONOUS_ENDPOINT, synchronous_endpoint); - FUNC_BY_REF (RTI_TYPECODE, rti_typecode, octetseq); - /* CYCLONE_IGNORELOCAL is not visible on the wire */ -#undef FUNC_BY_REF -#undef FUNC_BY_VAL -#undef SIMPLE -} - -static void add_locators (struct nn_xmsg *m, uint64_t present, uint64_t flag, const nn_locators_t *ls, unsigned pid) -{ - const struct nn_locators_one *l; - if (present & flag) - { - for (l = ls->first; l != NULL; l = l->next) - { - char *tmp = nn_xmsg_addpar (m, pid, sizeof (nn_locator_t)); - memcpy (tmp, &l->loc, sizeof (nn_locator_t)); - } - } + plist_or_xqos_addtomsg (m, xqos, offsetof (struct nn_plist, qos), 0, wanted); } void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted) { - /* Returns new nn_xmsg pointer (currently, reallocs may happen), or NULL - on out-of-memory. (In which case the original nn_xmsg is freed, cos - that is then required anyway */ - uint64_t w = ps->present & pwanted; - char *tmp; -#define SIMPLE_TYPE(name_, field_, type_) \ - do { \ - if (w & PP_##name_) { \ - tmp = nn_xmsg_addpar (m, PID_##name_, sizeof (ps->field_)); \ - *((type_ *) tmp) = ps->field_; \ - } \ - } while (0) -#define FUNC_BY_VAL(name_, field_, func_) \ - do { \ - if (w & PP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, ps->field_); \ - } \ - } while (0) -#define FUNC_BY_REF(name_, field_, func_) \ - do { \ - if (w & PP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, &ps->field_); \ - } \ - } while (0) - - nn_xqos_addtomsg (m, &ps->qos, qwanted); - SIMPLE_TYPE (PROTOCOL_VERSION, protocol_version, nn_protocol_version_t); - SIMPLE_TYPE (VENDORID, vendorid, nn_vendorid_t); - - add_locators (m, ps->present, PP_UNICAST_LOCATOR, &ps->unicast_locators, PID_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_MULTICAST_LOCATOR, &ps->multicast_locators, PID_MULTICAST_LOCATOR); - add_locators (m, ps->present, PP_DEFAULT_UNICAST_LOCATOR, &ps->default_unicast_locators, PID_DEFAULT_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_DEFAULT_MULTICAST_LOCATOR, &ps->default_multicast_locators, PID_DEFAULT_MULTICAST_LOCATOR); - add_locators (m, ps->present, PP_METATRAFFIC_UNICAST_LOCATOR, &ps->metatraffic_unicast_locators, PID_METATRAFFIC_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_METATRAFFIC_MULTICAST_LOCATOR, &ps->metatraffic_multicast_locators, PID_METATRAFFIC_MULTICAST_LOCATOR); - - SIMPLE_TYPE (EXPECTS_INLINE_QOS, expects_inline_qos, unsigned char); - SIMPLE_TYPE (PARTICIPANT_LEASE_DURATION, participant_lease_duration, nn_duration_t); - FUNC_BY_REF (PARTICIPANT_GUID, participant_guid, guid); - SIMPLE_TYPE (BUILTIN_ENDPOINT_SET, builtin_endpoint_set, unsigned); - SIMPLE_TYPE (KEYHASH, keyhash, nn_keyhash_t); - if (w & PP_STATUSINFO) - nn_xmsg_addpar_statusinfo (m, ps->statusinfo); - SIMPLE_TYPE (COHERENT_SET, coherent_set_seqno, nn_sequence_number_t); - if (! NN_PEDANTIC_P) - FUNC_BY_REF (ENDPOINT_GUID, endpoint_guid, guid); - else - { - if (w & PP_ENDPOINT_GUID) - { - nn_xmsg_addpar_guid (m, PID_PRISMTECH_ENDPOINT_GUID, &ps->endpoint_guid); - } - } - FUNC_BY_REF (GROUP_GUID, group_guid, guid); - SIMPLE_TYPE (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, unsigned); - FUNC_BY_REF (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, parvinfo); - FUNC_BY_VAL (ENTITY_NAME, entity_name, string); - FUNC_BY_VAL (PRISMTECH_NODE_NAME, node_name, string); - FUNC_BY_VAL (PRISMTECH_EXEC_NAME, exec_name, string); - SIMPLE_TYPE (PRISMTECH_PROCESS_ID, process_id, unsigned); - SIMPLE_TYPE (PRISMTECH_SERVICE_TYPE, service_type, unsigned); - FUNC_BY_VAL (PRISMTECH_TYPE_DESCRIPTION, type_description, string); - FUNC_BY_REF (PRISMTECH_EOTINFO, eotinfo, eotinfo); -#ifdef DDSI_INCLUDE_SSM - SIMPLE_TYPE (READER_FAVOURS_SSM, reader_favours_ssm, nn_reader_favours_ssm_t); -#endif -#undef FUNC_BY_REF -#undef FUNC_BY_VAL -#undef SIMPLE + plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted); } /*************************/ -static unsigned isprint_runlen (unsigned n, const unsigned char *xs) +static uint32_t isprint_runlen (uint32_t n, const unsigned char *xs) { - unsigned m; - for (m = 0; m < n && xs[m] != '"' && isprint (xs[m]); m++) + uint32_t m; + for (m = 0; m < n && xs[m] != '"' && isprint (xs[m]) && xs[m] < 127; m++) ; return m; } -static void log_octetseq (uint32_t cat, unsigned n, const unsigned char *xs) +static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs) { - unsigned i = 0; + uint32_t i = 0; while (i < n) { - unsigned m = isprint_runlen(n - i, xs); - if (m >= 4) + uint32_t m = isprint_runlen (n - i, xs); + if (m >= 4 || (i == 0 && m == n)) { - DDS_LOG(cat, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs); + DDS_CLOG (cat, logcfg, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs); xs += m; i += m; } @@ -3387,96 +2688,80 @@ static void log_octetseq (uint32_t cat, unsigned n, const unsigned char *xs) m = 1; while (m--) { - DDS_LOG(cat, "%s%u", i == 0 ? "" : ",", *xs++); + DDS_CLOG (cat, logcfg, "%s%u", i == 0 ? "" : ",", *xs++); i++; } } } } -void nn_log_xqos (uint32_t cat, const nn_xqos_t *xqos) +void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos) { uint64_t p = xqos->present; const char *prefix = ""; -#define LOGB0(fmt_) DDS_LOG(cat, "%s" fmt_, prefix) -#define LOGB1(fmt_, arg0_) DDS_LOG(cat, "%s" fmt_, prefix, arg0_) -#define LOGB2(fmt_, arg0_, arg1_) DDS_LOG(cat, "%s" fmt_, prefix, arg0_, arg1_) -#define LOGB3(fmt_, arg0_, arg1_, arg2_) DDS_LOG(cat, "%s" fmt_, prefix, arg0_, arg1_, arg2_) -#define LOGB4(fmt_, arg0_, arg1_, arg2_, arg3_) DDS_LOG(cat, "%s" fmt_, prefix, arg0_, arg1_, arg2_, arg3_) -#define LOGB5(fmt_, arg0_, arg1_, arg2_, arg3_, arg4_) DDS_LOG(cat, "%s" fmt_, prefix, arg0_, arg1_, arg2_, arg3_, arg4_) +#define LOGB0(fmt_) DDS_CLOG (cat, logcfg, "%s" fmt_, prefix) +#define LOGB1(fmt_, ...) DDS_CLOG (cat, logcfg, "%s" fmt_, prefix, __VA_ARGS__) #define DO(name_, body_) do { if (p & QP_##name_) { { body_ } prefix = ","; } } while (0) -#define FMT_DUR "%d.%09d" -#define PRINTARG_DUR(d) (d).seconds, (int) ((d).fraction/4.294967296) +#define FMT_DUR "%"PRId64".%09"PRId32 +#define PRINTARG_DUR(d) ((int64_t) ((d) / 1000000000)), ((int32_t) ((d) % 1000000000)) DO (TOPIC_NAME, { LOGB1 ("topic=%s", xqos->topic_name); }); DO (TYPE_NAME, { LOGB1 ("type=%s", xqos->type_name); }); - DO (PRESENTATION, { LOGB3 ("presentation=%d:%u:%u", xqos->presentation.access_scope, xqos->presentation.coherent_access, xqos->presentation.ordered_access); }); + DO (PRESENTATION, { LOGB1 ("presentation=%d:%u:%u", xqos->presentation.access_scope, xqos->presentation.coherent_access, xqos->presentation.ordered_access); }); DO (PARTITION, { - unsigned i; LOGB0 ("partition={"); - for (i = 0; i < xqos->partition.n; i++) { - DDS_LOG(cat, "%s%s", (i == 0) ? "" : ",", xqos->partition.strs[i]); + for (uint32_t i = 0; i < xqos->partition.n; i++) { + DDS_CLOG (cat, logcfg, "%s%s", (i == 0) ? "" : ",", xqos->partition.strs[i]); } - DDS_LOG(cat, "}"); + DDS_CLOG (cat, logcfg, "}"); }); DO (GROUP_DATA, { LOGB1 ("group_data=%"PRIu32"<", xqos->group_data.length); - log_octetseq (cat, xqos->group_data.length, xqos->group_data.value); - DDS_LOG(cat, ">"); + log_octetseq (cat, logcfg, xqos->group_data.length, xqos->group_data.value); + DDS_CLOG (cat, logcfg, ">"); }); DO (TOPIC_DATA, { LOGB1 ("topic_data=%"PRIu32"<", xqos->topic_data.length); - log_octetseq (cat, xqos->topic_data.length, xqos->topic_data.value); - DDS_LOG(cat, ">"); + log_octetseq (cat, logcfg, xqos->topic_data.length, xqos->topic_data.value); + DDS_CLOG(cat, logcfg, ">"); }); DO (DURABILITY, { LOGB1 ("durability=%d", xqos->durability.kind); }); DO (DURABILITY_SERVICE, { LOGB0 ("durability_service="); - DDS_LOG(cat, FMT_DUR, PRINTARG_DUR (xqos->durability_service.service_cleanup_delay)); - DDS_LOG(cat, ":{%u:%"PRId32"}", xqos->durability_service.history.kind, xqos->durability_service.history.depth); - DDS_LOG(cat, ":{%"PRId32":%"PRId32":%"PRId32"}", xqos->durability_service.resource_limits.max_samples, xqos->durability_service.resource_limits.max_instances, xqos->durability_service.resource_limits.max_samples_per_instance); + DDS_CLOG(cat, logcfg, FMT_DUR, PRINTARG_DUR (xqos->durability_service.service_cleanup_delay)); + DDS_CLOG(cat, logcfg, ":{%u:%"PRId32"}", xqos->durability_service.history.kind, xqos->durability_service.history.depth); + DDS_CLOG(cat, logcfg, ":{%"PRId32":%"PRId32":%"PRId32"}", xqos->durability_service.resource_limits.max_samples, xqos->durability_service.resource_limits.max_instances, xqos->durability_service.resource_limits.max_samples_per_instance); }); DO (DEADLINE, { LOGB1 ("deadline="FMT_DUR, PRINTARG_DUR (xqos->deadline.deadline)); }); DO (LATENCY_BUDGET, { LOGB1 ("latency_budget="FMT_DUR, PRINTARG_DUR (xqos->latency_budget.duration)); }); - DO (LIVELINESS, { LOGB2 ("liveliness=%d:"FMT_DUR, xqos->liveliness.kind, PRINTARG_DUR (xqos->liveliness.lease_duration)); }); - DO (RELIABILITY, { LOGB2 ("reliability=%d:"FMT_DUR, xqos->reliability.kind, PRINTARG_DUR (xqos->reliability.max_blocking_time)); }); + DO (LIVELINESS, { LOGB1 ("liveliness=%d:"FMT_DUR, xqos->liveliness.kind, PRINTARG_DUR (xqos->liveliness.lease_duration)); }); + DO (RELIABILITY, { LOGB1 ("reliability=%d:"FMT_DUR, xqos->reliability.kind, PRINTARG_DUR (xqos->reliability.max_blocking_time)); }); DO (DESTINATION_ORDER, { LOGB1 ("destination_order=%d", xqos->destination_order.kind); }); - DO (HISTORY, { LOGB2 ("history=%d:%"PRId32, xqos->history.kind, xqos->history.depth); }); - DO (RESOURCE_LIMITS, { LOGB3 ("resource_limits=%"PRId32":%"PRId32":%"PRId32, xqos->resource_limits.max_samples, xqos->resource_limits.max_instances, xqos->resource_limits.max_samples_per_instance); }); + DO (HISTORY, { LOGB1 ("history=%d:%"PRId32, xqos->history.kind, xqos->history.depth); }); + DO (RESOURCE_LIMITS, { LOGB1 ("resource_limits=%"PRId32":%"PRId32":%"PRId32, xqos->resource_limits.max_samples, xqos->resource_limits.max_instances, xqos->resource_limits.max_samples_per_instance); }); DO (TRANSPORT_PRIORITY, { LOGB1 ("transport_priority=%"PRId32, xqos->transport_priority.value); }); DO (LIFESPAN, { LOGB1 ("lifespan="FMT_DUR, PRINTARG_DUR (xqos->lifespan.duration)); }); DO (USER_DATA, { LOGB1 ("user_data=%"PRIu32"<", xqos->user_data.length); - log_octetseq (cat, xqos->user_data.length, xqos->user_data.value); - DDS_LOG(cat, ">"); + log_octetseq (cat, logcfg, xqos->user_data.length, xqos->user_data.value); + DDS_CLOG (cat, logcfg, ">"); }); DO (OWNERSHIP, { LOGB1 ("ownership=%d", xqos->ownership.kind); }); DO (OWNERSHIP_STRENGTH, { LOGB1 ("ownership_strength=%"PRId32, xqos->ownership_strength.value); }); DO (TIME_BASED_FILTER, { LOGB1 ("time_based_filter="FMT_DUR, PRINTARG_DUR (xqos->time_based_filter.minimum_separation)); }); - DO (PRISMTECH_READER_DATA_LIFECYCLE, { LOGB5 ("reader_data_lifecycle="FMT_DUR":"FMT_DUR":%u:%u:%d", PRINTARG_DUR (xqos->reader_data_lifecycle.autopurge_nowriter_samples_delay), PRINTARG_DUR (xqos->reader_data_lifecycle.autopurge_disposed_samples_delay), xqos->reader_data_lifecycle.autopurge_dispose_all, xqos->reader_data_lifecycle.enable_invalid_samples, (int) xqos->reader_data_lifecycle.invalid_sample_visibility); }); + DO (PRISMTECH_READER_DATA_LIFECYCLE, { LOGB1 ("reader_data_lifecycle="FMT_DUR":"FMT_DUR, PRINTARG_DUR (xqos->reader_data_lifecycle.autopurge_nowriter_samples_delay), PRINTARG_DUR (xqos->reader_data_lifecycle.autopurge_disposed_samples_delay)); }); DO (PRISMTECH_WRITER_DATA_LIFECYCLE, { - LOGB3 ("writer_data_lifecycle={%u,"FMT_DUR","FMT_DUR"}", - xqos->writer_data_lifecycle.autodispose_unregistered_instances, - PRINTARG_DUR (xqos->writer_data_lifecycle.autounregister_instance_delay), - PRINTARG_DUR (xqos->writer_data_lifecycle.autopurge_suspended_samples_delay)); }); - DO (PRISMTECH_RELAXED_QOS_MATCHING, { LOGB1 ("relaxed_qos_matching=%u", xqos->relaxed_qos_matching.value); }); - DO (PRISMTECH_READER_LIFESPAN, { LOGB2 ("reader_lifespan={%u,"FMT_DUR"}", xqos->reader_lifespan.use_lifespan, PRINTARG_DUR (xqos->reader_lifespan.duration)); }); + LOGB1 ("writer_data_lifecycle={%u}", xqos->writer_data_lifecycle.autodispose_unregistered_instances); }); + DO (PRISMTECH_READER_LIFESPAN, { LOGB1 ("reader_lifespan={%u,"FMT_DUR"}", xqos->reader_lifespan.use_lifespan, PRINTARG_DUR (xqos->reader_lifespan.duration)); }); DO (PRISMTECH_SUBSCRIPTION_KEYS, { - unsigned i; LOGB1 ("subscription_keys={%u,{", xqos->subscription_keys.use_key_list); - for (i = 0; i < xqos->subscription_keys.key_list.n; i++) { - DDS_LOG(cat, "%s%s", (i == 0) ? "" : ",", xqos->subscription_keys.key_list.strs[i]); + for (uint32_t i = 0; i < xqos->subscription_keys.key_list.n; i++) { + DDS_CLOG (cat, logcfg, "%s%s", (i == 0) ? "" : ",", xqos->subscription_keys.key_list.strs[i]); } - DDS_LOG(cat, "}}"); + DDS_CLOG (cat, logcfg, "}}"); }); DO (PRISMTECH_ENTITY_FACTORY, { LOGB1 ("entity_factory=%u", xqos->entity_factory.autoenable_created_entities); }); - DO (PRISMTECH_SYNCHRONOUS_ENDPOINT, { LOGB1 ("synchronous_endpoint=%u", xqos->synchronous_endpoint.value); }); - DO (RTI_TYPECODE, { - LOGB1 ("rti_typecode=%"PRIu32"<", xqos->rti_typecode.length); - log_octetseq (cat, xqos->rti_typecode.length, xqos->rti_typecode.value); - DDS_LOG(cat, ">"); - }); DO (CYCLONE_IGNORELOCAL, { LOGB1 ("ignorelocal=%u", xqos->ignorelocal.value); }); #undef PRINTARG_DUR diff --git a/src/core/ddsi/src/q_qosmatch.c b/src/core/ddsi/src/q_qosmatch.c index abac093..721a010 100644 --- a/src/core/ddsi/src/q_qosmatch.c +++ b/src/core/ddsi/src/q_qosmatch.c @@ -17,7 +17,7 @@ #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_qosmatch.h" -int is_wildcard_partition (const char *str) +static int is_wildcard_partition (const char *str) { return strchr (str, '*') || strchr (str, '?'); } @@ -35,18 +35,17 @@ static int partition_patmatch_p (const char *pat, const char *name) return ddsi2_patmatch (pat, name); } -static int partitions_match_default (const nn_xqos_t *x) +static int partitions_match_default (const dds_qos_t *x) { - unsigned i; if (!(x->present & QP_PARTITION) || x->partition.n == 0) return 1; - for (i = 0; i < x->partition.n; i++) + for (uint32_t i = 0; i < x->partition.n; i++) if (partition_patmatch_p (x->partition.strs[i], "")) return 1; return 0; } -int partitions_match_p (const nn_xqos_t *a, const nn_xqos_t *b) +int partitions_match_p (const dds_qos_t *a, const dds_qos_t *b) { if (!(a->present & QP_PARTITION) || a->partition.n == 0) return partitions_match_default (b); @@ -54,9 +53,8 @@ int partitions_match_p (const nn_xqos_t *a, const nn_xqos_t *b) return partitions_match_default (a); else { - unsigned i, j; - for (i = 0; i < a->partition.n; i++) - for (j = 0; j < b->partition.n; j++) + for (uint32_t i = 0; i < a->partition.n; i++) + for (uint32_t j = 0; j < b->partition.n; j++) { if (partition_patmatch_p (a->partition.strs[i], b->partition.strs[j]) || partition_patmatch_p (b->partition.strs[j], a->partition.strs[i])) @@ -66,157 +64,73 @@ int partitions_match_p (const nn_xqos_t *a, const nn_xqos_t *b) } } -int partition_match_based_on_wildcard_in_left_operand (const nn_xqos_t *a, const nn_xqos_t *b, const char **realname) -{ - assert (partitions_match_p (a, b)); - if (!(a->present & QP_PARTITION) || a->partition.n == 0) - { - return 0; - } - else if (!(b->present & QP_PARTITION) || b->partition.n == 0) - { - /* Either A explicitly includes the default partition, or it is a - wildcard that matches it */ - unsigned i; - for (i = 0; i < a->partition.n; i++) - if (strcmp (a->partition.strs[i], "") == 0) - return 0; - *realname = ""; - return 1; - } - else - { - unsigned i, j; - int maybe_yes = 0; - for (i = 0; i < a->partition.n; i++) - for (j = 0; j < b->partition.n; j++) - { - if (partition_patmatch_p (a->partition.strs[i], b->partition.strs[j])) - { - if (!is_wildcard_partition (a->partition.strs[i])) - return 0; - else - { - *realname = b->partition.strs[j]; - maybe_yes = 1; - } - } - } - return maybe_yes; - } -} - -static int ddsi_duration_is_lt (nn_duration_t a0, nn_duration_t b0) -{ - /* inf counts as <= inf */ - const int64_t a = nn_from_ddsi_duration (a0); - const int64_t b = nn_from_ddsi_duration (b0); - if (a == T_NEVER) - return 0; - else if (b == T_NEVER) - return 1; - else - return a < b; -} - -/* Duplicates of DDS policy ids to avoid inclusion of actual definitions */ - -#define Q_INVALID_QOS_POLICY_ID 0 -#define Q_USERDATA_QOS_POLICY_ID 1 -#define Q_DURABILITY_QOS_POLICY_ID 2 -#define Q_PRESENTATION_QOS_POLICY_ID 3 -#define Q_DEADLINE_QOS_POLICY_ID 4 -#define Q_LATENCYBUDGET_QOS_POLICY_ID 5 -#define Q_OWNERSHIP_QOS_POLICY_ID 6 -#define Q_OWNERSHIPSTRENGTH_QOS_POLICY_ID 7 -#define Q_LIVELINESS_QOS_POLICY_ID 8 -#define Q_TIMEBASEDFILTER_QOS_POLICY_ID 9 -#define Q_PARTITION_QOS_POLICY_ID 10 -#define Q_RELIABILITY_QOS_POLICY_ID 11 -#define Q_DESTINATIONORDER_QOS_POLICY_ID 12 -#define Q_HISTORY_QOS_POLICY_ID 13 -#define Q_RESOURCELIMITS_QOS_POLICY_ID 14 -#define Q_ENTITYFACTORY_QOS_POLICY_ID 15 -#define Q_WRITERDATALIFECYCLE_QOS_POLICY_ID 16 -#define Q_READERDATALIFECYCLE_QOS_POLICY_ID 17 -#define Q_TOPICDATA_QOS_POLICY_ID 18 -#define Q_GROUPDATA_QOS_POLICY_ID 19 -#define Q_TRANSPORTPRIORITY_QOS_POLICY_ID 20 -#define Q_LIFESPAN_QOS_POLICY_ID 21 -#define Q_DURABILITYSERVICE_QOS_POLICY_ID 22 - -int32_t qos_match_p (const nn_xqos_t *rd, const nn_xqos_t *wr) +bool qos_match_mask_p (const dds_qos_t *rd, const dds_qos_t *wr, uint64_t mask, dds_qos_policy_id_t *reason) { #ifndef NDEBUG - unsigned musthave = (QP_RXO_MASK | QP_PARTITION | QP_TOPIC_NAME | QP_TYPE_NAME); + unsigned musthave = (QP_RXO_MASK | QP_PARTITION | QP_TOPIC_NAME | QP_TYPE_NAME) & mask; assert ((rd->present & musthave) == musthave); assert ((wr->present & musthave) == musthave); #endif - if (strcmp (rd->topic_name, wr->topic_name) != 0) - { - return Q_INVALID_QOS_POLICY_ID; + mask &= rd->present & wr->present; + *reason = DDS_INVALID_QOS_POLICY_ID; + if ((mask & QP_TOPIC_NAME) && strcmp (rd->topic_name, wr->topic_name) != 0) + return false; + if ((mask & QP_TYPE_NAME) && strcmp (rd->type_name, wr->type_name) != 0) + return false; + + if ((mask & QP_RELIABILITY) && rd->reliability.kind > wr->reliability.kind) { + *reason = DDS_RELIABILITY_QOS_POLICY_ID; + return false; } - if (strcmp (rd->type_name, wr->type_name) != 0) - { - return Q_INVALID_QOS_POLICY_ID; + if ((mask & QP_DURABILITY) && rd->durability.kind > wr->durability.kind) { + *reason = DDS_DURABILITY_QOS_POLICY_ID; + return false; } - if (rd->relaxed_qos_matching.value || wr->relaxed_qos_matching.value) - { - if (rd->reliability.kind != wr->reliability.kind) - { - return Q_RELIABILITY_QOS_POLICY_ID; - } + if ((mask & QP_PRESENTATION) && rd->presentation.access_scope > wr->presentation.access_scope) { + *reason = DDS_PRESENTATION_QOS_POLICY_ID; + return false; } - else - { - if (rd->reliability.kind > wr->reliability.kind) - { - return Q_RELIABILITY_QOS_POLICY_ID; - } - if (rd->durability.kind > wr->durability.kind) - { - return Q_DURABILITY_QOS_POLICY_ID; - } - if (rd->presentation.access_scope > wr->presentation.access_scope) - { - return Q_PRESENTATION_QOS_POLICY_ID; - } - if (rd->presentation.coherent_access > wr->presentation.coherent_access) - { - return Q_PRESENTATION_QOS_POLICY_ID; - } - if (rd->presentation.ordered_access > wr->presentation.ordered_access) - { - return Q_PRESENTATION_QOS_POLICY_ID; - } - if (ddsi_duration_is_lt (rd->deadline.deadline, wr->deadline.deadline)) - { - return Q_DEADLINE_QOS_POLICY_ID; - } - if (ddsi_duration_is_lt (rd->latency_budget.duration, wr->latency_budget.duration)) - { - return Q_LATENCYBUDGET_QOS_POLICY_ID; - } - if (rd->ownership.kind != wr->ownership.kind) - { - return Q_OWNERSHIP_QOS_POLICY_ID; - } - if (rd->liveliness.kind > wr->liveliness.kind) - { - return Q_LIVELINESS_QOS_POLICY_ID; - } - if (ddsi_duration_is_lt (rd->liveliness.lease_duration, wr->liveliness.lease_duration)) - { - return Q_LIVELINESS_QOS_POLICY_ID; - } - if (rd->destination_order.kind > wr->destination_order.kind) - { - return Q_DESTINATIONORDER_QOS_POLICY_ID; - } + if ((mask & QP_PRESENTATION) && rd->presentation.coherent_access > wr->presentation.coherent_access) { + *reason = DDS_PRESENTATION_QOS_POLICY_ID; + return false; } - if (!partitions_match_p (rd, wr)) - { - return Q_PARTITION_QOS_POLICY_ID; + if ((mask & QP_PRESENTATION) && rd->presentation.ordered_access > wr->presentation.ordered_access) { + *reason = DDS_PRESENTATION_QOS_POLICY_ID; + return false; } - return -1; + if ((mask & QP_DEADLINE) && rd->deadline.deadline < wr->deadline.deadline) { + *reason = DDS_DEADLINE_QOS_POLICY_ID; + return false; + } + if ((mask & QP_LATENCY_BUDGET) && rd->latency_budget.duration < wr->latency_budget.duration) { + *reason = DDS_LATENCYBUDGET_QOS_POLICY_ID; + return false; + } + if ((mask & QP_OWNERSHIP) && rd->ownership.kind != wr->ownership.kind) { + *reason = DDS_OWNERSHIP_QOS_POLICY_ID; + return false; + } + if ((mask & QP_LIVELINESS) && rd->liveliness.kind > wr->liveliness.kind) { + *reason = DDS_LIVELINESS_QOS_POLICY_ID; + return false; + } + if ((mask & QP_LIVELINESS) && rd->liveliness.lease_duration < wr->liveliness.lease_duration) { + *reason = DDS_LIVELINESS_QOS_POLICY_ID; + return false; + } + if ((mask & QP_DESTINATION_ORDER) && rd->destination_order.kind > wr->destination_order.kind) { + *reason = DDS_DESTINATIONORDER_QOS_POLICY_ID; + return false; + } + if ((mask & QP_PARTITION) && !partitions_match_p (rd, wr)) { + *reason = DDS_PARTITION_QOS_POLICY_ID; + return false; + } + return true; +} + +bool qos_match_p (const dds_qos_t *rd, const dds_qos_t *wr, dds_qos_policy_id_t *reason) +{ + dds_qos_policy_id_t dummy; + return qos_match_mask_p (rd, wr, ~(uint64_t)0, reason ? reason : &dummy); } diff --git a/src/core/ddsi/src/q_radmin.c b/src/core/ddsi/src/q_radmin.c index a45d4e0..46578cc 100644 --- a/src/core/ddsi/src/q_radmin.c +++ b/src/core/ddsi/src/q_radmin.c @@ -284,6 +284,8 @@ struct nn_rbufpool { struct nn_rbuf *current; uint32_t rbuf_size; uint32_t max_rmsg_size; + const struct ddsrt_log_cfg *logcfg; + bool trace; #ifndef NDEBUG /* Thread that owns this pool, so we can check that no other thread is calling functions only the owner may use. */ @@ -291,9 +293,16 @@ struct nn_rbufpool { #endif }; -static struct nn_rbuf *nn_rbuf_alloc_new (struct nn_rbufpool *rbufpool); +static struct nn_rbuf *nn_rbuf_alloc_new (struct nn_rbufpool *rbp); static void nn_rbuf_release (struct nn_rbuf *rbuf); +#define TRACE_CFG(obj, logcfg, ...) ((obj)->trace ? (void) DDS_CLOG (DDS_LC_RADMIN, (logcfg), __VA_ARGS__) : (void) 0) +#define TRACE(obj, ...) TRACE_CFG ((obj), (obj)->logcfg, __VA_ARGS__) +#define RBPTRACE(...) TRACE_CFG (rbp, rbp->logcfg, __VA_ARGS__) +#define RBUFTRACE(...) TRACE_CFG (rbuf, rbuf->rbufpool->logcfg, __VA_ARGS__) +#define RMSGTRACE(...) TRACE_CFG (rmsg, rmsg->chunk.rbuf->rbufpool->logcfg, __VA_ARGS__) +#define RDATATRACE(rdata, ...) TRACE_CFG ((rdata)->rmsg, (rdata)->rmsg->chunk.rbuf->rbufpool->logcfg, __VA_ARGS__) + static uint32_t align8uint32 (uint32_t x) { return (x + 7u) & (uint32_t)-8; @@ -320,12 +329,12 @@ static uint32_t max_rmsg_size_w_hdr (uint32_t max_rmsg_size) allocate for the worst case, and may waste a few bytes here or there. */ return - max_uint32 ((uint32_t) offsetof (struct nn_rmsg, chunk.u.payload), - (uint32_t) offsetof (struct nn_rmsg_chunk, u.payload)) + max_uint32 ((uint32_t) (offsetof (struct nn_rmsg, chunk) + sizeof (struct nn_rmsg_chunk)), + (uint32_t) sizeof (struct nn_rmsg_chunk)) + max_rmsg_size; } -struct nn_rbufpool *nn_rbufpool_new (uint32_t rbuf_size, uint32_t max_rmsg_size) +struct nn_rbufpool *nn_rbufpool_new (const struct ddsrt_log_cfg *logcfg, uint32_t rbuf_size, uint32_t max_rmsg_size) { struct nn_rbufpool *rbp; @@ -348,6 +357,8 @@ struct nn_rbufpool *nn_rbufpool_new (uint32_t rbuf_size, uint32_t max_rmsg_size) rbp->rbuf_size = rbuf_size; rbp->max_rmsg_size = max_rmsg_size; + rbp->logcfg = logcfg; + rbp->trace = (logcfg->c.mask & DDS_LC_RADMIN) != 0; #if USE_VALGRIND VALGRIND_CREATE_MEMPOOL (rbp, 0, 0); @@ -398,6 +409,7 @@ struct nn_rbuf { uint32_t size; uint32_t max_rmsg_size; struct nn_rbufpool *rbufpool; + bool trace; /* Allocating sequentially, releasing in random order, not bothering to reuse memory as soon as it becomes available again. I think @@ -405,48 +417,49 @@ struct nn_rbuf { approach. Changes would be confined rmsg_new and rmsg_free. */ unsigned char *freeptr; + /* to ensure reasonable alignment of raw[] */ union { - /* raw data array, nn_rbuf::size bytes long in reality */ - unsigned char raw[1]; - - /* to ensure reasonable alignment of raw[] */ int64_t l; double d; void *p; } u; + + /* raw data array, nn_rbuf::size bytes long in reality */ + unsigned char raw[]; }; -static struct nn_rbuf *nn_rbuf_alloc_new (struct nn_rbufpool *rbufpool) +static struct nn_rbuf *nn_rbuf_alloc_new (struct nn_rbufpool *rbp) { struct nn_rbuf *rb; - ASSERT_RBUFPOOL_OWNER (rbufpool); + ASSERT_RBUFPOOL_OWNER (rbp); - if ((rb = ddsrt_malloc (offsetof (struct nn_rbuf, u.raw) + rbufpool->rbuf_size)) == NULL) + if ((rb = ddsrt_malloc (sizeof (struct nn_rbuf) + rbp->rbuf_size)) == NULL) return NULL; #if USE_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS (rb->u.raw, rbufpool->rbuf_size); + VALGRIND_MAKE_MEM_NOACCESS (rb->raw, rbp->rbuf_size); #endif - rb->rbufpool = rbufpool; + rb->rbufpool = rbp; ddsrt_atomic_st32 (&rb->n_live_rmsg_chunks, 1); - rb->size = rbufpool->rbuf_size; - rb->max_rmsg_size = rbufpool->max_rmsg_size; - rb->freeptr = rb->u.raw; - DDS_LOG(DDS_LC_RADMIN, "rbuf_alloc_new(%p) = %p\n", (void *) rbufpool, (void *) rb); + rb->size = rbp->rbuf_size; + rb->max_rmsg_size = rbp->max_rmsg_size; + rb->freeptr = rb->raw; + rb->trace = rbp->trace; + RBPTRACE ("rbuf_alloc_new(%p) = %p\n", (void *) rbp, (void *) rb); return rb; } -static struct nn_rbuf *nn_rbuf_new (struct nn_rbufpool *rbufpool) +static struct nn_rbuf *nn_rbuf_new (struct nn_rbufpool *rbp) { struct nn_rbuf *rb; - assert (rbufpool->current); - ASSERT_RBUFPOOL_OWNER (rbufpool); - if ((rb = nn_rbuf_alloc_new (rbufpool)) != NULL) + assert (rbp->current); + ASSERT_RBUFPOOL_OWNER (rbp); + if ((rb = nn_rbuf_alloc_new (rbp)) != NULL) { - ddsrt_mutex_lock (&rbufpool->lock); - nn_rbuf_release (rbufpool->current); - rbufpool->current = rb; - ddsrt_mutex_unlock (&rbufpool->lock); + ddsrt_mutex_lock (&rbp->lock); + nn_rbuf_release (rbp->current); + rbp->current = rb; + ddsrt_mutex_unlock (&rbp->lock); } return rb; } @@ -454,10 +467,10 @@ static struct nn_rbuf *nn_rbuf_new (struct nn_rbufpool *rbufpool) static void nn_rbuf_release (struct nn_rbuf *rbuf) { struct nn_rbufpool *rbp = rbuf->rbufpool; - DDS_LOG(DDS_LC_RADMIN, "rbuf_release(%p) pool %p current %p\n", (void *) rbuf, (void *) rbp, (void *) rbp->current); + RBPTRACE ("rbuf_release(%p) pool %p current %p\n", (void *) rbuf, (void *) rbp, (void *) rbp->current); if (ddsrt_atomic_dec32_ov (&rbuf->n_live_rmsg_chunks) == 1) { - DDS_LOG(DDS_LC_RADMIN, "rbuf_release(%p) free\n", (void *) rbuf); + RBPTRACE ("rbuf_release(%p) free\n", (void *) rbuf); ddsrt_free (rbuf); } } @@ -479,31 +492,31 @@ static void nn_rbuf_release (struct nn_rbuf *rbuf) #define ASSERT_RMSG_UNCOMMITTED(rmsg) ((void) 0) #endif -static void *nn_rbuf_alloc (struct nn_rbufpool *rbufpool) +static void *nn_rbuf_alloc (struct nn_rbufpool *rbp) { /* Note: only one thread calls nn_rmsg_new on a pool */ - uint32_t asize = max_rmsg_size_w_hdr (rbufpool->max_rmsg_size); + uint32_t asize = max_rmsg_size_w_hdr (rbp->max_rmsg_size); struct nn_rbuf *rb; - DDS_LOG(DDS_LC_RADMIN, "rmsg_rbuf_alloc(%p, %"PRIu32")\n", (void *) rbufpool, asize); - ASSERT_RBUFPOOL_OWNER (rbufpool); - rb = rbufpool->current; + RBPTRACE ("rmsg_rbuf_alloc(%p, %"PRIu32")\n", (void *) rbp, asize); + ASSERT_RBUFPOOL_OWNER (rbp); + rb = rbp->current; assert (rb != NULL); - assert (rb->freeptr >= rb->u.raw); - assert (rb->freeptr <= rb->u.raw + rb->size); + assert (rb->freeptr >= rb->raw); + assert (rb->freeptr <= rb->raw + rb->size); - if ((uint32_t) (rb->u.raw + rb->size - rb->freeptr) < asize) + if ((uint32_t) (rb->raw + rb->size - rb->freeptr) < asize) { /* not enough space left for new rmsg */ - if ((rb = nn_rbuf_new (rbufpool)) == NULL) + if ((rb = nn_rbuf_new (rbp)) == NULL) return NULL; /* a new one should have plenty of space */ - assert ((uint32_t) (rb->u.raw + rb->size - rb->freeptr) >= asize); + assert ((uint32_t) (rb->raw + rb->size - rb->freeptr) >= asize); } - DDS_LOG(DDS_LC_RADMIN, "rmsg_rbuf_alloc(%p, %"PRIu32") = %p\n", (void *) rbufpool, asize, (void *) rb->freeptr); + RBPTRACE ("rmsg_rbuf_alloc(%p, %"PRIu32") = %p\n", (void *) rbp, asize, (void *) rb->freeptr); #if USE_VALGRIND - VALGRIND_MEMPOOL_ALLOC (rbufpool, rb->freeptr, asize); + VALGRIND_MEMPOOL_ALLOC (rbp, rb->freeptr, asize); #endif return rb->freeptr; } @@ -512,42 +525,43 @@ static void init_rmsg_chunk (struct nn_rmsg_chunk *chunk, struct nn_rbuf *rbuf) { chunk->rbuf = rbuf; chunk->next = NULL; - chunk->size = 0; + chunk->u.size = 0; ddsrt_atomic_inc32 (&rbuf->n_live_rmsg_chunks); } -struct nn_rmsg *nn_rmsg_new (struct nn_rbufpool *rbufpool) +struct nn_rmsg *nn_rmsg_new (struct nn_rbufpool *rbp) { /* Note: only one thread calls nn_rmsg_new on a pool */ struct nn_rmsg *rmsg; - DDS_LOG(DDS_LC_RADMIN, "rmsg_new(%p)\n", (void *) rbufpool); + RBPTRACE ("rmsg_new(%p)\n", (void *) rbp); - rmsg = nn_rbuf_alloc (rbufpool); + rmsg = nn_rbuf_alloc (rbp); if (rmsg == NULL) return NULL; /* Reference to this rmsg, undone by rmsg_commit(). */ ddsrt_atomic_st32 (&rmsg->refcount, RMSG_REFCOUNT_UNCOMMITTED_BIAS); /* Initial chunk */ - init_rmsg_chunk (&rmsg->chunk, rbufpool->current); + init_rmsg_chunk (&rmsg->chunk, rbp->current); + rmsg->trace = rbp->trace; rmsg->lastchunk = &rmsg->chunk; /* Incrementing freeptr happens in commit(), so that discarding the message is really simple. */ - DDS_LOG(DDS_LC_RADMIN, "rmsg_new(%p) = %p\n", (void *) rbufpool, (void *) rmsg); + RBPTRACE ("rmsg_new(%p) = %p\n", (void *) rbp, (void *) rmsg); return rmsg; } void nn_rmsg_setsize (struct nn_rmsg *rmsg, uint32_t size) { uint32_t size8 = align8uint32 (size); - DDS_LOG(DDS_LC_RADMIN, "rmsg_setsize(%p, %"PRIu32" => %"PRIu32")\n", (void *) rmsg, size, size8); + RMSGTRACE ("rmsg_setsize(%p, %"PRIu32" => %"PRIu32")\n", (void *) rmsg, size, size8); ASSERT_RBUFPOOL_OWNER (rmsg->chunk.rbuf->rbufpool); ASSERT_RMSG_UNCOMMITTED (rmsg); assert (ddsrt_atomic_ld32 (&rmsg->refcount) == RMSG_REFCOUNT_UNCOMMITTED_BIAS); - assert (rmsg->chunk.size == 0); + assert (rmsg->chunk.u.size == 0); assert (size8 <= rmsg->chunk.rbuf->max_rmsg_size); assert (rmsg->lastchunk == &rmsg->chunk); - rmsg->chunk.size = size8; + rmsg->chunk.u.size = size8; #if USE_VALGRIND VALGRIND_MEMPOOL_CHANGE (rmsg->chunk.rbuf->rbufpool, rmsg, rmsg, offsetof (struct nn_rmsg, chunk.u.payload) + rmsg->chunk.size); #endif @@ -563,7 +577,7 @@ void nn_rmsg_free (struct nn_rmsg *rmsg) free() which we don't do currently. And ideally, you'd use compare-and-swap for this. */ struct nn_rmsg_chunk *c; - DDS_LOG(DDS_LC_RADMIN, "rmsg_free(%p)\n", (void *) rmsg); + RMSGTRACE ("rmsg_free(%p)\n", (void *) rmsg); assert (ddsrt_atomic_ld32 (&rmsg->refcount) == 0); c = &rmsg->chunk; while (c) @@ -586,8 +600,8 @@ void nn_rmsg_free (struct nn_rmsg *rmsg) static void commit_rmsg_chunk (struct nn_rmsg_chunk *chunk) { struct nn_rbuf *rbuf = chunk->rbuf; - DDS_LOG(DDS_LC_RADMIN, "commit_rmsg_chunk(%p)\n", (void *) chunk); - rbuf->freeptr = chunk->u.payload + chunk->size; + RBUFTRACE ("commit_rmsg_chunk(%p)\n", (void *) chunk); + rbuf->freeptr = (unsigned char *) (chunk + 1) + chunk->u.size; } void nn_rmsg_commit (struct nn_rmsg *rmsg) @@ -601,12 +615,12 @@ void nn_rmsg_commit (struct nn_rmsg *rmsg) happens to be such that any asynchronous activities have completed before we got to commit. */ struct nn_rmsg_chunk *chunk = rmsg->lastchunk; - DDS_LOG(DDS_LC_RADMIN, "rmsg_commit(%p) refcount 0x%"PRIx32" last-chunk-size %"PRIu32"\n", - (void *) rmsg, rmsg->refcount.v, chunk->size); + RMSGTRACE ("rmsg_commit(%p) refcount 0x%"PRIx32" last-chunk-size %"PRIu32"\n", + (void *) rmsg, rmsg->refcount.v, chunk->u.size); ASSERT_RBUFPOOL_OWNER (chunk->rbuf->rbufpool); ASSERT_RMSG_UNCOMMITTED (rmsg); - assert (chunk->size <= chunk->rbuf->max_rmsg_size); - assert ((chunk->size % 8) == 0); + assert (chunk->u.size <= chunk->rbuf->max_rmsg_size); + assert ((chunk->u.size % 8) == 0); assert (ddsrt_atomic_ld32 (&rmsg->refcount) >= RMSG_REFCOUNT_UNCOMMITTED_BIAS); assert (ddsrt_atomic_ld32 (&rmsg->chunk.rbuf->n_live_rmsg_chunks) > 0); assert (ddsrt_atomic_ld32 (&chunk->rbuf->n_live_rmsg_chunks) > 0); @@ -617,7 +631,7 @@ void nn_rmsg_commit (struct nn_rmsg *rmsg) { /* Other references exist, so either stored in defrag, reorder and/or delivery queue */ - DDS_LOG(DDS_LC_RADMIN, "rmsg_commit(%p) => keep\n", (void *) rmsg); + RMSGTRACE ("rmsg_commit(%p) => keep\n", (void *) rmsg); commit_rmsg_chunk (chunk); } } @@ -630,7 +644,7 @@ static void nn_rmsg_addbias (struct nn_rmsg *rmsg) However, other threads (e.g., delivery threads) may have been triggered already, so the increment must be done atomically. */ - DDS_LOG(DDS_LC_RADMIN, "rmsg_addbias(%p)\n", (void *) rmsg); + RMSGTRACE ("rmsg_addbias(%p)\n", (void *) rmsg); ASSERT_RBUFPOOL_OWNER (rmsg->chunk.rbuf->rbufpool); ASSERT_RMSG_UNCOMMITTED (rmsg); ddsrt_atomic_add32 (&rmsg->refcount, RMSG_REFCOUNT_RDATA_BIAS); @@ -642,7 +656,7 @@ static void nn_rmsg_rmbias_and_adjust (struct nn_rmsg *rmsg, int adjust) progressing through the pipeline, but only by a receive thread. Can't require it to be uncommitted. */ uint32_t sub; - DDS_LOG(DDS_LC_RADMIN, "rmsg_rmbias_and_adjust(%p, %d)\n", (void *) rmsg, adjust); + RMSGTRACE ("rmsg_rmbias_and_adjust(%p, %d)\n", (void *) rmsg, adjust); assert (adjust >= 0); assert ((uint32_t) adjust < RMSG_REFCOUNT_RDATA_BIAS); sub = RMSG_REFCOUNT_RDATA_BIAS - (uint32_t) adjust; @@ -653,7 +667,7 @@ static void nn_rmsg_rmbias_and_adjust (struct nn_rmsg *rmsg, int adjust) static void nn_rmsg_unref (struct nn_rmsg *rmsg) { - DDS_LOG(DDS_LC_RADMIN, "rmsg_unref(%p)\n", (void *) rmsg); + RMSGTRACE ("rmsg_unref(%p)\n", (void *) rmsg); assert (ddsrt_atomic_ld32 (&rmsg->refcount) > 0); if (ddsrt_atomic_dec32_ov (&rmsg->refcount) == 1) nn_rmsg_free (rmsg); @@ -665,32 +679,32 @@ void *nn_rmsg_alloc (struct nn_rmsg *rmsg, uint32_t size) struct nn_rbuf *rbuf = chunk->rbuf; uint32_t size8 = align8uint32 (size); void *ptr; - DDS_LOG(DDS_LC_RADMIN, "rmsg_alloc(%p, %"PRIu32" => %"PRIu32")\n", (void *) rmsg, size, size8); + RMSGTRACE ("rmsg_alloc(%p, %"PRIu32" => %"PRIu32")\n", (void *) rmsg, size, size8); ASSERT_RBUFPOOL_OWNER (rbuf->rbufpool); ASSERT_RMSG_UNCOMMITTED (rmsg); - assert ((chunk->size % 8) == 0); + assert ((chunk->u.size % 8) == 0); assert (size8 <= rbuf->max_rmsg_size); - if (chunk->size + size8 > rbuf->max_rmsg_size) + if (chunk->u.size + size8 > rbuf->max_rmsg_size) { - struct nn_rbufpool *rbufpool = rbuf->rbufpool; + struct nn_rbufpool *rbp = rbuf->rbufpool; struct nn_rmsg_chunk *newchunk; - DDS_LOG(DDS_LC_RADMIN, "rmsg_alloc(%p, %"PRIu32") limit hit - new chunk\n", (void *) rmsg, size); + RMSGTRACE ("rmsg_alloc(%p, %"PRIu32") limit hit - new chunk\n", (void *) rmsg, size); commit_rmsg_chunk (chunk); - newchunk = nn_rbuf_alloc (rbufpool); + newchunk = nn_rbuf_alloc (rbp); if (newchunk == NULL) { - DDS_WARNING ("nn_rmsg_alloc: can't allocate more memory (%"PRIu32" bytes) ... giving up\n", size); + DDS_CWARNING (rbp->logcfg, "nn_rmsg_alloc: can't allocate more memory (%"PRIu32" bytes) ... giving up\n", size); return NULL; } - init_rmsg_chunk (newchunk, rbufpool->current); + init_rmsg_chunk (newchunk, rbp->current); rmsg->lastchunk = chunk->next = newchunk; chunk = newchunk; } - ptr = chunk->u.payload + chunk->size; - chunk->size += size8; - DDS_LOG(DDS_LC_RADMIN, "rmsg_alloc(%p, %"PRIu32") = %p\n", (void *) rmsg, size, ptr); + ptr = (unsigned char *) (chunk + 1) + chunk->u.size; + chunk->u.size += size8; + RMSGTRACE ("rmsg_alloc(%p, %"PRIu32") = %p\n", (void *) rmsg, size, ptr); #if USE_VALGRIND if (chunk == &rmsg->chunk) { VALGRIND_MEMPOOL_CHANGE (rbuf->rbufpool, rmsg, rmsg, offsetof (struct nn_rmsg, chunk.u.payload) + chunk->size); @@ -717,35 +731,39 @@ struct nn_rdata *nn_rdata_new (struct nn_rmsg *rmsg, uint32_t start, uint32_t en #ifndef NDEBUG ddsrt_atomic_st32 (&d->refcount_bias_added, 0); #endif - DDS_LOG(DDS_LC_RADMIN, "rdata_new(%p, bytes [%"PRIu32",%"PRIu32"), submsg @ %u, payload @ %u) = %p\n", (void *) rmsg, start, endp1, NN_RDATA_SUBMSG_OFF (d), NN_RDATA_PAYLOAD_OFF (d), (void *) d); + RMSGTRACE ("rdata_new(%p, bytes [%"PRIu32",%"PRIu32"), submsg @ %u, payload @ %u) = %p\n", + (void *) rmsg, start, endp1, NN_RDATA_SUBMSG_OFF (d), NN_RDATA_PAYLOAD_OFF (d), (void *) d); return d; } static void nn_rdata_addbias (struct nn_rdata *rdata) { - DDS_LOG(DDS_LC_RADMIN, "rdata_addbias(%p)\n", (void *) rdata); + struct nn_rmsg *rmsg = rdata->rmsg; + RMSGTRACE ("rdata_addbias(%p)\n", (void *) rdata); #ifndef NDEBUG - ASSERT_RBUFPOOL_OWNER (rdata->rmsg->chunk.rbuf->rbufpool); + ASSERT_RBUFPOOL_OWNER (rmsg->chunk.rbuf->rbufpool); if (ddsrt_atomic_inc32_nv (&rdata->refcount_bias_added) != 1) abort (); #endif - nn_rmsg_addbias (rdata->rmsg); + nn_rmsg_addbias (rmsg); } static void nn_rdata_rmbias_and_adjust (struct nn_rdata *rdata, int adjust) { - DDS_LOG(DDS_LC_RADMIN, "rdata_rmbias_and_adjust(%p, %d)\n", (void *) rdata, adjust); + struct nn_rmsg *rmsg = rdata->rmsg; + RMSGTRACE ("rdata_rmbias_and_adjust(%p, %d)\n", (void *) rdata, adjust); #ifndef NDEBUG if (ddsrt_atomic_dec32_ov (&rdata->refcount_bias_added) != 1) abort (); #endif - nn_rmsg_rmbias_and_adjust (rdata->rmsg, adjust); + nn_rmsg_rmbias_and_adjust (rmsg, adjust); } static void nn_rdata_unref (struct nn_rdata *rdata) { - DDS_LOG(DDS_LC_RADMIN, "rdata_rdata_unref(%p)\n", (void *) rdata); - nn_rmsg_unref (rdata->rmsg); + struct nn_rmsg *rmsg = rdata->rmsg; + RMSGTRACE ("rdata_rdata_unref(%p)\n", (void *) rdata); + nn_rmsg_unref (rmsg); } /* DEFRAG -------------------------------------------------------------- @@ -842,6 +860,8 @@ struct nn_defrag { uint32_t n_samples; uint32_t max_samples; enum nn_defrag_drop_mode drop_mode; + const struct ddsrt_log_cfg *logcfg; + bool trace; }; static int compare_uint32 (const void *va, const void *vb); @@ -864,7 +884,7 @@ static int compare_seqno (const void *va, const void *vb) return (a == b) ? 0 : (a < b) ? -1 : 1; } -struct nn_defrag *nn_defrag_new (enum nn_defrag_drop_mode drop_mode, uint32_t max_samples) +struct nn_defrag *nn_defrag_new (const struct ddsrt_log_cfg *logcfg, enum nn_defrag_drop_mode drop_mode, uint32_t max_samples) { struct nn_defrag *d; assert (max_samples >= 1); @@ -875,12 +895,14 @@ struct nn_defrag *nn_defrag_new (enum nn_defrag_drop_mode drop_mode, uint32_t ma d->max_samples = max_samples; d->n_samples = 0; d->max_sample = NULL; + d->logcfg = logcfg; + d->trace = (logcfg->c.mask & DDS_LC_RADMIN) != 0; return d; } void nn_fragchain_adjust_refcount (struct nn_rdata *frag, int adjust) { - DDS_LOG(DDS_LC_RADMIN, "fragchain_adjust_refcount(%p, %d)\n", (void *) frag, adjust); + RDATATRACE (frag, "fragchain_adjust_refcount(%p, %d)\n", (void *) frag, adjust); while (frag) { struct nn_rdata * const frag1 = frag->nextfrag; @@ -905,12 +927,16 @@ static void defrag_rsample_drop (struct nn_defrag *defrag, struct nn_rsample *rs inorder treewalk does provide. */ ddsrt_avl_iter_t iter; struct nn_defrag_iv *iv; - DDS_LOG(DDS_LC_RADMIN, " defrag_rsample_drop (%p, %p)\n", (void *) defrag, (void *) rsample); + TRACE (defrag, " defrag_rsample_drop (%p, %p)\n", (void *) defrag, (void *) rsample); ddsrt_avl_delete (&defrag_sampletree_treedef, &defrag->sampletree, rsample); assert (defrag->n_samples > 0); defrag->n_samples--; for (iv = ddsrt_avl_iter_first (&rsample_defrag_fragtree_treedef, &rsample->u.defrag.fragtree, &iter); iv; iv = ddsrt_avl_iter_next (&iter)) - nn_fragchain_rmbias (iv->first); + { + if (iv->first) + /* if the first fragment is missing, a sentinel "iv" is inserted with an empty chain */ + nn_fragchain_rmbias (iv->first); + } } void nn_defrag_free (struct nn_defrag *defrag) @@ -919,7 +945,7 @@ void nn_defrag_free (struct nn_defrag *defrag) s = ddsrt_avl_find_min (&defrag_sampletree_treedef, &defrag->sampletree); while (s) { - DDS_LOG(DDS_LC_RADMIN, "defrag_free(%p, sample %p seq %"PRId64")\n", (void *) defrag, (void *) s, s->u.defrag.seq); + TRACE (defrag, "defrag_free(%p, sample %p seq %"PRId64")\n", (void *) defrag, (void *) s, s->u.defrag.seq); defrag_rsample_drop (defrag, s); s = ddsrt_avl_find_min (&defrag_sampletree_treedef, &defrag->sampletree); } @@ -927,25 +953,24 @@ void nn_defrag_free (struct nn_defrag *defrag) ddsrt_free (defrag); } -static int defrag_try_merge_with_succ (struct nn_rsample_defrag *sample, struct nn_defrag_iv *node) +static int defrag_try_merge_with_succ (const struct nn_defrag *defrag, struct nn_rsample_defrag *sample, struct nn_defrag_iv *node) { struct nn_defrag_iv *succ; - DDS_LOG(DDS_LC_RADMIN, " defrag_try_merge_with_succ(%p [%"PRIu32"..%"PRIu32")):\n", - (void *) node, node->min, node->maxp1); + TRACE (defrag, " defrag_try_merge_with_succ(%p [%"PRIu32"..%"PRIu32")):\n", (void *) node, node->min, node->maxp1); if (node == sample->lastfrag) { /* there is no interval following node */ - DDS_LOG(DDS_LC_RADMIN, " node is lastfrag\n"); + TRACE (defrag, " node is lastfrag\n"); return 0; } succ = ddsrt_avl_find_succ (&rsample_defrag_fragtree_treedef, &sample->fragtree, node); assert (succ != NULL); - DDS_LOG(DDS_LC_RADMIN, " succ is %p [%"PRIu32"..%"PRIu32")\n", (void *) succ, succ->min, succ->maxp1); + TRACE (defrag, " succ is %p [%"PRIu32"..%"PRIu32")\n", (void *) succ, succ->min, succ->maxp1); if (succ->min > node->maxp1) { - DDS_LOG(DDS_LC_RADMIN, " gap between node and succ\n"); + TRACE (defrag, " gap between node and succ\n"); return 0; } else @@ -958,7 +983,7 @@ static int defrag_try_merge_with_succ (struct nn_rsample_defrag *sample, struct ddsrt_avl_delete (&rsample_defrag_fragtree_treedef, &sample->fragtree, succ); if (sample->lastfrag == succ) { - DDS_LOG(DDS_LC_RADMIN, " succ is lastfrag\n"); + TRACE (defrag, " succ is lastfrag\n"); sample->lastfrag = node; } @@ -973,9 +998,9 @@ static int defrag_try_merge_with_succ (struct nn_rsample_defrag *sample, struct references to rmsgs of the rdata in succ, freeing it may cause the rsample to be freed as well. */ if (node->maxp1 < succ_maxp1) - DDS_LOG(DDS_LC_RADMIN, " succ adds data to node\n"); + TRACE (defrag, " succ adds data to node\n"); else - DDS_LOG(DDS_LC_RADMIN, " succ is contained in node\n"); + TRACE (defrag, " succ is contained in node\n"); node->last->nextfrag = succ->first; node->last = succ->last; @@ -1129,7 +1154,7 @@ static void rsample_convert_defrag_to_reorder (struct nn_rsample *sample) sample->u.reorder.n_samples = 1; } -static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo) +static struct nn_rsample *defrag_add_fragment (const struct nn_defrag *defrag, struct nn_rsample *sample, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo) { struct nn_rsample_defrag *dfsample = &sample->u.defrag; struct nn_defrag_iv *predeq, *succ; @@ -1147,9 +1172,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct /* relatively expensive test: lastfrag, tree must be consistent */ assert (dfsample->lastfrag == ddsrt_avl_find_max (&rsample_defrag_fragtree_treedef, &dfsample->fragtree)); - DDS_LOG(DDS_LC_RADMIN, " lastfrag %p [%"PRIu32"..%"PRIu32")\n", - (void *) dfsample->lastfrag, - dfsample->lastfrag->min, dfsample->lastfrag->maxp1); + TRACE (defrag, " lastfrag %p [%"PRIu32"..%"PRIu32")\n", (void *) dfsample->lastfrag, dfsample->lastfrag->min, dfsample->lastfrag->maxp1); /* Interval tree is sorted on min offset; each key is unique: otherwise one would be wholly contained in another. */ @@ -1157,15 +1180,14 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct { /* Assumed normal case: fragment appends data */ predeq = dfsample->lastfrag; - DDS_LOG(DDS_LC_RADMIN, " fast path: predeq = lastfrag\n"); + TRACE (defrag, " fast path: predeq = lastfrag\n"); } else { /* Slow path: find preceding fragment by tree search */ predeq = ddsrt_avl_lookup_pred_eq (&rsample_defrag_fragtree_treedef, &dfsample->fragtree, &min); assert (predeq); - DDS_LOG(DDS_LC_RADMIN, " slow path: predeq = lookup %"PRIu32" => %p [%"PRIu32"..%"PRIu32")\n", - min, (void *) predeq, predeq->min, predeq->maxp1); + TRACE (defrag, " slow path: predeq = lookup %"PRIu32" => %p [%"PRIu32"..%"PRIu32")\n", min, (void *) predeq, predeq->min, predeq->maxp1); } /* we have a sentinel interval of [0,0) until we receive a packet @@ -1177,7 +1199,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct { /* new is contained in predeq, discard new; rdata did not cause completion of a sample */ - DDS_LOG(DDS_LC_RADMIN, " new contained in predeq\n"); + TRACE (defrag, " new contained in predeq\n"); return NULL; } else if (min <= predeq->maxp1) @@ -1185,7 +1207,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct /* new extends predeq, add it to the chain (necessarily at the end); this may close the gap to the successor of predeq; predeq need not have a fragment chain yet (it may be the sentinel) */ - DDS_LOG(DDS_LC_RADMIN, " grow predeq with new\n"); + TRACE (defrag, " grow predeq with new\n"); nn_rdata_addbias (rdata); rdata->nextfrag = NULL; if (predeq->first) @@ -1201,7 +1223,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct predeq->last = rdata; predeq->maxp1 = maxp1; /* it may now be possible to merge with the successor */ - while (defrag_try_merge_with_succ (dfsample, predeq)) + while (defrag_try_merge_with_succ (defrag, dfsample, predeq)) ; return is_complete (dfsample) ? sample : NULL; } @@ -1213,8 +1235,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct fragment in the chain adds value); but doesn't overlap with predeq so the tree structure doesn't change even though the key does change */ - DDS_LOG(DDS_LC_RADMIN, " extending succ %p [%"PRIu32"..%"PRIu32") at head\n", - (void *) succ, succ->min, succ->maxp1); + TRACE (defrag, " extending succ %p [%"PRIu32"..%"PRIu32") at head\n", (void *) succ, succ->min, succ->maxp1); nn_rdata_addbias (rdata); rdata->nextfrag = succ->first; succ->first = rdata; @@ -1224,9 +1245,9 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct succ-succ */ if (maxp1 > succ->maxp1) { - DDS_LOG(DDS_LC_RADMIN, " extending succ at end as well\n"); + TRACE (defrag, " extending succ at end as well\n"); succ->maxp1 = maxp1; - while (defrag_try_merge_with_succ (dfsample, succ)) + while (defrag_try_merge_with_succ (defrag, dfsample, succ)) ; } assert (!is_complete (dfsample)); @@ -1237,7 +1258,7 @@ static struct nn_rsample *defrag_add_fragment (struct nn_rsample *sample, struct /* doesn't extend either predeq at the end or succ at the head => new interval; rdata did not cause completion of sample */ ddsrt_avl_ipath_t path; - DDS_LOG(DDS_LC_RADMIN, " new interval\n"); + TRACE (defrag, " new interval\n"); if (ddsrt_avl_lookup_ipath (&rsample_defrag_fragtree_treedef, &dfsample->fragtree, &min, &path)) assert (0); defrag_rsample_addiv (dfsample, rdata, &path); @@ -1260,25 +1281,25 @@ static int defrag_limit_samples (struct nn_defrag *defrag, seqno_t seq, seqno_t return 1; /* max_samples >= 1 => some sample present => max_sample != NULL */ assert (defrag->max_sample != NULL); - DDS_LOG(DDS_LC_RADMIN, " max samples reached\n"); + TRACE (defrag, " max samples reached\n"); switch (defrag->drop_mode) { case NN_DEFRAG_DROP_LATEST: - DDS_LOG(DDS_LC_RADMIN, " drop mode = DROP_LATEST\n"); + TRACE (defrag, " drop mode = DROP_LATEST\n"); if (seq > defrag->max_sample->u.defrag.seq) { - DDS_LOG(DDS_LC_RADMIN, " new sample is new latest => discarding it\n"); + TRACE (defrag, " new sample is new latest => discarding it\n"); return 0; } sample_to_drop = defrag->max_sample; break; case NN_DEFRAG_DROP_OLDEST: - DDS_LOG(DDS_LC_RADMIN, " drop mode = DROP_OLDEST\n"); + TRACE (defrag, " drop mode = DROP_OLDEST\n"); sample_to_drop = ddsrt_avl_find_min (&defrag_sampletree_treedef, &defrag->sampletree); assert (sample_to_drop); if (seq < sample_to_drop->u.defrag.seq) { - DDS_LOG(DDS_LC_RADMIN, " new sample is new oldest => discarding it\n"); + TRACE (defrag, " new sample is new oldest => discarding it\n"); return 0; } break; @@ -1289,9 +1310,8 @@ static int defrag_limit_samples (struct nn_defrag *defrag, seqno_t seq, seqno_t { defrag->max_sample = ddsrt_avl_find_max (&defrag_sampletree_treedef, &defrag->sampletree); *max_seq = defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0; - DDS_LOG(DDS_LC_RADMIN, " updating max_sample: now %p %"PRId64"\n", - (void *) defrag->max_sample, - defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0); + TRACE (defrag, " updating max_sample: now %p %"PRId64"\n", + (void *) defrag->max_sample, defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0); } return 1; } @@ -1336,20 +1356,20 @@ struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata consistent. Max_sample must be consistent with tree */ assert (defrag->max_sample == ddsrt_avl_find_max (&defrag_sampletree_treedef, &defrag->sampletree)); max_seq = defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0; - DDS_LOG(DDS_LC_RADMIN, "defrag_rsample(%p, %p [%"PRIu32"..%"PRIu32") msg %p, %p seq %"PRId64" size %"PRIu32") max_seq %p %"PRId64":\n", - (void *) defrag, (void *) rdata, rdata->min, rdata->maxp1, (void *) rdata->rmsg, - (void *) sampleinfo, sampleinfo->seq, sampleinfo->size, - (void *) defrag->max_sample, max_seq); + TRACE (defrag, "defrag_rsample(%p, %p [%"PRIu32"..%"PRIu32") msg %p, %p seq %"PRId64" size %"PRIu32") max_seq %p %"PRId64":\n", + (void *) defrag, (void *) rdata, rdata->min, rdata->maxp1, (void *) rdata->rmsg, + (void *) sampleinfo, sampleinfo->seq, sampleinfo->size, + (void *) defrag->max_sample, max_seq); /* fast path: rdata is part of message with the highest sequence number we're currently defragmenting, or is beyond that */ if (sampleinfo->seq == max_seq) { - DDS_LOG(DDS_LC_RADMIN, " add fragment to max_sample\n"); - result = defrag_add_fragment (defrag->max_sample, rdata, sampleinfo); + TRACE (defrag, " add fragment to max_sample\n"); + result = defrag_add_fragment (defrag, defrag->max_sample, rdata, sampleinfo); } else if (!defrag_limit_samples (defrag, sampleinfo->seq, &max_seq)) { - DDS_LOG(DDS_LC_RADMIN, " discarding sample\n"); + TRACE (defrag, " discarding sample\n"); result = NULL; } else if (sampleinfo->seq > max_seq) @@ -1357,7 +1377,7 @@ struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata /* a node with a key greater than the maximum always is the right child of the old maximum node */ /* FIXME: MERGE THIS ONE WITH THE NEXT */ - DDS_LOG(DDS_LC_RADMIN, " new max sample\n"); + TRACE (defrag, " new max sample\n"); ddsrt_avl_lookup_ipath (&defrag_sampletree_treedef, &defrag->sampletree, &sampleinfo->seq, &path); if ((sample = defrag_rsample_new (rdata, sampleinfo)) == NULL) return NULL; @@ -1369,7 +1389,7 @@ struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata else if ((sample = ddsrt_avl_lookup_ipath (&defrag_sampletree_treedef, &defrag->sampletree, &sampleinfo->seq, &path)) == NULL) { /* a new sequence number, but smaller than the maximum */ - DDS_LOG(DDS_LC_RADMIN, " new sample less than max\n"); + TRACE (defrag, " new sample less than max\n"); assert (sampleinfo->seq < max_seq); if ((sample = defrag_rsample_new (rdata, sampleinfo)) == NULL) return NULL; @@ -1380,8 +1400,8 @@ struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata else { /* adds (or, as the case may be, doesn't add) to a known message */ - DDS_LOG(DDS_LC_RADMIN, " add fragment to %p\n", (void *) sample); - result = defrag_add_fragment (sample, rdata, sampleinfo); + TRACE (defrag, " add fragment to %p\n", (void *) sample); + result = defrag_add_fragment (defrag, sample, rdata, sampleinfo); } if (result != NULL) @@ -1389,16 +1409,15 @@ struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata /* Once completed, remove from defrag sample tree and convert to reorder format. If it is the sample with the maximum sequence in the tree, an update of max_sample is required. */ - DDS_LOG(DDS_LC_RADMIN, " complete\n"); + TRACE (defrag, " complete\n"); ddsrt_avl_delete (&defrag_sampletree_treedef, &defrag->sampletree, result); assert (defrag->n_samples > 0); defrag->n_samples--; if (result == defrag->max_sample) { defrag->max_sample = ddsrt_avl_find_max (&defrag_sampletree_treedef, &defrag->sampletree); - DDS_LOG(DDS_LC_RADMIN, " updating max_sample: now %p %"PRId64"\n", - (void *) defrag->max_sample, - defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0); + TRACE (defrag, " updating max_sample: now %p %"PRId64"\n", + (void *) defrag->max_sample, defrag->max_sample ? defrag->max_sample->u.defrag.seq : 0); } rsample_convert_defrag_to_reorder (result); } @@ -1422,7 +1441,7 @@ void nn_defrag_notegap (struct nn_defrag *defrag, seqno_t min, seqno_t maxp1) defrag->max_sample = ddsrt_avl_find_max (&defrag_sampletree_treedef, &defrag->sampletree); } -int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set *map, uint32_t maxsz) +int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set_header *map, uint32_t *mapbits, uint32_t maxsz) { struct nn_rsample *s; struct nn_defrag_iv *iv; @@ -1446,7 +1465,7 @@ int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnu else map->numbits = maxfragnum + 1; map->bitmap_base = 0; - nn_bitset_one (map->numbits, map->bits); + nn_bitset_one (map->numbits, mapbits); return (int) map->numbits; } } @@ -1491,7 +1510,7 @@ int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnu /* Clear bitmap, then set bits for gaps in available fragments */ if (map->numbits > maxsz) map->numbits = maxsz; - nn_bitset_zero (map->numbits, map->bits); + nn_bitset_zero (map->numbits, mapbits); i = map->bitmap_base; while (iv && i < map->bitmap_base + map->numbits) { @@ -1509,7 +1528,7 @@ int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnu for (; i < map->bitmap_base + map->numbits && i < bound; i++) { unsigned x = (unsigned) (i - map->bitmap_base); - nn_bitset_set (map->numbits, map->bits, x); + nn_bitset_set (map->numbits, mapbits, x); } /* next sequence of fragments to request retranmsission of starts at fragment containing maxp1 (because we don't have that byte @@ -1521,7 +1540,7 @@ int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnu for (; i < map->bitmap_base + map->numbits; i++) { unsigned x = (unsigned) (i - map->bitmap_base); - nn_bitset_set (map->numbits, map->bits, x); + nn_bitset_set (map->numbits, mapbits, x); } return (int) map->numbits; } @@ -1609,12 +1628,15 @@ struct nn_reorder { enum nn_reorder_mode mode; uint32_t max_samples; uint32_t n_samples; + const struct ddsrt_log_cfg *logcfg; + bool late_ack_mode; + bool trace; }; static const ddsrt_avl_treedef_t reorder_sampleivtree_treedef = DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct nn_rsample, u.reorder.avlnode), offsetof (struct nn_rsample, u.reorder.min), compare_seqno, 0); -struct nn_reorder *nn_reorder_new (enum nn_reorder_mode mode, uint32_t max_samples) +struct nn_reorder *nn_reorder_new (const struct ddsrt_log_cfg *logcfg, enum nn_reorder_mode mode, uint32_t max_samples, bool late_ack_mode) { struct nn_reorder *r; if ((r = ddsrt_malloc (sizeof (*r))) == NULL) @@ -1625,6 +1647,9 @@ struct nn_reorder *nn_reorder_new (enum nn_reorder_mode mode, uint32_t max_sampl r->mode = mode; r->max_samples = max_samples; r->n_samples = 0; + r->late_ack_mode = late_ack_mode; + r->logcfg = logcfg; + r->trace = (logcfg->c.mask & DDS_LC_RADMIN) != 0; return r; } @@ -1695,28 +1720,28 @@ static int reorder_try_append_and_discard (struct nn_reorder *reorder, struct nn { if (todiscard == NULL) { - DDS_LOG(DDS_LC_RADMIN, " try_append_and_discard: fail: todiscard = NULL\n"); + TRACE (reorder, " try_append_and_discard: fail: todiscard = NULL\n"); return 0; } else if (appendto->u.reorder.maxp1 < todiscard->u.reorder.min) { - DDS_LOG(DDS_LC_RADMIN, " try_append_and_discard: fail: appendto = [%"PRId64",%"PRId64") @ %p, " - "todiscard = [%"PRId64",%"PRId64") @ %p - gap\n", - appendto->u.reorder.min, appendto->u.reorder.maxp1, (void *) appendto, - todiscard->u.reorder.min, todiscard->u.reorder.maxp1, (void *) todiscard); + TRACE (reorder, " try_append_and_discard: fail: appendto = [%"PRId64",%"PRId64") @ %p, " + "todiscard = [%"PRId64",%"PRId64") @ %p - gap\n", + appendto->u.reorder.min, appendto->u.reorder.maxp1, (void *) appendto, + todiscard->u.reorder.min, todiscard->u.reorder.maxp1, (void *) todiscard); return 0; } else { - DDS_LOG(DDS_LC_RADMIN, " try_append_and_discard: success: appendto = [%"PRId64",%"PRId64") @ %p, " - "todiscard = [%"PRId64",%"PRId64") @ %p\n", - appendto->u.reorder.min, appendto->u.reorder.maxp1, (void *) appendto, - todiscard->u.reorder.min, todiscard->u.reorder.maxp1, (void *) todiscard); + TRACE (reorder, " try_append_and_discard: success: appendto = [%"PRId64",%"PRId64") @ %p, " + "todiscard = [%"PRId64",%"PRId64") @ %p\n", + appendto->u.reorder.min, appendto->u.reorder.maxp1, (void *) appendto, + todiscard->u.reorder.min, todiscard->u.reorder.maxp1, (void *) todiscard); assert (todiscard->u.reorder.min == appendto->u.reorder.maxp1); ddsrt_avl_delete (&reorder_sampleivtree_treedef, &reorder->sampleivtree, todiscard); append_rsample_interval (appendto, todiscard); - DDS_LOG(DDS_LC_RADMIN, " try_append_and_discard: max_sampleiv needs update? %s\n", - (todiscard == reorder->max_sampleiv) ? "yes" : "no"); + TRACE (reorder, " try_append_and_discard: max_sampleiv needs update? %s\n", + (todiscard == reorder->max_sampleiv) ? "yes" : "no"); /* Inform caller whether reorder->max must be updated -- the expected thing to do is to update it to appendto here, but that fails if appendto isn't actually in the tree. And that happens @@ -1726,7 +1751,7 @@ static int reorder_try_append_and_discard (struct nn_reorder *reorder, struct nn } } -struct nn_rsample *nn_reorder_rsample_dup (struct nn_rmsg *rmsg, struct nn_rsample *rsampleiv) +struct nn_rsample *nn_reorder_rsample_dup_first (struct nn_rmsg *rmsg, struct nn_rsample *rsampleiv) { /* Duplicates the rsampleiv without updating any reference counts: that is left to the caller, as they do not need to be updated if @@ -1738,7 +1763,6 @@ struct nn_rsample *nn_reorder_rsample_dup (struct nn_rmsg *rmsg, struct nn_rsamp rsampleiv. */ struct nn_rsample *rsampleiv_new; struct nn_rsample_chain_elem *sce; - assert (rsample_is_singleton (&rsampleiv->u.reorder)); #ifndef NDEBUG { struct nn_rdata *d = rsampleiv->u.reorder.sc.first->fragchain; @@ -1754,7 +1778,9 @@ struct nn_rsample *nn_reorder_rsample_dup (struct nn_rmsg *rmsg, struct nn_rsamp sce->fragchain = rsampleiv->u.reorder.sc.first->fragchain; sce->next = NULL; sce->sampleinfo = rsampleiv->u.reorder.sc.first->sampleinfo; - *rsampleiv_new = *rsampleiv; + rsampleiv_new->u.reorder.min = rsampleiv->u.reorder.min; + rsampleiv_new->u.reorder.maxp1 = rsampleiv_new->u.reorder.min + 1; + rsampleiv_new->u.reorder.n_samples = 1; rsampleiv_new->u.reorder.sc.first = rsampleiv_new->u.reorder.sc.last = sce; return rsampleiv_new; } @@ -1791,7 +1817,7 @@ static void delete_last_sample (struct nn_reorder *reorder) { /* Last sample is in an interval of its own - delete it, and recalc max_sampleiv. */ - DDS_LOG(DDS_LC_RADMIN, " delete_last_sample: in singleton interval\n"); + TRACE (reorder, " delete_last_sample: in singleton interval\n"); fragchain = last->sc.first->fragchain; ddsrt_avl_delete (&reorder_sampleivtree_treedef, &reorder->sampleivtree, reorder->max_sampleiv); reorder->max_sampleiv = ddsrt_avl_find_max (&reorder_sampleivtree_treedef, &reorder->sampleivtree); @@ -1807,8 +1833,7 @@ static void delete_last_sample (struct nn_reorder *reorder) large!). Can't be a singleton list, so might as well chop off one evaluation of the loop condition. */ struct nn_rsample_chain_elem *e, *pe; - DDS_LOG(DDS_LC_RADMIN, " delete_last_sample: scanning last interval [%"PRId64"..%"PRId64")\n", - last->min, last->maxp1); + TRACE (reorder, " delete_last_sample: scanning last interval [%"PRId64"..%"PRId64")\n", last->min, last->maxp1); assert (last->n_samples >= 1); assert (last->min + last->n_samples <= last->maxp1); e = last->sc.first; @@ -1838,7 +1863,9 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r refcount_adjust is incremented if the sample is not discarded. */ struct nn_rsample_reorder *s = &rsampleiv->u.reorder; - DDS_LOG(DDS_LC_RADMIN, "reorder_sample(%p %c, %"PRId64" @ %p) expecting %"PRId64":\n", (void *) reorder, reorder_mode_as_char (reorder), rsampleiv->u.reorder.min, (void *) rsampleiv, reorder->next_seq); + TRACE (reorder, "reorder_sample(%p %c, %"PRId64" @ %p) expecting %"PRId64":\n", + (void *) reorder, reorder_mode_as_char (reorder), rsampleiv->u.reorder.min, + (void *) rsampleiv, reorder->next_seq); /* Incoming rsample must be a singleton */ assert (rsample_is_singleton (s)); @@ -1849,7 +1876,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r { struct nn_rsample *min = ddsrt_avl_find_min (&reorder_sampleivtree_treedef, &reorder->sampleivtree); if (min) - DDS_LOG(DDS_LC_RADMIN, " min = %"PRId64" @ %p\n", min->u.reorder.min, (void *) min); + TRACE (reorder, " min = %"PRId64" @ %p\n", min->u.reorder.min, (void *) min); assert (min == NULL || reorder->next_seq < min->u.reorder.min); assert ((reorder->max_sampleiv == NULL && min == NULL) || (reorder->max_sampleiv != NULL && min != NULL)); @@ -1859,7 +1886,8 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r assert (reorder->max_sampleiv == NULL || reorder->max_sampleiv == ddsrt_avl_find_max (&reorder_sampleivtree_treedef, &reorder->sampleivtree)); assert (reorder->n_samples <= reorder->max_samples); if (reorder->max_sampleiv) - DDS_LOG(DDS_LC_RADMIN, " max = [%"PRId64",%"PRId64") @ %p\n", reorder->max_sampleiv->u.reorder.min, reorder->max_sampleiv->u.reorder.maxp1, (void *) reorder->max_sampleiv); + TRACE (reorder, " max = [%"PRId64",%"PRId64") @ %p\n", reorder->max_sampleiv->u.reorder.min, + reorder->max_sampleiv->u.reorder.maxp1, (void *) reorder->max_sampleiv); if (s->min == reorder->next_seq || (s->min > reorder->next_seq && reorder->mode == NN_REORDER_MODE_MONOTONICALLY_INCREASING) || @@ -1873,7 +1901,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r admin, or things go wrong very quickly.) */ if (delivery_queue_full_p) { - DDS_LOG(DDS_LC_RADMIN, " discarding deliverable sample: delivery queue is full\n"); + TRACE (reorder, " discarding deliverable sample: delivery queue is full\n"); return NN_REORDER_REJECT; } @@ -1884,14 +1912,14 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r if (reorder->max_sampleiv != NULL) { struct nn_rsample *min = ddsrt_avl_find_min (&reorder_sampleivtree_treedef, &reorder->sampleivtree); - DDS_LOG(DDS_LC_RADMIN, " try append_and_discard\n"); + TRACE (reorder, " try append_and_discard\n"); if (reorder_try_append_and_discard (reorder, rsampleiv, min)) reorder->max_sampleiv = NULL; } reorder->next_seq = s->maxp1; *sc = rsampleiv->u.reorder.sc; (*refcount_adjust)++; - DDS_LOG(DDS_LC_RADMIN, " return [%"PRId64",%"PRId64")\n", s->min, s->maxp1); + TRACE (reorder, " return [%"PRId64",%"PRId64")\n", s->min, s->maxp1); /* Adjust reorder->n_samples, new sample is not counted yet */ assert (s->maxp1 - s->min >= 1); @@ -1905,7 +1933,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r { /* we've moved beyond this one: discard it; no need to adjust n_samples */ - DDS_LOG(DDS_LC_RADMIN, " discard: too old\n"); + TRACE (reorder, " discard: too old\n"); return NN_REORDER_TOO_OLD; /* don't want refcount increment */ } else if (ddsrt_avl_is_empty (&reorder->sampleivtree)) @@ -1914,10 +1942,10 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r is technically allowed, and potentially useful, so check for it */ assert (reorder->n_samples == 0); - DDS_LOG(DDS_LC_RADMIN, " adding to empty store\n"); + TRACE (reorder, " adding to empty store\n"); if (reorder->max_samples == 0) { - DDS_LOG(DDS_LC_RADMIN, " NOT - max_samples hit\n"); + TRACE (reorder, " NOT - max_samples hit\n"); return NN_REORDER_REJECT; } else @@ -1933,12 +1961,12 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r if (delivery_queue_full_p) { /* growing last inteval will not be accepted when this flag is set */ - DDS_LOG(DDS_LC_RADMIN, " discarding sample: only accepting delayed samples due to backlog in delivery queue\n"); + TRACE (reorder, " discarding sample: only accepting delayed samples due to backlog in delivery queue\n"); return NN_REORDER_REJECT; } /* grow the last interval, if we're still accepting samples */ - DDS_LOG(DDS_LC_RADMIN, " growing last interval\n"); + TRACE (reorder, " growing last interval\n"); if (reorder->n_samples < reorder->max_samples) { append_rsample_interval (reorder->max_sampleiv, rsampleiv); @@ -1946,7 +1974,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r } else { - DDS_LOG(DDS_LC_RADMIN, " discarding sample: max_samples reached and sample at end\n"); + TRACE (reorder, " discarding sample: max_samples reached and sample at end\n"); return NN_REORDER_REJECT; } } @@ -1955,19 +1983,19 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r if (delivery_queue_full_p) { /* new interval at the end will not be accepted when this flag is set */ - DDS_LOG(DDS_LC_RADMIN, " discarding sample: only accepting delayed samples due to backlog in delivery queue\n"); + TRACE (reorder, " discarding sample: only accepting delayed samples due to backlog in delivery queue\n"); return NN_REORDER_REJECT; } if (reorder->n_samples < reorder->max_samples) { - DDS_LOG(DDS_LC_RADMIN, " new interval at end\n"); + TRACE (reorder, " new interval at end\n"); reorder_add_rsampleiv (reorder, rsampleiv); reorder->max_sampleiv = rsampleiv; reorder->n_samples++; } else { - DDS_LOG(DDS_LC_RADMIN, " discarding sample: max_samples reached and sample at end\n"); + TRACE (reorder, " discarding sample: max_samples reached and sample at end\n"); return NN_REORDER_REJECT; } } @@ -1981,37 +2009,37 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r - if immsucc exists we can prepend s to immsucc - and possibly join predeq, s, and immsucc */ struct nn_rsample *predeq, *immsucc; - DDS_LOG(DDS_LC_RADMIN, " hard case ...\n"); + TRACE (reorder, " hard case ...\n"); - if (config.late_ack_mode && delivery_queue_full_p) + if (reorder->late_ack_mode && delivery_queue_full_p) { - DDS_LOG(DDS_LC_RADMIN, " discarding sample: delivery queue full\n"); + TRACE (reorder, " discarding sample: delivery queue full\n"); return NN_REORDER_REJECT; } predeq = ddsrt_avl_lookup_pred_eq (&reorder_sampleivtree_treedef, &reorder->sampleivtree, &s->min); if (predeq) - DDS_LOG(DDS_LC_RADMIN, " predeq = [%"PRId64",%"PRId64") @ %p\n", - predeq->u.reorder.min, predeq->u.reorder.maxp1, (void *) predeq); + TRACE (reorder, " predeq = [%"PRId64",%"PRId64") @ %p\n", + predeq->u.reorder.min, predeq->u.reorder.maxp1, (void *) predeq); else - DDS_LOG(DDS_LC_RADMIN, " predeq = null\n"); + TRACE (reorder, " predeq = null\n"); if (predeq && s->min >= predeq->u.reorder.min && s->min < predeq->u.reorder.maxp1) { /* contained in predeq */ - DDS_LOG(DDS_LC_RADMIN, " discard: contained in predeq\n"); + TRACE (reorder, " discard: contained in predeq\n"); return NN_REORDER_REJECT; } immsucc = ddsrt_avl_lookup (&reorder_sampleivtree_treedef, &reorder->sampleivtree, &s->maxp1); if (immsucc) - DDS_LOG(DDS_LC_RADMIN, " immsucc = [%"PRId64",%"PRId64") @ %p\n", - immsucc->u.reorder.min, immsucc->u.reorder.maxp1, (void *) immsucc); + TRACE (reorder, " immsucc = [%"PRId64",%"PRId64") @ %p\n", + immsucc->u.reorder.min, immsucc->u.reorder.maxp1, (void *) immsucc); else - DDS_LOG(DDS_LC_RADMIN, " immsucc = null\n"); + TRACE (reorder, " immsucc = null\n"); if (predeq && s->min == predeq->u.reorder.maxp1) { /* grow predeq at end, and maybe append immsucc as well */ - DDS_LOG(DDS_LC_RADMIN, " growing predeq at end ...\n"); + TRACE (reorder, " growing predeq at end ...\n"); append_rsample_interval (predeq, rsampleiv); if (reorder_try_append_and_discard (reorder, predeq, immsucc)) reorder->max_sampleiv = predeq; @@ -2021,7 +2049,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r /* no predecessor, grow immsucc at head, which _does_ alter the key of the node in the tree, but _doesn't_ change the tree's structure. */ - DDS_LOG(DDS_LC_RADMIN, " growing immsucc at head\n"); + TRACE (reorder, " growing immsucc at head\n"); s->sc.last->next = immsucc->u.reorder.sc.first; immsucc->u.reorder.sc.first = s->sc.first; immsucc->u.reorder.min = s->min; @@ -2047,7 +2075,7 @@ nn_reorder_result_t nn_reorder_rsample (struct nn_rsample_chain *sc, struct nn_r else { /* neither extends predeq nor immsucc */ - DDS_LOG(DDS_LC_RADMIN, " new interval\n"); + TRACE (reorder, " new interval\n"); reorder_add_rsampleiv (reorder, rsampleiv); } @@ -2174,18 +2202,18 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord struct nn_rsample *coalesced; int valuable; - DDS_LOG(DDS_LC_RADMIN, "reorder_gap(%p %c, [%"PRId64",%"PRId64") data %p) expecting %"PRId64":\n", - (void *) reorder, reorder_mode_as_char (reorder), - min, maxp1, (void *) rdata, reorder->next_seq); + TRACE (reorder, "reorder_gap(%p %c, [%"PRId64",%"PRId64") data %p) expecting %"PRId64":\n", + (void *) reorder, reorder_mode_as_char (reorder), + min, maxp1, (void *) rdata, reorder->next_seq); if (maxp1 <= reorder->next_seq) { - DDS_LOG(DDS_LC_RADMIN, " too old\n"); + TRACE (reorder, " too old\n"); return NN_REORDER_TOO_OLD; } if (reorder->mode != NN_REORDER_MODE_NORMAL) { - DDS_LOG(DDS_LC_RADMIN, " special mode => don't care\n"); + TRACE (reorder, " special mode => don't care\n"); return NN_REORDER_REJECT; } @@ -2193,10 +2221,10 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord if ((coalesced = coalesce_intervals_touching_range (reorder, min, maxp1, &valuable)) == NULL) { nn_reorder_result_t res; - DDS_LOG(DDS_LC_RADMIN, " coalesced = null\n"); + TRACE (reorder, " coalesced = null\n"); if (min <= reorder->next_seq) { - DDS_LOG(DDS_LC_RADMIN, " next expected: %"PRId64"\n", maxp1); + TRACE (reorder, " next expected: %"PRId64"\n", maxp1); reorder->next_seq = maxp1; res = NN_REORDER_ACCEPT; } @@ -2204,17 +2232,17 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord (reorder->max_sampleiv == NULL || min > reorder->max_sampleiv->u.reorder.maxp1)) { /* n_samples = max_samples => (max_sampleiv = NULL <=> max_samples = 0) */ - DDS_LOG(DDS_LC_RADMIN, " discarding gap: max_samples reached and gap at end\n"); + TRACE (reorder, " discarding gap: max_samples reached and gap at end\n"); res = NN_REORDER_REJECT; } else if (!reorder_insert_gap (reorder, rdata, min, maxp1)) { - DDS_LOG(DDS_LC_RADMIN, " store gap failed: no memory\n"); + TRACE (reorder, " store gap failed: no memory\n"); res = NN_REORDER_REJECT; } else { - DDS_LOG(DDS_LC_RADMIN, " storing gap\n"); + TRACE (reorder, " storing gap\n"); res = NN_REORDER_ACCEPT; /* do not let radmin grow beyond max_samples; there is a small possibility that we insert it & delete it immediately @@ -2230,15 +2258,15 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord } else if (coalesced->u.reorder.min <= reorder->next_seq) { - DDS_LOG(DDS_LC_RADMIN, " coalesced = [%"PRId64",%"PRId64") @ %p containing %"PRId32" samples\n", - coalesced->u.reorder.min, coalesced->u.reorder.maxp1, - (void *) coalesced, coalesced->u.reorder.n_samples); + TRACE (reorder, " coalesced = [%"PRId64",%"PRId64") @ %p containing %"PRId32" samples\n", + coalesced->u.reorder.min, coalesced->u.reorder.maxp1, + (void *) coalesced, coalesced->u.reorder.n_samples); ddsrt_avl_delete (&reorder_sampleivtree_treedef, &reorder->sampleivtree, coalesced); if (coalesced->u.reorder.min <= reorder->next_seq) assert (min <= reorder->next_seq); reorder->next_seq = coalesced->u.reorder.maxp1; reorder->max_sampleiv = ddsrt_avl_find_max (&reorder_sampleivtree_treedef, &reorder->sampleivtree); - DDS_LOG(DDS_LC_RADMIN, " next expected: %"PRId64"\n", reorder->next_seq); + TRACE (reorder, " next expected: %"PRId64"\n", reorder->next_seq); *sc = coalesced->u.reorder.sc; /* Adjust n_samples */ @@ -2249,8 +2277,8 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord } else { - DDS_LOG(DDS_LC_RADMIN, " coalesced = [%"PRId64",%"PRId64") @ %p - that is all\n", - coalesced->u.reorder.min, coalesced->u.reorder.maxp1, (void *) coalesced); + TRACE (reorder, " coalesced = [%"PRId64",%"PRId64") @ %p - that is all\n", + coalesced->u.reorder.min, coalesced->u.reorder.maxp1, (void *) coalesced); reorder->max_sampleiv = ddsrt_avl_find_max (&reorder_sampleivtree_treedef, &reorder->sampleivtree); return valuable ? NN_REORDER_ACCEPT : NN_REORDER_REJECT; } @@ -2268,7 +2296,7 @@ int nn_reorder_wantsample (struct nn_reorder *reorder, seqno_t seq) return (s == NULL || s->u.reorder.maxp1 <= seq); } -unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set *map, uint32_t maxsz, int notail) +unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set_header *map, uint32_t *mapbits, uint32_t maxsz, int notail) { struct nn_rsample *iv; seqno_t i; @@ -2290,13 +2318,13 @@ unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t m #else if (base > reorder->next_seq) { - DDS_ERROR("nn_reorder_nackmap: incorrect base sequence number supplied (%"PRId64" > %"PRId64")\n", base, reorder->next_seq); + DDS_CERROR (reorder->logcfg, "nn_reorder_nackmap: incorrect base sequence number supplied (%"PRId64" > %"PRId64")\n", base, reorder->next_seq); base = reorder->next_seq; } #endif if (maxseq + 1 < base) { - DDS_ERROR("nn_reorder_nackmap: incorrect max sequence number supplied (maxseq %"PRId64" base %"PRId64")\n", maxseq, base); + DDS_CERROR (reorder->logcfg, "nn_reorder_nackmap: incorrect max sequence number supplied (maxseq %"PRId64" base %"PRId64")\n", maxseq, base); maxseq = base - 1; } @@ -2305,7 +2333,7 @@ unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t m map->numbits = maxsz; else map->numbits = (uint32_t) (maxseq + 1 - base); - nn_bitset_zero (map->numbits, map->bits); + nn_bitset_zero (map->numbits, mapbits); if ((iv = ddsrt_avl_find_min (&reorder_sampleivtree_treedef, &reorder->sampleivtree)) != NULL) assert (iv->u.reorder.min > base); @@ -2315,7 +2343,7 @@ unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t m for (; i < base + map->numbits && i < iv->u.reorder.min; i++) { unsigned x = (unsigned) (i - base); - nn_bitset_set (map->numbits, map->bits, x); + nn_bitset_set (map->numbits, mapbits, x); } i = iv->u.reorder.maxp1; iv = ddsrt_avl_find_succ (&reorder_sampleivtree_treedef, &reorder->sampleivtree, iv); @@ -2327,7 +2355,7 @@ unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t m for (; i < base + map->numbits; i++) { unsigned x = (unsigned) (i - base); - nn_bitset_set (map->numbits, map->bits, x); + nn_bitset_set (map->numbits, mapbits, x); } } return map->numbits; @@ -2398,6 +2426,7 @@ static enum dqueue_elem_kind dqueue_elem_kind (const struct nn_rsample_chain_ele static uint32_t dqueue_thread (struct nn_dqueue *q) { struct thread_state1 * const ts1 = lookup_thread_state (); + struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&ts1->gv); nn_mtime_t next_thread_cputime = { 0 }; int keepgoing = 1; nn_guid_t rdguid, *prdguid = NULL; @@ -2408,7 +2437,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q) { struct nn_rsample_chain sc; - LOG_THREAD_CPUTIME (next_thread_cputime); + LOG_THREAD_CPUTIME (&gv->logconfig, next_thread_cputime); if (q->sc.first == NULL) ddsrt_cond_wait (&q->cond, &q->lock); @@ -2416,7 +2445,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q) q->sc.first = q->sc.last = NULL; ddsrt_mutex_unlock (&q->lock); - thread_state_awake (ts1); + thread_state_awake_fixed_domain (ts1); while (sc.first) { struct nn_rsample_chain_elem *e = sc.first; @@ -2484,7 +2513,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q) return 0; } -struct nn_dqueue *nn_dqueue_new (const char *name, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg) +struct nn_dqueue *nn_dqueue_new (const char *name, const struct q_globals *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg) { struct nn_dqueue *q; char *thrname; @@ -2507,7 +2536,7 @@ struct nn_dqueue *nn_dqueue_new (const char *name, uint32_t max_samples, nn_dque if ((thrname = ddsrt_malloc (thrnamesz)) == NULL) goto fail_thrname; snprintf (thrname, thrnamesz, "dq.%s", name); - if (create_thread (&q->ts, thrname, (uint32_t (*) (void *)) dqueue_thread, q) != DDS_RETCODE_OK) + if (create_thread (&q->ts, gv, thrname, (uint32_t (*) (void *)) dqueue_thread, q) != DDS_RETCODE_OK) goto fail_thread; ddsrt_free (thrname); return q; diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index a706067..00b678c 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -19,6 +19,7 @@ #include "dds/ddsrt/md5.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/static_assert.h" #include "dds/ddsrt/avl.h" #include "dds__stream.h" @@ -36,7 +37,6 @@ #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_ddsi_discovery.h" #include "dds/ddsi/q_radmin.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_lease.h" @@ -44,10 +44,10 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_receive.h" +#include "dds/ddsi/q_rhc.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/q_globals.h" -#include "dds/ddsi/q_static_assert.h" #include "dds/ddsi/q_init.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_mcgroup.h" @@ -74,7 +74,7 @@ Notes: */ -static void deliver_user_data_synchronously (struct nn_rsample_chain *sc); +static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid); static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_match *wn, seqno_t last_deliv_seq) { @@ -87,13 +87,15 @@ static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_ma if (last_deliv_seq >= wn->u.not_in_sync.end_of_tl_seq) { wn->in_sync = PRMSS_SYNC; - pwr->n_readers_out_of_sync--; + if (--pwr->n_readers_out_of_sync == 0) + local_reader_ary_setfastpath_ok (&pwr->rdary, true); } break; case PRMSS_OUT_OF_SYNC: - if (nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1 >= wn->u.not_in_sync.end_of_out_of_sync_seq) + assert (nn_reorder_next_seq (wn->u.not_in_sync.reorder) <= nn_reorder_next_seq (pwr->reorder)); + if (pwr->have_seen_heartbeat && nn_reorder_next_seq (wn->u.not_in_sync.reorder) == nn_reorder_next_seq (pwr->reorder)) { - DDS_TRACE(" msr_in_sync("PGUIDFMT" out-of-sync to tlcatchup)", PGUID (wn->rd_guid)); + ETRACE (pwr, " msr_in_sync("PGUIDFMT" out-of-sync to tlcatchup)", PGUID (wn->rd_guid)); wn->in_sync = PRMSS_TLCATCHUP; maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); } @@ -101,25 +103,17 @@ static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_ma } } -static int valid_sequence_number_set (const nn_sequence_number_set_t *snset) +static int valid_sequence_number_set (const nn_sequence_number_set_header_t *snset) { - if (fromSN (snset->bitmap_base) <= 0) - return 0; - if (snset->numbits <= 0 || snset->numbits > 256) - return 0; - return 1; + return (fromSN (snset->bitmap_base) > 0 && snset->numbits <= 256); } -static int valid_fragment_number_set (const nn_fragment_number_set_t *fnset) +static int valid_fragment_number_set (const nn_fragment_number_set_header_t *fnset) { - if (fnset->bitmap_base <= 0) - return 0; - if (fnset->numbits <= 0 || fnset->numbits > 256) - return 0; - return 1; + return (fnset->bitmap_base > 0 && fnset->numbits <= 256); } -static int valid_AckNack (AckNack_t *msg, size_t size, int byteswap) +static int valid_AckNack (const struct receiver_state *rst, AckNack_t *msg, size_t size, int byteswap) { nn_count_t *count; /* this should've preceded the bitmap */ if (size < ACKNACK_SIZE (0)) @@ -136,32 +130,21 @@ static int valid_AckNack (AckNack_t *msg, size_t size, int byteswap) /* Validation following 8.3.7.1.3 + 8.3.5.5 */ if (!valid_sequence_number_set (&msg->readerSNState)) { - if (NN_STRICT_P) - return 0; + /* FastRTPS sends invalid pre-emptive ACKs -- patch the message so we can process it */ + if (! NN_STRICT_P (rst->gv->config) && vendor_is_eprosima (rst->vendor) && + fromSN (msg->readerSNState.bitmap_base) == 0 && msg->readerSNState.numbits == 0) + msg->readerSNState.bitmap_base = toSN (1); else - { - /* RTI generates AckNacks with bitmapBase = 0 and numBits = 0 - (and possibly others that I don't know about) - their - Wireshark RTPS dissector says that such a message has a - length-0 bitmap, which is to expected given the way the - length is computed from numbits */ - if (fromSN (msg->readerSNState.bitmap_base) == 0 && - msg->readerSNState.numbits == 0) - ; /* accept this one known case */ - else if (msg->readerSNState.numbits == 0) - ; /* maybe RTI, definitely Twinoaks */ - else - return 0; - } + return 0; } /* Given the number of bits, we can compute the size of the AckNack submessage, and verify that the submessage is large enough */ if (size < ACKNACK_SIZE (msg->readerSNState.numbits)) return 0; - count = (nn_count_t *) ((char *) &msg->readerSNState + NN_SEQUENCE_NUMBER_SET_SIZE (msg->readerSNState.numbits)); + count = (nn_count_t *) ((char *) &msg->bits + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (msg->readerSNState.numbits)); if (byteswap) { - bswap_sequence_number_set_bitmap (&msg->readerSNState); + bswap_sequence_number_set_bitmap (&msg->readerSNState, msg->bits); *count = bswap4 (*count); } return 1; @@ -181,16 +164,13 @@ static int valid_Gap (Gap_t *msg, size_t size, int byteswap) if (fromSN (msg->gapStart) <= 0) return 0; if (!valid_sequence_number_set (&msg->gapList)) - { - if (NN_STRICT_P || msg->gapList.numbits != 0) - return 0; - } + return 0; /* One would expect gapStart < gapList.base, but it is not required by the spec for the GAP to valid. */ if (size < GAP_SIZE (msg->gapList.numbits)) return 0; if (byteswap) - bswap_sequence_number_set_bitmap (&msg->gapList); + bswap_sequence_number_set_bitmap (&msg->gapList, msg->bits); return 1; } @@ -251,24 +231,9 @@ static int valid_Heartbeat (Heartbeat_t *msg, size_t size, int byteswap) } msg->readerId = nn_ntoh_entityid (msg->readerId); msg->writerId = nn_ntoh_entityid (msg->writerId); - /* Validation following 8.3.7.5.3 */ - if (fromSN (msg->firstSN) <= 0 || - /* fromSN (msg->lastSN) <= 0 || -- implicit in last < first */ - fromSN (msg->lastSN) < fromSN (msg->firstSN)) - { - if (NN_STRICT_P) - return 0; - else - { - /* Note that we don't actually know the set of all possible - malformed messages that we have to process, so we stick to - the ones we've seen */ - if (fromSN (msg->firstSN) == fromSN (msg->lastSN) + 1) - ; /* ok */ - else - return 0; - } - } + /* Validation following 8.3.7.5.3; lastSN + 1 == firstSN: no data */ + if (fromSN (msg->firstSN) <= 0 || fromSN (msg->lastSN) + 1 < fromSN (msg->firstSN)) + return 0; return 1; } @@ -311,19 +276,18 @@ static int valid_NackFrag (NackFrag_t *msg, size_t size, int byteswap) submessage, and verify that the submessage is large enough */ if (size < NACKFRAG_SIZE (msg->fragmentNumberState.numbits)) return 0; - count = (nn_count_t *) ((char *) &msg->fragmentNumberState + - NN_FRAGMENT_NUMBER_SET_SIZE (msg->fragmentNumberState.numbits)); + count = (nn_count_t *) ((char *) &msg->bits + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (msg->fragmentNumberState.numbits)); if (byteswap) { - bswap_fragment_number_set_bitmap (&msg->fragmentNumberState); + bswap_fragment_number_set_bitmap (&msg->fragmentNumberState, msg->bits); *count = bswap4 (*count); } return 1; } -static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_guid_t * pwr_guid) +static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_guid_t *pwr_guid) { - struct proxy_writer * pwr = ephash_lookup_proxy_writer_guid (pwr_guid); + struct proxy_writer * pwr = ephash_lookup_proxy_writer_guid (sampleinfo->rst->gv->guid_hash, pwr_guid); sampleinfo->pwr = pwr; } @@ -386,6 +350,8 @@ static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, D src.encoding = (msg->x.smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; src.buf = ptr; src.bufsz = (unsigned) ((unsigned char *) msg + size - src.buf); /* end of message, that's all we know */ + src.factory = NULL; + src.logconfig = &rst->gv->logconfig; /* just a quick scan, gathering only what we _really_ need */ if ((ptr = nn_plist_quickscan (sampleinfo, rmsg, &src)) == NULL) return 0; @@ -460,7 +426,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms pwr_guid.prefix = rst->src_guid_prefix; pwr_guid.entityid = msg->x.writerId; - if (NN_STRICT_P && msg->fragmentSize <= 1024 && msg->fragmentSize < config.fragment_size) + if (NN_STRICT_P (rst->gv->config) && msg->fragmentSize <= 1024 && msg->fragmentSize < rst->gv->config.fragment_size) { /* Spec says fragments must > 1kB; not allowing 1024 bytes is IMHO totally ridiculous; and I really don't care how small the @@ -471,7 +437,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms } if (msg->fragmentSize == 0 || msg->fragmentStartingNum == 0 || msg->fragmentsInSubmessage == 0) return 0; - if (NN_STRICT_P && msg->fragmentSize >= msg->sampleSize) + if (NN_STRICT_P (rst->gv->config) && msg->fragmentSize >= msg->sampleSize) /* may not fragment if not needed -- but I don't care */ return 0; if ((msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2) * msg->fragmentSize >= msg->sampleSize) @@ -506,6 +472,8 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms src.encoding = (msg->x.smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; src.buf = ptr; src.bufsz = (unsigned) ((unsigned char *) msg + size - src.buf); /* end of message, that's all we know */ + src.factory = NULL; + src.logconfig = &rst->gv->logconfig; /* just a quick scan, gathering only what we _really_ need */ if ((ptr = nn_plist_quickscan (sampleinfo, rmsg, &src)) == NULL) return 0; @@ -563,7 +531,6 @@ static int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader struct nn_xmsg_marker sm_marker; Gap_t *gap; ASSERT_MUTEX_HELD (wr->e.lock); - assert (numbits > 0); gap = nn_xmsg_append (msg, &sm_marker, GAP_SIZE (numbits)); nn_xmsg_submsg_init (msg, sm_marker, SMID_GAP); gap->readerId = nn_hton_entityid (prd->e.guid.entityid); @@ -571,7 +538,7 @@ static int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader gap->gapStart = toSN (start); gap->gapList.bitmap_base = toSN (base); gap->gapList.numbits = numbits; - memcpy (gap->gapList.bits, bits, NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)); + memcpy (gap->bits, bits, NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)); nn_xmsg_submsg_setnext (msg, sm_marker); return 0; } @@ -583,7 +550,7 @@ static void force_heartbeat_to_peer (struct writer *wr, const struct whc_state * ASSERT_MUTEX_HELD (&wr->e.lock); assert (wr->reliable); - m = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); + m = nn_xmsg_new (wr->e.gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPRD (m, prd) < 0) { /* If we don't have an address, give up immediately */ @@ -593,8 +560,8 @@ static void force_heartbeat_to_peer (struct writer *wr, const struct whc_state * /* Send a Heartbeat just to this peer */ add_Heartbeat (m, wr, whcst, hbansreq, prd->e.guid.entityid, 0); - DDS_TRACE("force_heartbeat_to_peer: "PGUIDFMT" -> "PGUIDFMT" - queue for transmit\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + ETRACE (wr, "force_heartbeat_to_peer: "PGUIDFMT" -> "PGUIDFMT" - queue for transmit\n", + PGUID (wr->e.guid), PGUID (prd->e.guid)); qxev_msg (wr->evq, m); } @@ -619,12 +586,12 @@ static int acknack_is_nack (const AckNack_t *msg) even we generate them) */ return 0; for (i = 0; i < (int) NN_SEQUENCE_NUMBER_SET_BITS_SIZE (msg->readerSNState.numbits) / 4 - 1; i++) - x |= msg->readerSNState.bits[i]; + x |= msg->bits[i]; if ((msg->readerSNState.numbits % 32) == 0) mask = ~0u; else mask = ~(~0u >> (msg->readerSNState.numbits % 32)); - x |= msg->readerSNState.bits[i] & mask; + x |= msg->bits[i] & mask; return x != 0; } @@ -656,7 +623,7 @@ static int accept_ack_or_hb_w_timeout (nn_count_t new_count, nn_count_t *exp_cou return 1; } -static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const AckNack_t *msg, nn_ddsi_time_t timestamp) +static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const AckNack_t *msg, nn_wctime_t timestamp) { struct proxy_reader *prd; struct wr_prd_match *rn; @@ -678,56 +645,53 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac seqno_t max_seq_in_reply; struct whc_node *deferred_free_list = NULL; struct whc_state whcst; - unsigned i; int hb_sent_in_response = 0; memset (gapbits, 0, sizeof (gapbits)); - countp = (nn_count_t *) ((char *) msg + offsetof (AckNack_t, readerSNState) + - NN_SEQUENCE_NUMBER_SET_SIZE (msg->readerSNState.numbits)); + countp = (nn_count_t *) ((char *) msg + offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (msg->readerSNState.numbits)); src.prefix = rst->src_guid_prefix; src.entityid = msg->readerId; dst.prefix = rst->dst_guid_prefix; dst.entityid = msg->writerId; - DDS_TRACE("ACKNACK(%s#%"PRId32":%"PRId64"/%"PRIu32":", msg->smhdr.flags & ACKNACK_FLAG_FINAL ? "F" : "", - *countp, fromSN (msg->readerSNState.bitmap_base), msg->readerSNState.numbits); - for (i = 0; i < msg->readerSNState.numbits; i++) - DDS_TRACE("%c", nn_bitset_isset (msg->readerSNState.numbits, msg->readerSNState.bits, i) ? '1' : '0'); + RSTTRACE ("ACKNACK(%s#%"PRId32":%"PRId64"/%"PRIu32":", msg->smhdr.flags & ACKNACK_FLAG_FINAL ? "F" : "", + *countp, fromSN (msg->readerSNState.bitmap_base), msg->readerSNState.numbits); + for (uint32_t i = 0; i < msg->readerSNState.numbits; i++) + RSTTRACE ("%c", nn_bitset_isset (msg->readerSNState.numbits, msg->bits, i) ? '1' : '0'); seqbase = fromSN (msg->readerSNState.bitmap_base); if (!rst->forme) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); return 1; } - if ((wr = ephash_lookup_writer_guid (&dst)) == NULL) + if ((wr = ephash_lookup_writer_guid (rst->gv->guid_hash, &dst)) == NULL) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT"?)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"?)", PGUID (src), PGUID (dst)); return 1; } /* Always look up the proxy reader -- even though we don't need for the normal pure ack steady state. If (a big "if"!) this shows up as a significant portion of the time, we can always rewrite it to only retrieve it when needed. */ - if ((prd = ephash_lookup_proxy_reader_guid (&src)) == NULL) + if ((prd = ephash_lookup_proxy_reader_guid (rst->gv->guid_hash, &src)) == NULL) { - DDS_TRACE(" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (prd->assert_pp_lease) - lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow); + lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow); if (!wr->reliable) /* note: reliability can't be changed */ { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer!)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer!)", PGUID (src), PGUID (dst)); return 1; } ddsrt_mutex_lock (&wr->e.lock); if ((rn = ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, &src)) == NULL) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not a connection)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a connection)", PGUID (src), PGUID (dst)); goto out; } @@ -747,23 +711,22 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac if (!accept_ack_or_hb_w_timeout (*countp, &rn->next_acknack, tnow, &rn->t_acknack_accepted, is_preemptive_ack)) { - DDS_TRACE(" ["PGUIDFMT" -> "PGUIDFMT"])", PGUID (src), PGUID (dst)); + RSTTRACE (" ["PGUIDFMT" -> "PGUIDFMT"])", PGUID (src), PGUID (dst)); goto out; } - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); /* Update latency estimates if we have a timestamp -- won't actually work so well if the timestamp can be a left over from some other submessage -- but then, it is no more than a quick hack at the moment. */ - if (config.meas_hb_to_ack_latency && valid_ddsi_timestamp (timestamp)) + if (rst->gv->config.meas_hb_to_ack_latency && timestamp.v) { nn_wctime_t tstamp_now = now (); - nn_wctime_t tstamp_msg = nn_wctime_from_ddsi_time (timestamp); - nn_lat_estim_update (&rn->hb_to_ack_latency, tstamp_now.v - tstamp_msg.v); - if ((dds_get_log_mask() & DDS_LC_TRACE) && tstamp_now.v > rn->hb_to_ack_latency_tlastlog.v + 10 * T_SECOND) + nn_lat_estim_update (&rn->hb_to_ack_latency, tstamp_now.v - timestamp.v); + if ((rst->gv->logconfig.c.mask & DDS_LC_TRACE) && tstamp_now.v > rn->hb_to_ack_latency_tlastlog.v + 10 * T_SECOND) { - nn_lat_estim_log (DDS_LC_TRACE, NULL, &rn->hb_to_ack_latency); + nn_lat_estim_log (DDS_LC_TRACE, &rst->gv->logconfig, NULL, &rn->hb_to_ack_latency); rn->hb_to_ack_latency_tlastlog = tstamp_now; } } @@ -783,7 +746,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac } ddsrt_avl_augment_update (&wr_readers_treedef, rn); n = remove_acked_messages (wr, &whcst, &deferred_free_list); - DDS_TRACE(" ACK%"PRId64" RM%u", n_ack, n); + RSTTRACE (" ACK%"PRId64" RM%u", n_ack, n); } else { @@ -793,7 +756,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac /* If this reader was marked as "non-responsive" in the past, it's now responding again, so update its status */ - if (rn->seq == MAX_SEQ_NUMBER && prd->c.xqos->reliability.kind == NN_RELIABLE_RELIABILITY_QOS) + if (rn->seq == MAX_SEQ_NUMBER && prd->c.xqos->reliability.kind == DDS_RELIABILITY_RELIABLE) { seqno_t oldest_seq; oldest_seq = WHCST_ISEMPTY(&whcst) ? wr->seq : whcst.max_seq; @@ -809,7 +772,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac rn->seq = wr->seq; } ddsrt_avl_augment_update (&wr_readers_treedef, rn); - DDS_LOG(DDS_LC_THROTTLE, "writer "PGUIDFMT" considering reader "PGUIDFMT" responsive again\n", PGUID (wr->e.guid), PGUID (rn->prd_guid)); + DDS_CLOG (DDS_LC_THROTTLE, &rst->gv->logconfig, "writer "PGUIDFMT" considering reader "PGUIDFMT" responsive again\n", PGUID (wr->e.guid), PGUID (rn->prd_guid)); } /* Second, the NACK bits (literally, that is). To do so, attempt to @@ -821,7 +784,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac max_seq_in_reply = 0; if (!rn->has_replied_to_hb && seqbase > 1 && is_pure_nonhist_ack) { - DDS_TRACE(" setting-has-replied-to-hb"); + RSTTRACE (" setting-has-replied-to-hb"); rn->has_replied_to_hb = 1; /* walk the whole tree to ensure all proxy readers for this writer have their unack'ed info updated */ @@ -835,19 +798,19 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac reader start-up and we respond with a heartbeat and, if we have data in our WHC, we start sending it regardless of whether the remote reader asked for it */ - DDS_TRACE(" preemptive-nack"); + RSTTRACE (" preemptive-nack"); if (WHCST_ISEMPTY(&whcst)) { - DDS_TRACE(" whc-empty "); + RSTTRACE (" whc-empty "); force_heartbeat_to_peer (wr, &whcst, prd, 0); hb_sent_in_response = 1; } else { - DDS_TRACE(" rebase "); + RSTTRACE (" rebase "); force_heartbeat_to_peer (wr, &whcst, prd, 0); hb_sent_in_response = 1; - numbits = config.accelerate_rexmit_block_size; + numbits = rst->gv->config.accelerate_rexmit_block_size; seqbase = whcst.min_seq; } } @@ -860,19 +823,19 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac that doesn't play too nicely with this. */ if (is_pure_nonhist_ack) { - DDS_TRACE(" happy-now"); + RSTTRACE (" happy-now"); rn->assumed_in_sync = 1; } - else if (msg->readerSNState.numbits < config.accelerate_rexmit_block_size) + else if (msg->readerSNState.numbits < rst->gv->config.accelerate_rexmit_block_size) { - DDS_TRACE(" accelerating"); + RSTTRACE (" accelerating"); accelerate_rexmit = 1; - if (accelerate_rexmit && numbits < config.accelerate_rexmit_block_size) - numbits = config.accelerate_rexmit_block_size; + if (accelerate_rexmit && numbits < rst->gv->config.accelerate_rexmit_block_size) + numbits = rst->gv->config.accelerate_rexmit_block_size; } else { - DDS_TRACE(" complying"); + RSTTRACE (" complying"); } } /* Retransmit requested messages, including whatever we decided to @@ -887,28 +850,30 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac a future request'll fix it. */ enqueued = 1; seq_xmit = READ_SEQ_XMIT(wr); - for (i = 0; i < numbits && seqbase + i <= seq_xmit && enqueued; i++) + const bool gap_for_already_acked = vendor_is_eclipse (rst->vendor) && prd->c.xqos->durability.kind == DDS_DURABILITY_VOLATILE && seqbase <= rn->seq; + const seqno_t min_seq_to_rexmit = gap_for_already_acked ? rn->seq + 1 : 0; + for (uint32_t i = 0; i < numbits && seqbase + i <= seq_xmit && enqueued; i++) { /* Accelerated schedule may run ahead of sequence number set contained in the acknack, and assumes all messages beyond the set are NACK'd -- don't feel like tracking where exactly we left off ... */ - if (i >= msg->readerSNState.numbits || nn_bitset_isset (numbits, msg->readerSNState.bits, i)) + if (i >= msg->readerSNState.numbits || nn_bitset_isset (numbits, msg->bits, i)) { seqno_t seq = seqbase + i; struct whc_borrowed_sample sample; - if (whc_borrow_sample (wr->whc, seq, &sample)) + if (seqbase + i >= min_seq_to_rexmit && whc_borrow_sample (wr->whc, seq, &sample)) { if (!wr->retransmitting && sample.unacked) writer_set_retransmitting (wr); - if (config.retransmit_merging != REXMIT_MERGE_NEVER && rn->assumed_in_sync) + if (rst->gv->config.retransmit_merging != REXMIT_MERGE_NEVER && rn->assumed_in_sync) { /* send retransmit to all receivers, but skip if recently done */ nn_mtime_t tstamp = now_mt (); - if (tstamp.v > sample.last_rexmit_ts.v + config.retransmit_merging_period) + if (tstamp.v > sample.last_rexmit_ts.v + rst->gv->config.retransmit_merging_period) { - DDS_TRACE(" RX%"PRId64, seqbase + i); + RSTTRACE (" RX%"PRId64, seqbase + i); enqueued = (enqueue_sample_wrlock_held (wr, seq, sample.plist, sample.serdata, NULL, 0) >= 0); if (enqueued) { @@ -919,13 +884,13 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac } else { - DDS_TRACE(" RX%"PRId64" (merged)", seqbase + i); + RSTTRACE (" RX%"PRId64" (merged)", seqbase + i); } } else { /* no merging, send directed retransmit */ - DDS_TRACE(" RX%"PRId64"", seqbase + i); + RSTTRACE (" RX%"PRId64"", seqbase + i); enqueued = (enqueue_sample_wrlock_held (wr, seq, sample.plist, sample.serdata, prd, 0) >= 0); if (enqueued) { @@ -939,21 +904,21 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac } else if (gapstart == -1) { - DDS_TRACE(" M%"PRId64, seqbase + i); + RSTTRACE (" M%"PRId64, seqbase + i); gapstart = seqbase + i; gapend = gapstart + 1; msgs_lost++; } else if (seqbase + i == gapend) { - DDS_TRACE(" M%"PRId64, seqbase + i); + RSTTRACE (" M%"PRId64, seqbase + i); gapend = seqbase + i + 1; msgs_lost++; } else if (seqbase + i - gapend < 256) { - unsigned idx = (unsigned) (seqbase + i - gapend); - DDS_TRACE(" M%"PRId64, seqbase + i); + uint32_t idx = (uint32_t) (seqbase + i - gapend); + RSTTRACE (" M%"PRId64, seqbase + i); gapnumbits = idx + 1; nn_bitset_set (gapnumbits, gapbits, idx); msgs_lost++; @@ -961,7 +926,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac } } if (!enqueued) - DDS_TRACE(" rexmit-limit-hit"); + RSTTRACE (" rexmit-limit-hit"); /* Generate a Gap message if some of the sequence is missing */ if (gapstart > 0) { @@ -973,23 +938,16 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac to the remote reader. */ gapend = grow_gap_to_next_seq (wr, gapend); } - if (gapnumbits == 0) - { - /* Avoid sending an invalid bitset */ - gapnumbits = 1; - nn_bitset_set (gapnumbits, gapbits, 0); - gapend--; - } /* The non-bitmap part of a gap message says everything <= gapend-1 is no more (so the maximum sequence number it informs the peer of is gapend-1); each bit adds one sequence number to that. */ if (gapend-1 + gapnumbits > max_seq_in_reply) max_seq_in_reply = gapend-1 + gapnumbits; - DDS_TRACE(" XGAP%"PRId64"..%"PRId64"/%u:", gapstart, gapend, gapnumbits); - for (i = 0; i < gapnumbits; i++) - DDS_TRACE("%c", nn_bitset_isset (gapnumbits, gapbits, i) ? '1' : '0'); - m = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); + RSTTRACE (" XGAP%"PRId64"..%"PRId64"/%u:", gapstart, gapend, gapnumbits); + for (uint32_t i = 0; i < gapnumbits; i++) + RSTTRACE ("%c", nn_bitset_isset (gapnumbits, gapbits, i) ? '1' : '0'); + m = nn_xmsg_new (rst->gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS nn_xmsg_setencoderid (m, wr->partition_id); #endif @@ -1011,7 +969,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac it might ... [NB writer->seq is the last msg sent so far] */ if (msgs_sent && max_seq_in_reply < seq_xmit) { - DDS_TRACE(" rexmit#%"PRIu32" maxseq:%"PRId64"<%"PRId64"<=%"PRId64"", msgs_sent, max_seq_in_reply, seq_xmit, wr->seq); + RSTTRACE (" rexmit#%"PRIu32" maxseq:%"PRId64"<%"PRId64"<=%"PRId64"", msgs_sent, max_seq_in_reply, seq_xmit, wr->seq); force_heartbeat_to_peer (wr, &whcst, prd, 1); hb_sent_in_response = 1; @@ -1026,7 +984,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac now if we haven't done so already */ if (!(msg->smhdr.flags & ACKNACK_FLAG_FINAL) && !hb_sent_in_response) force_heartbeat_to_peer (wr, &whcst, prd, 0); - DDS_TRACE(")"); + RSTTRACE (")"); out: ddsrt_mutex_unlock (&wr->e.lock); whc_free_deferred_free_list (wr->whc, deferred_free_list); @@ -1085,13 +1043,14 @@ struct handle_Heartbeat_helper_arg { struct receiver_state *rst; const Heartbeat_t *msg; struct proxy_writer *pwr; - nn_ddsi_time_t timestamp; + nn_wctime_t timestamp; nn_etime_t tnow; nn_mtime_t tnow_mt; }; static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct handle_Heartbeat_helper_arg * const arg) { + struct receiver_state * const rst = arg->rst; Heartbeat_t const * const msg = arg->msg; struct proxy_writer * const pwr = arg->pwr; seqno_t refseq; @@ -1101,7 +1060,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand /* Not supposed to respond to repeats and old heartbeats. */ if (!accept_ack_or_hb_w_timeout (msg->count, &wn->next_heartbeat, arg->tnow, &wn->t_heartbeat_accepted, 0)) { - DDS_TRACE(" ("PGUIDFMT")", PGUID (wn->rd_guid)); + RSTTRACE (" ("PGUIDFMT")", PGUID (wn->rd_guid)); return; } @@ -1112,7 +1071,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand refseq = nn_reorder_next_seq (pwr->reorder) - 1; else refseq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1; - DDS_TRACE(" "PGUIDFMT"@%"PRId64"%s", PGUID (wn->rd_guid), refseq, (wn->in_sync == PRMSS_SYNC) ? "(sync)" : (wn->in_sync == PRMSS_TLCATCHUP) ? "(tlcatchup)" : ""); + RSTTRACE (" "PGUIDFMT"@%"PRId64"%s", PGUID (wn->rd_guid), refseq, (wn->in_sync == PRMSS_SYNC) ? "(sync)" : (wn->in_sync == PRMSS_TLCATCHUP) ? "(tlcatchup)" : ""); /* Reschedule AckNack transmit if deemed appropriate; unreliable readers have acknack_xevent == NULL and can't do this. @@ -1127,13 +1086,13 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand tsched.v = T_NEVER; if (pwr->last_seq > refseq) { - DDS_TRACE("/NAK"); - if (arg->tnow_mt.v >= wn->t_last_nack.v + config.nack_delay || refseq >= wn->seq_last_nack) + RSTTRACE ("/NAK"); + if (arg->tnow_mt.v >= wn->t_last_nack.v + rst->gv->config.nack_delay || refseq >= wn->seq_last_nack) tsched = arg->tnow_mt; else { - tsched.v = arg->tnow_mt.v + config.nack_delay; - DDS_TRACE("d"); + tsched.v = arg->tnow_mt.v + rst->gv->config.nack_delay; + RSTTRACE ("d"); } } else if (!(msg->smhdr.flags & HEARTBEAT_FLAG_FINAL)) @@ -1142,13 +1101,13 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand } if (resched_xevent_if_earlier (wn->acknack_xevent, tsched)) { - if (config.meas_hb_to_ack_latency && valid_ddsi_timestamp (arg->timestamp)) - wn->hb_timestamp = nn_wctime_from_ddsi_time (arg->timestamp); + if (rst->gv->config.meas_hb_to_ack_latency && arg->timestamp.v) + wn->hb_timestamp = arg->timestamp; } } } -static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Heartbeat_t *msg, nn_ddsi_time_t timestamp) +static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Heartbeat_t *msg, nn_wctime_t timestamp) { /* We now cheat: and process the heartbeat for _all_ readers, always, regardless of the destination address in the Heartbeat @@ -1172,44 +1131,48 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct dst.prefix = rst->dst_guid_prefix; dst.entityid = msg->readerId; - DDS_TRACE("HEARTBEAT(%s#%"PRId32":%"PRId64"..%"PRId64" ", msg->smhdr.flags & HEARTBEAT_FLAG_FINAL ? "F" : "", msg->count, firstseq, lastseq); + RSTTRACE ("HEARTBEAT(%s#%"PRId32":%"PRId64"..%"PRId64" ", msg->smhdr.flags & HEARTBEAT_FLAG_FINAL ? "F" : "", msg->count, firstseq, lastseq); if (!rst->forme) { - DDS_TRACE(""PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); + RSTTRACE (PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); return 1; } - if ((pwr = ephash_lookup_proxy_writer_guid (&src)) == NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (rst->gv->guid_hash, &src)) == NULL) { - DDS_TRACE(""PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); + RSTTRACE (PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } - /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (pwr->assert_pp_lease) - lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); + /* liveliness is still only implemented partially (with all set to AUTOMATIC, + BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ + lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); - DDS_TRACE(""PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst)); + RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst)); ddsrt_mutex_lock (&pwr->e.lock); + if (pwr->n_reliable_readers == 0) + { + RSTTRACE (PGUIDFMT" -> "PGUIDFMT" no-reliable-readers)", PGUID (src), PGUID (dst)); + ddsrt_mutex_unlock (&pwr->e.lock); + return 1; + } + if (!pwr->have_seen_heartbeat) { struct nn_rdata *gap; struct nn_rsample_chain sc; int refc_adjust = 0; nn_reorder_result_t res; - nn_defrag_notegap (pwr->defrag, 1, lastseq + 1); gap = nn_rdata_newgap (rmsg); - if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, 1, lastseq + 1, &refc_adjust)) > 0) - { - if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc); - else - nn_dqueue_enqueue (pwr->dqueue, &sc, res); - } + res = nn_reorder_gap (&sc, pwr->reorder, gap, 1, lastseq + 1, &refc_adjust); + /* proxy writer is not accepting data until it has received a heartbeat, so + there can't be any data to deliver */ + assert (res <= 0); + (void) res; nn_fragchain_adjust_refcount (gap, refc_adjust); pwr->have_seen_heartbeat = 1; } @@ -1243,7 +1206,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, 1, firstseq, &refc_adjust)) > 0) { if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc); + deliver_user_data_synchronously (&sc, NULL); else nn_dqueue_enqueue (pwr->dqueue, &sc, res); } @@ -1262,14 +1225,19 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct case PRMSS_OUT_OF_SYNC: { struct nn_reorder *ro = wn->u.not_in_sync.reorder; if ((res = nn_reorder_gap (&sc, ro, gap, 1, firstseq, &refc_adjust)) > 0) - nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); + { + if (pwr->deliver_synchronously) + deliver_user_data_synchronously (&sc, &wn->rd_guid); + else + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); + } last_deliv_seq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1; } } if (wn->u.not_in_sync.end_of_tl_seq == MAX_SEQ_NUMBER) { - wn->u.not_in_sync.end_of_out_of_sync_seq = wn->u.not_in_sync.end_of_tl_seq = fromSN (msg->lastSN); - DDS_TRACE(" end-of-tl-seq(rd "PGUIDFMT" #%"PRId64")", PGUID(wn->rd_guid), wn->u.not_in_sync.end_of_tl_seq); + wn->u.not_in_sync.end_of_tl_seq = fromSN (msg->lastSN); + RSTTRACE (" end-of-tl-seq(rd "PGUIDFMT" #%"PRId64")", PGUID(wn->rd_guid), wn->u.not_in_sync.end_of_tl_seq); } maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); } @@ -1283,7 +1251,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct arg.tnow = tnow; arg.tnow_mt = now_mt (); handle_forall_destinations (&dst, pwr, (ddsrt_avl_walk_t) handle_Heartbeat_helper, &arg); - DDS_TRACE(")"); + RSTTRACE (")"); ddsrt_mutex_unlock (&pwr->e.lock); return 1; @@ -1301,24 +1269,23 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime dst.prefix = rst->dst_guid_prefix; dst.entityid = msg->readerId; - DDS_TRACE("HEARTBEATFRAG(#%"PRId32":%"PRId64"/[1,%u]", msg->count, seq, fragnum+1); + RSTTRACE ("HEARTBEATFRAG(#%"PRId32":%"PRId64"/[1,%u]", msg->count, seq, fragnum+1); if (!rst->forme) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); return 1; } - if ((pwr = ephash_lookup_proxy_writer_guid (&src)) == NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (rst->gv->guid_hash, &src)) == NULL) { - DDS_TRACE(" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (pwr->assert_pp_lease) - lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); + lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); ddsrt_mutex_lock (&pwr->e.lock); if (seq > pwr->last_seq) @@ -1339,7 +1306,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime handle_Heartbeat's scheduling of an AckNack event when it must respond. Why? Just because. */ if (ddsrt_avl_is_empty (&pwr->readers) || pwr->local_matching_inprogress) - DDS_TRACE(" no readers"); + RSTTRACE (" no readers"); else { struct pwr_rd_match *m = NULL; @@ -1377,25 +1344,26 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime } if (m == NULL) - DDS_TRACE(" no interested reliable readers"); + RSTTRACE (" no interested reliable readers"); else { /* Check if we are missing something */ - union { - struct nn_fragment_number_set set; - char pad[NN_FRAGMENT_NUMBER_SET_SIZE (256)]; + DDSRT_STATIC_ASSERT ((NN_FRAGMENT_NUMBER_SET_MAX_BITS % 32) == 0); + struct { + struct nn_fragment_number_set_header set; + uint32_t bits[NN_FRAGMENT_NUMBER_SET_MAX_BITS / 32]; } nackfrag; - if (nn_defrag_nackmap (pwr->defrag, seq, fragnum, &nackfrag.set, 256) > 0) + if (nn_defrag_nackmap (pwr->defrag, seq, fragnum, &nackfrag.set, nackfrag.bits, NN_FRAGMENT_NUMBER_SET_MAX_BITS) > 0) { /* Yes we are (note that this potentially also happens for samples we no longer care about) */ - int64_t delay = config.nack_delay; - DDS_TRACE("/nackfrag"); + int64_t delay = rst->gv->config.nack_delay; + RSTTRACE ("/nackfrag"); resched_xevent_if_earlier (m->acknack_xevent, add_duration_to_mtime (now_mt(), delay)); } } } - DDS_TRACE(")"); + RSTTRACE (")"); ddsrt_mutex_unlock (&pwr->e.lock); return 1; } @@ -1409,64 +1377,62 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N nn_guid_t src, dst; nn_count_t *countp; seqno_t seq = fromSN (msg->writerSN); - unsigned i; - countp = (nn_count_t *) ((char *) msg + offsetof (NackFrag_t, fragmentNumberState) + NN_FRAGMENT_NUMBER_SET_SIZE (msg->fragmentNumberState.numbits)); + countp = (nn_count_t *) ((char *) msg + offsetof (NackFrag_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (msg->fragmentNumberState.numbits)); src.prefix = rst->src_guid_prefix; src.entityid = msg->readerId; dst.prefix = rst->dst_guid_prefix; dst.entityid = msg->writerId; - DDS_TRACE("NACKFRAG(#%"PRId32":%"PRId64"/%u/%"PRIu32":", *countp, seq, msg->fragmentNumberState.bitmap_base, msg->fragmentNumberState.numbits); - for (i = 0; i < msg->fragmentNumberState.numbits; i++) - DDS_TRACE("%c", nn_bitset_isset (msg->fragmentNumberState.numbits, msg->fragmentNumberState.bits, i) ? '1' : '0'); + RSTTRACE ("NACKFRAG(#%"PRId32":%"PRId64"/%u/%"PRIu32":", *countp, seq, msg->fragmentNumberState.bitmap_base, msg->fragmentNumberState.numbits); + for (uint32_t i = 0; i < msg->fragmentNumberState.numbits; i++) + RSTTRACE ("%c", nn_bitset_isset (msg->fragmentNumberState.numbits, msg->bits, i) ? '1' : '0'); if (!rst->forme) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); return 1; } - if ((wr = ephash_lookup_writer_guid (&dst)) == NULL) + if ((wr = ephash_lookup_writer_guid (rst->gv->guid_hash, &dst)) == NULL) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT"?)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"?)", PGUID (src), PGUID (dst)); return 1; } /* Always look up the proxy reader -- even though we don't need for the normal pure ack steady state. If (a big "if"!) this shows up as a significant portion of the time, we can always rewrite it to only retrieve it when needed. */ - if ((prd = ephash_lookup_proxy_reader_guid (&src)) == NULL) + if ((prd = ephash_lookup_proxy_reader_guid (rst->gv->guid_hash, &src)) == NULL) { - DDS_TRACE(" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (prd->assert_pp_lease) - lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow); + lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow); if (!wr->reliable) /* note: reliability can't be changed */ { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer)", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer)", PGUID (src), PGUID (dst)); return 1; } ddsrt_mutex_lock (&wr->e.lock); if ((rn = ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, &src)) == NULL) { - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT" not a connection", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a connection", PGUID (src), PGUID (dst)); goto out; } /* Ignore old NackFrags (see also handle_AckNack) */ if (*countp < rn->next_nackfrag) { - DDS_TRACE(" ["PGUIDFMT" -> "PGUIDFMT"]", PGUID (src), PGUID (dst)); + RSTTRACE (" ["PGUIDFMT" -> "PGUIDFMT"]", PGUID (src), PGUID (dst)); goto out; } rn->next_nackfrag = *countp + 1; - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); /* Resend the requested fragments if we still have the sample, send a Gap if we don't have them anymore. */ @@ -1474,10 +1440,10 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N { const unsigned base = msg->fragmentNumberState.bitmap_base - 1; int enqueued = 1; - DDS_TRACE(" scheduling requested frags ...\n"); - for (i = 0; i < msg->fragmentNumberState.numbits && enqueued; i++) + RSTTRACE (" scheduling requested frags ...\n"); + for (uint32_t i = 0; i < msg->fragmentNumberState.numbits && enqueued; i++) { - if (nn_bitset_isset (msg->fragmentNumberState.numbits, msg->fragmentNumberState.bits, i)) + if (nn_bitset_isset (msg->fragmentNumberState.numbits, msg->bits, i)) { struct nn_xmsg *reply; if (create_fragment_message (wr, seq, sample.plist, sample.serdata, base + i, prd, &reply, 0) < 0) @@ -1492,8 +1458,8 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N { static uint32_t zero = 0; struct nn_xmsg *m; - DDS_TRACE(" msg not available: scheduling Gap\n"); - m = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); + RSTTRACE (" msg not available: scheduling Gap\n"); + m = nn_xmsg_new (rst->gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS nn_xmsg_setencoderid (m, wr->partition_id); #endif @@ -1520,14 +1486,14 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N out: ddsrt_mutex_unlock (&wr->e.lock); - DDS_TRACE(")"); + RSTTRACE (")"); return 1; } static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, const nn_guid_prefix_t *dst_prefix) { rst->dst_guid_prefix = nn_ntoh_guid_prefix (msg->guid_prefix); - DDS_TRACE("INFODST(%"PRIx32":%"PRIx32":%"PRIx32")", PGUIDPREFIX (rst->dst_guid_prefix)); + RSTTRACE ("INFODST(%"PRIx32":%"PRIx32":%"PRIx32")", PGUIDPREFIX (rst->dst_guid_prefix)); if (rst->dst_guid_prefix.u[0] == 0 && rst->dst_guid_prefix.u[1] == 0 && rst->dst_guid_prefix.u[2] == 0) { if (dst_prefix) @@ -1539,7 +1505,8 @@ static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, con nn_guid_t dst; dst.prefix = rst->dst_guid_prefix; dst.entityid = to_entityid(NN_ENTITYID_PARTICIPANT); - rst->forme = (ephash_lookup_participant_guid (&dst) != NULL) || is_deleted_participant_guid (&dst, DPG_LOCAL); + rst->forme = (ephash_lookup_participant_guid (rst->gv->guid_hash, &dst) != NULL || + is_deleted_participant_guid (rst->gv->deleted_participants, &dst, DPG_LOCAL)); } return 1; } @@ -1549,29 +1516,26 @@ static int handle_InfoSRC (struct receiver_state *rst, const InfoSRC_t *msg) rst->src_guid_prefix = nn_ntoh_guid_prefix (msg->guid_prefix); rst->protocol_version = msg->version; rst->vendor = msg->vendorid; - DDS_TRACE("INFOSRC(%"PRIx32":%"PRIx32":%"PRIx32" vendor %u.%u)", + RSTTRACE ("INFOSRC(%"PRIx32":%"PRIx32":%"PRIx32" vendor %u.%u)", PGUIDPREFIX (rst->src_guid_prefix), rst->vendor.id[0], rst->vendor.id[1]); return 1; } -static int handle_InfoTS (const InfoTS_t *msg, nn_ddsi_time_t *timestamp) +static int handle_InfoTS (const struct receiver_state *rst, const InfoTS_t *msg, nn_wctime_t *timestamp) { - DDS_TRACE("INFOTS("); + RSTTRACE ("INFOTS("); if (msg->smhdr.flags & INFOTS_INVALIDATE_FLAG) { - *timestamp = invalid_ddsi_timestamp; - DDS_TRACE("invalidate"); + *timestamp = NN_WCTIME_INVALID; + RSTTRACE ("invalidate"); } else { - *timestamp = msg->time; - if (dds_get_log_mask() & DDS_LC_TRACE) - { - nn_wctime_t t = nn_wctime_from_ddsi_time (* timestamp); - DDS_TRACE("%d.%09d", (int) (t.v / 1000000000), (int) (t.v % 1000000000)); - } + *timestamp = nn_wctime_from_ddsi_time (msg->time); + if (rst->gv->logconfig.c.mask & DDS_LC_TRACE) + RSTTRACE ("%d.%09d", (int) (timestamp->v / 1000000000), (int) (timestamp->v % 1000000000)); } - DDS_TRACE(")"); + RSTTRACE (")"); return 1; } @@ -1591,7 +1555,7 @@ static int handle_one_gap (struct proxy_writer *pwr, struct pwr_rd_match *wn, se if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, a, b, refc_adjust)) > 0) { if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc); + deliver_user_data_synchronously (&sc, NULL); else nn_dqueue_enqueue (pwr->dqueue, &sc, res); } @@ -1600,7 +1564,7 @@ static int handle_one_gap (struct proxy_writer *pwr, struct pwr_rd_match *wn, se anything useful, or there was insufficient memory to store it. When the result is either ACCEPT or a sample chain, it clearly meant something. */ - Q_STATIC_ASSERT_CODE (NN_REORDER_ACCEPT == 0); + DDSRT_STATIC_ASSERT_CODE (NN_REORDER_ACCEPT == 0); if (res >= 0) gap_was_valuable = 1; @@ -1617,13 +1581,15 @@ static int handle_one_gap (struct proxy_writer *pwr, struct pwr_rd_match *wn, se case PRMSS_TLCATCHUP: break; case PRMSS_OUT_OF_SYNC: - if (a <= wn->u.not_in_sync.end_of_out_of_sync_seq) + if ((res = nn_reorder_gap (&sc, wn->u.not_in_sync.reorder, gap, a, b, refc_adjust)) > 0) { - if ((res = nn_reorder_gap (&sc, wn->u.not_in_sync.reorder, gap, a, b, refc_adjust)) > 0) + if (pwr->deliver_synchronously) + deliver_user_data_synchronously (&sc, &wn->rd_guid); + else nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); - if (res >= 0) - gap_was_valuable = 1; } + if (res >= 0) + gap_was_valuable = 1; break; } @@ -1659,8 +1625,8 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm struct pwr_rd_match *wn; nn_guid_t src, dst; seqno_t gapstart, listbase; - int64_t last_included_rel; - unsigned listidx; + int32_t last_included_rel; + uint32_t listidx; src.prefix = rst->src_guid_prefix; src.entityid = msg->writerId; @@ -1668,44 +1634,43 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm dst.entityid = msg->readerId; gapstart = fromSN (msg->gapStart); listbase = fromSN (msg->gapList.bitmap_base); - DDS_TRACE("GAP(%"PRId64"..%"PRId64"/%"PRIu32" ", gapstart, listbase, msg->gapList.numbits); + RSTTRACE ("GAP(%"PRId64"..%"PRId64"/%"PRIu32" ", gapstart, listbase, msg->gapList.numbits); /* There is no _good_ reason for a writer to start the bitmap with a 1 bit, but check for it just in case, to reduce the number of sequence number gaps to be processed. */ for (listidx = 0; listidx < msg->gapList.numbits; listidx++) - if (!nn_bitset_isset (msg->gapList.numbits, msg->gapList.bits, listidx)) + if (!nn_bitset_isset (msg->gapList.numbits, msg->bits, listidx)) break; - last_included_rel = (int)listidx - 1; + last_included_rel = (int32_t) listidx - 1; if (!rst->forme) { - DDS_TRACE(""PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); + RSTTRACE (""PGUIDFMT" -> "PGUIDFMT" not-for-me)", PGUID (src), PGUID (dst)); return 1; } - if ((pwr = ephash_lookup_proxy_writer_guid (&src)) == NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (rst->gv->guid_hash, &src)) == NULL) { - DDS_TRACE(""PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); + RSTTRACE (""PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (pwr->assert_pp_lease) - lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); + lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); ddsrt_mutex_lock (&pwr->e.lock); if ((wn = ddsrt_avl_lookup (&pwr_readers_treedef, &pwr->readers, &dst)) == NULL) { - DDS_TRACE(PGUIDFMT" -> "PGUIDFMT" not a connection)", PGUID (src), PGUID (dst)); + RSTTRACE (PGUIDFMT" -> "PGUIDFMT" not a connection)", PGUID (src), PGUID (dst)); ddsrt_mutex_unlock (&pwr->e.lock); return 1; } - DDS_TRACE(PGUIDFMT" -> "PGUIDFMT, PGUID (src), PGUID (dst)); + RSTTRACE (PGUIDFMT" -> "PGUIDFMT, PGUID (src), PGUID (dst)); if (!pwr->have_seen_heartbeat && pwr->n_reliable_readers > 0) { - DDS_TRACE(": no heartbeat seen yet"); + RSTTRACE (": no heartbeat seen yet"); ddsrt_mutex_unlock (&pwr->e.lock); return 1; } @@ -1726,20 +1691,20 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm } while (listidx < msg->gapList.numbits) { - if (!nn_bitset_isset (msg->gapList.numbits, msg->gapList.bits, listidx)) + if (!nn_bitset_isset (msg->gapList.numbits, msg->bits, listidx)) listidx++; else { - unsigned j; - for (j = listidx+1; j < msg->gapList.numbits; j++) - if (!nn_bitset_isset (msg->gapList.numbits, msg->gapList.bits, j)) + uint32_t j; + for (j = listidx + 1; j < msg->gapList.numbits; j++) + if (!nn_bitset_isset (msg->gapList.numbits, msg->bits, j)) break; /* spec says gapList (2) identifies an additional list of sequence numbers that are invalid (8.3.7.4.2), so by that rule an insane start would simply mean the initial interval is to be ignored and the bitmap to be applied */ (void) handle_one_gap (pwr, wn, listbase + listidx, listbase + j, gap, &refc_adjust); assert(j >= 1); - last_included_rel = j - 1; + last_included_rel = (int32_t) j - 1; listidx = j; } } @@ -1758,7 +1723,7 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm pwr->last_fragnum = ~0u; pwr->last_fragnum_reset = 0; } - DDS_TRACE(")"); + RSTTRACE (")"); ddsrt_mutex_unlock (&pwr->e.lock); return 1; } @@ -1766,8 +1731,11 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm static struct ddsi_serdata *get_serdata (struct ddsi_sertopic const * const topic, const struct nn_rdata *fragchain, uint32_t sz, int justkey, unsigned statusinfo, nn_wctime_t tstamp) { struct ddsi_serdata *sd = ddsi_serdata_from_ser (topic, justkey ? SDK_KEY : SDK_DATA, fragchain, sz); - sd->statusinfo = statusinfo; - sd->timestamp = tstamp; + if (sd) + { + sd->statusinfo = statusinfo; + sd->timestamp = tstamp; + } return sd; } @@ -1789,11 +1757,11 @@ static struct ddsi_serdata *extract_sample_from_data { const struct proxy_writer *pwr = sampleinfo->pwr; nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */ - DDS_TRACE("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64 - ": write without proper payload (data_smhdr_flags 0x%x size %"PRIu32")\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (guid), sampleinfo->seq, - data_smhdr_flags, sampleinfo->size); + DDS_CTRACE (&sampleinfo->rst->gv->logconfig, + "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": write without proper payload (data_smhdr_flags 0x%x size %"PRIu32")\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (guid), sampleinfo->seq, + data_smhdr_flags, sampleinfo->size); return NULL; } sample = get_serdata (topic, fragchain, sampleinfo->size, 0, statusinfo, tstamp); @@ -1817,7 +1785,7 @@ static struct ddsi_serdata *extract_sample_from_data { /* RTI always tries to make us survive on the keyhash. RTI must mend its ways. */ - if (NN_STRICT_P) + if (NN_STRICT_P (sampleinfo->rst->gv->config)) failmsg = "no content"; else if (!(qos->present & PP_KEYHASH)) failmsg = "qos present but without keyhash"; @@ -1838,14 +1806,12 @@ static struct ddsi_serdata *extract_sample_from_data /* No message => error out */ const struct proxy_writer *pwr = sampleinfo->pwr; nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */ - DDS_WARNING - ( - "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization %s/%s failed (%s)\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (guid), sampleinfo->seq, - topic->name, topic->type_name, - failmsg ? failmsg : "for reasons unknown" - ); + DDS_CWARNING (&sampleinfo->rst->gv->logconfig, + "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization %s/%s failed (%s)\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (guid), sampleinfo->seq, + topic->name, topic->type_name, + failmsg ? failmsg : "for reasons unknown"); } return sample; } @@ -1859,7 +1825,7 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr) case SMID_DATA_FRAG: { unsigned char common = smhdr->flags & DATA_FLAG_INLINE_QOS; - Q_STATIC_ASSERT_CODE (DATA_FLAG_INLINE_QOS == DATAFRAG_FLAG_INLINE_QOS); + DDSRT_STATIC_ASSERT_CODE (DATA_FLAG_INLINE_QOS == DATAFRAG_FLAG_INLINE_QOS); if (smhdr->flags & DATAFRAG_FLAG_KEYFLAG) return common | DATA_FLAG_KEYFLAG; else @@ -1934,17 +1900,21 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st { nn_plist_src_t src; size_t qos_offset = NN_RDATA_SUBMSG_OFF (fragchain) + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->octetsToInlineQos) + msg->octetsToInlineQos; - int plist_ret; + dds_return_t plist_ret; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = (msg->smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; src.buf = NN_RMSG_PAYLOADOFF (fragchain->rmsg, qos_offset); src.bufsz = NN_RDATA_PAYLOAD_OFF (fragchain) - qos_offset; - if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET | PP_PRISMTECH_EOTINFO, 0, &src)) < 0) + src.strict = NN_STRICT_P (rst->gv->config); + src.factory = rst->gv->m_factory; + src.logconfig = &rst->gv->logconfig; + if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET, 0, &src)) < 0) { - if (plist_ret != Q_ERR_INCOMPATIBLE) - DDS_WARNING ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", - src.vendorid.id[0], src.vendorid.id[1], PGUID (pwr->e.guid), sampleinfo->seq); + if (plist_ret != DDS_RETCODE_UNSUPPORTED) + DDS_CWARNING (&sampleinfo->rst->gv->logconfig, + "data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", + src.vendorid.id[0], src.vendorid.id[1], PGUID (pwr->e.guid), sampleinfo->seq); return 0; } statusinfo = (qos.present & PP_STATUSINFO) ? qos.statusinfo : 0; @@ -1956,8 +1926,8 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st worry about it. */ { nn_wctime_t tstamp; - if (valid_ddsi_timestamp (sampleinfo->timestamp)) - tstamp = nn_wctime_from_ddsi_time (sampleinfo->timestamp); + if (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v) + tstamp = sampleinfo->timestamp; else tstamp.v = 0; payload = extract_sample_from_data (sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, topic); @@ -1967,94 +1937,87 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st goto no_payload; } - /* Generate the DDS_SampleInfo (which is faked to some extent - because we don't actually have a data reader); also note that - the PRISMTECH_WRITER_INFO thing is completely meaningless to - us */ + because we don't actually have a data reader) */ + struct ddsi_tkmap_instance *tk; + if ((tk = ddsi_tkmap_lookup_instance_ref (pwr->e.gv->m_tkmap, payload)) != NULL) { - struct ddsi_tkmap_instance * tk; - tk = ddsi_tkmap_lookup_instance_ref(payload); - if (tk) + struct proxy_writer_info pwr_info; + make_proxy_writer_info (&pwr_info, &pwr->e, pwr->c.xqos); + + if (rdguid == NULL) { - struct proxy_writer_info pwr_info; - make_proxy_writer_info(&pwr_info, &pwr->e, pwr->c.xqos); + ETRACE (pwr, " %"PRId64"=>EVERYONE\n", sampleinfo->seq); - if (rdguid == NULL) + /* FIXME: pwr->rdary is an array of pointers to attached + readers. There's only one thread delivering data for the + proxy writer (as long as there is only one receive thread), + so could get away with not locking at all, and doing safe + updates + GC of rdary instead. */ + + /* Retry loop, for re-delivery of rejected reliable samples. Is a + temporary hack till throttling back of writer is implemented + (with late acknowledgement of sample and nack). */ + retry: + + ddsrt_mutex_lock (&pwr->rdary.rdary_lock); + if (pwr->rdary.fastpath_ok) { - DDS_TRACE(" %"PRId64"=>EVERYONE\n", sampleinfo->seq); - - /* FIXME: pwr->rdary is an array of pointers to attached - readers. There's only one thread delivering data for the - proxy writer (as long as there is only one receive thread), - so could get away with not locking at all, and doing safe - updates + GC of rdary instead. */ - - /* Retry loop, for re-delivery of rejected reliable samples. Is a - temporary hack till throttling back of writer is implemented - (with late acknowledgement of sample and nack). */ -retry: - - ddsrt_mutex_lock (&pwr->rdary.rdary_lock); - if (pwr->rdary.fastpath_ok) + struct reader ** const rdary = pwr->rdary.rdary; + for (uint32_t i = 0; rdary[i]; i++) { - struct reader ** const rdary = pwr->rdary.rdary; - unsigned i; - for (i = 0; rdary[i]; i++) + ETRACE (pwr, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid)); + if (!rhc_store (rdary[i]->rhc, &pwr_info, payload, tk)) { - DDS_TRACE("reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid)); - if (! (ddsi_plugin.rhc_plugin.rhc_store_fn) (rdary[i]->rhc, &pwr_info, payload, tk)) - { - if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); - dds_sleepfor (DDS_MSECS (10)); - if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); - goto retry; - } + if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); + ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); + dds_sleepfor (DDS_MSECS (10)); + if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); + goto retry; } - ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); } - else - { - /* When deleting, pwr is no longer accessible via the hash - tables, and consequently, a reader may be deleted without - it being possible to remove it from rdary. The primary - reason rdary exists is to avoid locking the proxy writer - but this is less of an issue when we are deleting it, so - we fall back to using the GUIDs so that we can deliver all - samples we received from it. As writer being deleted any - reliable samples that are rejected are simply discarded. */ - ddsrt_avl_iter_t it; - struct pwr_rd_match *m; - ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); - if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); - for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it)) - { - struct reader *rd; - if ((rd = ephash_lookup_reader_guid (&m->rd_guid)) != NULL) - { - DDS_TRACE("reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid)); - (void) (ddsi_plugin.rhc_plugin.rhc_store_fn) (rd->rhc, &pwr_info, payload, tk); - } - } - if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - } - - ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1)); + ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); } else { - struct reader *rd = ephash_lookup_reader_guid (rdguid);; - DDS_TRACE(" %"PRId64"=>"PGUIDFMT"%s\n", sampleinfo->seq, PGUID (*rdguid), rd ? "" : "?"); - while (rd && ! (ddsi_plugin.rhc_plugin.rhc_store_fn) (rd->rhc, &pwr_info, payload, tk) && ephash_lookup_proxy_writer_guid (&pwr->e.guid)) + /* When deleting, pwr is no longer accessible via the hash + tables, and consequently, a reader may be deleted without + it being possible to remove it from rdary. The primary + reason rdary exists is to avoid locking the proxy writer + but this is less of an issue when we are deleting it, so + we fall back to using the GUIDs so that we can deliver all + samples we received from it. As writer being deleted any + reliable samples that are rejected are simply discarded. */ + ddsrt_avl_iter_t it; + struct pwr_rd_match *m; + ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); + if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); + for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it)) { - if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - dds_sleepfor (DDS_MSECS (1)); - if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); + struct reader *rd; + if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL && m->in_sync == PRMSS_SYNC) + { + ETRACE (pwr, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid)); + (void) rhc_store (rd->rhc, &pwr_info, payload, tk); + } } + if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); } - ddsi_tkmap_instance_unref (tk); + + ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1)); } + else + { + struct reader *rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rdguid); + ETRACE (pwr, " %"PRId64"=>"PGUIDFMT"%s\n", sampleinfo->seq, PGUID (*rdguid), rd ? "" : "?"); + while (rd && ! rhc_store (rd->rhc, &pwr_info, payload, tk) && ephash_lookup_proxy_writer_guid (pwr->e.gv->guid_hash, &pwr->e.guid)) + { + if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); + dds_sleepfor (DDS_MSECS (1)); + if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); + } + } + ddsi_tkmap_instance_unref (pwr->e.gv->m_tkmap, tk); } ddsi_serdata_unref (payload); no_payload: @@ -2069,7 +2032,7 @@ int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct return res; } -static void deliver_user_data_synchronously (struct nn_rsample_chain *sc) +static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid) { while (sc->first) { @@ -2081,7 +2044,7 @@ static void deliver_user_data_synchronously (struct nn_rsample_chain *sc) sample_lost events. Also note that the synchronous path is _never_ used for historical data, and therefore never has the GUID of a reader to deliver to */ - deliver_user_data (e->sampleinfo, e->fragchain, NULL, 1); + deliver_user_data (e->sampleinfo, e->fragchain, rdguid, 1); } nn_fragchain_unref (e->fragchain); } @@ -2121,17 +2084,14 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_guid_t src; src.prefix = rst->src_guid_prefix; src.entityid = msg->writerId; - DDS_TRACE(" "PGUIDFMT"? -> "PGUIDFMT, PGUID (src), PGUID (dst)); + RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT, PGUID (src), PGUID (dst)); return; } /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */ - if (pwr->assert_pp_lease) - { - lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); - } + lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow); /* Shouldn't lock the full writer, but will do so for now */ ddsrt_mutex_lock (&pwr->e.lock); @@ -2150,14 +2110,14 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct if (!pwr->have_seen_heartbeat && pwr->n_reliable_readers > 0) { ddsrt_mutex_unlock (&pwr->e.lock); - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT": no heartbeat seen yet", PGUID (pwr->e.guid), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT": no heartbeat seen yet", PGUID (pwr->e.guid), PGUID (dst)); return; } if (ddsrt_avl_is_empty (&pwr->readers) || pwr->local_matching_inprogress) { ddsrt_mutex_unlock (&pwr->e.lock); - DDS_TRACE(" "PGUIDFMT" -> "PGUIDFMT": no readers", PGUID (pwr->e.guid), PGUID (dst)); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT": no readers", PGUID (pwr->e.guid), PGUID (dst)); return; } @@ -2212,7 +2172,7 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct by the current mishandling of resource limits */ if (*deferred_wakeup) dd_dqueue_enqueue_trigger (*deferred_wakeup); - deliver_user_data_synchronously (&sc); + deliver_user_data_synchronously (&sc, NULL); } else { @@ -2223,31 +2183,27 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct *deferred_wakeup = pwr->dqueue; } } - if (pwr->n_readers_out_of_sync > 0) - { - /* Those readers catching up with TL but in sync with the proxy - writer may have become in sync with the proxy writer and the - writer; those catching up with TL all by themselves go through - the "TOO_OLD" path below. */ - ddsrt_avl_iter_t it; - struct pwr_rd_match *wn; - for (wn = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); wn != NULL; wn = ddsrt_avl_iter_next (&it)) - if (wn->in_sync == PRMSS_TLCATCHUP) - maybe_set_reader_in_sync (pwr, wn, sampleinfo->seq); - } } - else if (rres == NN_REORDER_TOO_OLD) + + if (pwr->n_readers_out_of_sync > 0) { + /* Those readers catching up with TL but in sync with the proxy + writer may have become in sync with the proxy writer and the + writer; those catching up with TL all by themselves go through + the "TOO_OLD" path below. */ + ddsrt_avl_iter_t it; struct pwr_rd_match *wn; struct nn_rsample *rsample_dup = NULL; int reuse_rsample_dup = 0; - for (wn = ddsrt_avl_find_min (&pwr_readers_treedef, &pwr->readers); wn != NULL; wn = ddsrt_avl_find_succ (&pwr_readers_treedef, &pwr->readers, wn)) + for (wn = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); wn != NULL; wn = ddsrt_avl_iter_next (&it)) { nn_reorder_result_t rres2; - if (wn->in_sync != PRMSS_OUT_OF_SYNC || sampleinfo->seq > wn->u.not_in_sync.end_of_out_of_sync_seq) + if (wn->in_sync == PRMSS_SYNC) continue; + /* only need to get a copy of the first sample, because that's the one + that triggered delivery */ if (!reuse_rsample_dup) - rsample_dup = nn_reorder_rsample_dup (rmsg, rsample); + rsample_dup = nn_reorder_rsample_dup_first (rmsg, rsample); rres2 = nn_reorder_rsample (&sc, wn->u.not_in_sync.reorder, rsample_dup, &refc_adjust, nn_dqueue_is_full (pwr->dqueue)); switch (rres2) { @@ -2270,17 +2226,26 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct in-order, and those few microseconds can't hurt in catching up on transient-local data. See also NN_REORDER_DELIVER case in outer switch. */ - nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, rres2); + if (pwr->deliver_synchronously) + { + /* FIXME: just in case the synchronous delivery runs into a delay caused + by the current mishandling of resource limits */ + deliver_user_data_synchronously (&sc, &wn->rd_guid); + } + else + { + if (*deferred_wakeup && *deferred_wakeup != pwr->dqueue) + { + dd_dqueue_enqueue_trigger (*deferred_wakeup); + *deferred_wakeup = NULL; + } + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, rres2); + } break; } } } -#ifndef NDEBUG - else - { - assert (rres == NN_REORDER_ACCEPT || rres == NN_REORDER_REJECT); - } -#endif + nn_fragchain_adjust_refcount (fragchain, refc_adjust); } ddsrt_mutex_unlock (&pwr->e.lock); @@ -2289,18 +2254,19 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct static int handle_SPDP (const struct nn_rsample_info *sampleinfo, struct nn_rdata *rdata) { + struct q_globals * const gv = sampleinfo->rst->gv; struct nn_rsample *rsample; struct nn_rsample_chain sc; struct nn_rdata *fragchain; nn_reorder_result_t rres; int refc_adjust = 0; - ddsrt_mutex_lock (&gv.spdp_lock); - rsample = nn_defrag_rsample (gv.spdp_defrag, rdata, sampleinfo); + ddsrt_mutex_lock (&gv->spdp_lock); + rsample = nn_defrag_rsample (gv->spdp_defrag, rdata, sampleinfo); fragchain = nn_rsample_fragchain (rsample); - if ((rres = nn_reorder_rsample (&sc, gv.spdp_reorder, rsample, &refc_adjust, nn_dqueue_is_full (gv.builtins_dqueue))) > 0) - nn_dqueue_enqueue (gv.builtins_dqueue, &sc, rres); + if ((rres = nn_reorder_rsample (&sc, gv->spdp_reorder, rsample, &refc_adjust, nn_dqueue_is_full (gv->builtins_dqueue))) > 0) + nn_dqueue_enqueue (gv->builtins_dqueue, &sc, rres); nn_fragchain_adjust_refcount (fragchain, refc_adjust); - ddsrt_mutex_unlock (&gv.spdp_lock); + ddsrt_mutex_unlock (&gv->spdp_lock); return 0; } @@ -2314,9 +2280,9 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con cause periodic warnings. */ if (msg->writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) { - DDS_WARNING ("dropping oversize (%"PRIu32" > %"PRIu32") SPDP sample %"PRId64" from remote writer "PGUIDFMT"\n", - sampleinfo->size, config.max_sample_size, sampleinfo->seq, - PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u); + DDS_CWARNING (&rst->gv->logconfig, "dropping oversize (%"PRIu32" > %"PRIu32") SPDP sample %"PRId64" from remote writer "PGUIDFMT"\n", + sampleinfo->size, rst->gv->config.max_sample_size, sampleinfo->seq, + PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u); } } else @@ -2344,27 +2310,27 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con { const char *tname = pwr->c.topic ? pwr->c.topic->name : "(null)"; const char *ttname = pwr->c.topic ? pwr->c.topic->type_name : "(null)"; - DDS_WARNING ("dropping oversize (%"PRIu32" > %"PRIu32") sample %"PRId64" from remote writer "PGUIDFMT" %s/%s\n", - sampleinfo->size, config.max_sample_size, sampleinfo->seq, - PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u, - tname, ttname); + DDS_CWARNING (&rst->gv->logconfig, "dropping oversize (%"PRIu32" > %"PRIu32") sample %"PRId64" from remote writer "PGUIDFMT" %s/%s\n", + sampleinfo->size, rst->gv->config.max_sample_size, sampleinfo->seq, + PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u, + tname, ttname); } } } static int handle_Data (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup) { - DDS_TRACE("DATA("PGUIDFMT" -> "PGUIDFMT" #%"PRId64, - PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, - PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u, - fromSN (msg->x.writerSN)); + RSTTRACE ("DATA("PGUIDFMT" -> "PGUIDFMT" #%"PRId64, + PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, + PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u, + fromSN (msg->x.writerSN)); if (!rst->forme) { - DDS_TRACE(" not-for-me)"); + RSTTRACE (" not-for-me)"); return 1; } - if (sampleinfo->size > config.max_sample_size) + if (sampleinfo->size > rst->gv->config.max_sample_size) drop_oversize (rst, rmsg, &msg->x, sampleinfo); else { @@ -2392,24 +2358,24 @@ static int handle_Data (struct receiver_state *rst, nn_etime_t tnow, struct nn_r handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup); } } - DDS_TRACE(")"); + RSTTRACE (")"); return 1; } static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const DataFrag_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup) { - DDS_TRACE("DATAFRAG("PGUIDFMT" -> "PGUIDFMT" #%"PRId64"/[%u..%u]", - PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, - PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u, - fromSN (msg->x.writerSN), - msg->fragmentStartingNum, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 1); + RSTTRACE ("DATAFRAG("PGUIDFMT" -> "PGUIDFMT" #%"PRId64"/[%u..%u]", + PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, + PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u, + fromSN (msg->x.writerSN), + msg->fragmentStartingNum, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 1); if (!rst->forme) { - DDS_TRACE(" not-for-me)"); + RSTTRACE (" not-for-me)"); return 1; } - if (sampleinfo->size > config.max_sample_size) + if (sampleinfo->size > rst->gv->config.max_sample_size) drop_oversize (rst, rmsg, &msg->x, sampleinfo); else { @@ -2418,9 +2384,9 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct uint32_t begin, endp1; if (msg->x.writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) { - DDS_WARNING ("DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n", - PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN), - PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u); + DDS_CWARNING (&rst->gv->logconfig, "DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n", + PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN), + PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u); return 1; } @@ -2451,7 +2417,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct here */ endp1 = msg->sampleSize; } - DDS_TRACE("/[%"PRIu32"..%"PRIu32") of %"PRIu32, begin, endp1, msg->sampleSize); + RSTTRACE ("/[%"PRIu32"..%"PRIu32") of %"PRIu32, begin, endp1, msg->sampleSize); rdata = nn_rdata_new (rmsg, begin, endp1, submsg_offset, payload_offset); @@ -2464,7 +2430,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct dealing with that. */ handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2, rdata, deferred_wakeup); } - DDS_TRACE(")"); + RSTTRACE (")"); return 1; } @@ -2484,12 +2450,7 @@ static size_t decode_container (unsigned char *submsg, size_t len) } #endif /* DDSI_INCLUDE_ENCRYPTION */ -static void malformed_packet_received_nosubmsg -( - const unsigned char * msg, - ssize_t len, - const char *state, - nn_vendorid_t vendorid +static void malformed_packet_received_nosubmsg (const struct q_globals *gv, const unsigned char * msg, ssize_t len, const char *state, nn_vendorid_t vendorid ) { char tmp[1024]; @@ -2503,18 +2464,10 @@ static void malformed_packet_received_nosubmsg if (pos < sizeof (tmp)) pos += (size_t) snprintf (tmp + pos, sizeof (tmp) - pos, "> (note: maybe partially bswap'd)"); assert (pos < sizeof (tmp)); - DDS_WARNING ("%s\n", tmp); + GVWARNING ("%s\n", tmp); } -static void malformed_packet_received -( - const unsigned char *msg, - const unsigned char *submsg, - size_t len, - const char *state, - SubmessageKind_t smkind, - nn_vendorid_t vendorid -) +static void malformed_packet_received (const struct q_globals *gv, const unsigned char *msg, const unsigned char *submsg, size_t len, const char *state, SubmessageKind_t smkind, nn_vendorid_t vendorid) { char tmp[1024]; size_t i, pos, smsize; @@ -2610,7 +2563,7 @@ static void malformed_packet_received break; } - DDS_WARNING ("%s\n", tmp); + GVWARNING ("%s\n", tmp); } static struct receiver_state *rst_cow_if_needed (int *rst_live, struct nn_rmsg *rmsg, struct receiver_state *rst) @@ -2629,6 +2582,7 @@ static struct receiver_state *rst_cow_if_needed (int *rst_live, struct nn_rmsg * static int handle_submsg_sequence ( struct thread_state1 * const ts1, + struct q_globals *gv, ddsi_tran_conn_t conn, const nn_locator_t *srcloc, nn_wctime_t tnowWC, @@ -2646,7 +2600,7 @@ static int handle_submsg_sequence Header_t * hdr = (Header_t *) msg; struct receiver_state *rst; int rst_live, ts_for_latmeas; - nn_ddsi_time_t timestamp; + nn_wctime_t timestamp; size_t submsg_size = 0; unsigned char * end = msg + len; struct nn_dqueue *deferred_wakeup = NULL; @@ -2674,12 +2628,13 @@ static int handle_submsg_sequence rst->vendor = hdr->vendorid; rst->protocol_version = hdr->version; rst->srcloc = *srcloc; + rst->gv = gv; rst_live = 0; ts_for_latmeas = 0; - timestamp = invalid_ddsi_timestamp; + timestamp = NN_WCTIME_INVALID; assert (thread_is_asleep ()); - thread_state_awake (ts1); + thread_state_awake_fixed_domain (ts1); while (submsg <= (end - sizeof (SubmessageHeader_t))) { Submessage_t *sm = (Submessage_t *) submsg; @@ -2712,11 +2667,11 @@ static int handle_submsg_sequence { submsg_size = (unsigned) (end - submsg); } - /*DDS_TRACE(("submsg_size %d\n", submsg_size));*/ + /*GVTRACE ("submsg_size %d\n", submsg_size);*/ if (submsg + submsg_size > end) { - DDS_TRACE(" BREAK (%u %"PRIuSIZE": %p %u)\n", (unsigned) (submsg - msg), submsg_size, (void *) msg, (unsigned) len); + GVTRACE (" BREAK (%u %"PRIuSIZE": %p %u)\n", (unsigned) (submsg - msg), submsg_size, (void *) msg, (unsigned) len); break; } @@ -2725,20 +2680,20 @@ static int handle_submsg_sequence switch (sm->smhdr.submessageId) { case SMID_PAD: - DDS_TRACE("PAD"); + GVTRACE ("PAD"); break; case SMID_ACKNACK: state = "parse:acknack"; - if (!valid_AckNack (&sm->acknack, submsg_size, byteswap)) + if (!valid_AckNack (rst, &sm->acknack, submsg_size, byteswap)) goto malformed; - handle_AckNack (rst, tnowE, &sm->acknack, ts_for_latmeas ? timestamp : invalid_ddsi_timestamp); + handle_AckNack (rst, tnowE, &sm->acknack, ts_for_latmeas ? timestamp : NN_WCTIME_INVALID); ts_for_latmeas = 0; break; case SMID_HEARTBEAT: state = "parse:heartbeat"; if (!valid_Heartbeat (&sm->heartbeat, submsg_size, byteswap)) goto malformed; - handle_Heartbeat (rst, tnowE, rmsg, &sm->heartbeat, ts_for_latmeas ? timestamp : invalid_ddsi_timestamp); + handle_Heartbeat (rst, tnowE, rmsg, &sm->heartbeat, ts_for_latmeas ? timestamp : NN_WCTIME_INVALID); ts_for_latmeas = 0; break; case SMID_GAP: @@ -2757,7 +2712,7 @@ static int handle_submsg_sequence state = "parse:info_ts"; if (!valid_InfoTS (&sm->infots, submsg_size, byteswap)) goto malformed; - handle_InfoTS (&sm->infots, ×tamp); + handle_InfoTS (rst, &sm->infots, ×tamp); ts_for_latmeas = 1; break; case SMID_INFO_SRC: @@ -2772,7 +2727,7 @@ static int handle_submsg_sequence #if 0 state = "parse:info_reply_ip4"; #endif - DDS_TRACE("INFO_REPLY_IP4"); + GVTRACE ("INFO_REPLY_IP4"); /* no effect on ts_for_latmeas */ break; case SMID_INFO_DST: @@ -2787,7 +2742,7 @@ static int handle_submsg_sequence #if 0 state = "parse:info_reply"; #endif - DDS_TRACE("INFO_REPLY"); + GVTRACE ("INFO_REPLY"); /* no effect on ts_for_latmeas */ break; case SMID_NACK_FRAG: @@ -2839,7 +2794,7 @@ static int handle_submsg_sequence if (vendor_is_eclipse_or_prismtech (rst->vendor)) { state = "parse:pt_info_container"; - DDS_TRACE("PT_INFO_CONTAINER("); + GVTRACE ("PT_INFO_CONTAINER("); if (!valid_PT_InfoContainer (&sm->pt_infocontainer, submsg_size, byteswap)) goto malformed; switch (sm->pt_infocontainer.id) @@ -2865,7 +2820,7 @@ static int handle_submsg_sequence #endif /* DDSI_INCLUDE_ENCRYPTION */ break; default: - DDS_TRACE("(unknown id %"PRIu32"?)\n", sm->pt_infocontainer.id); + GVTRACE ("(unknown id %"PRIu32"?)\n", sm->pt_infocontainer.id); } } break; @@ -2874,7 +2829,7 @@ static int handle_submsg_sequence #if 0 state = "parse:msg_len"; #endif - DDS_TRACE("MSG_LEN(%"PRIu32")", ((MsgLen_t*) sm)->length); + GVTRACE ("MSG_LEN(%"PRIu32")", ((MsgLen_t*) sm)->length); break; } case SMID_PT_ENTITY_ID: @@ -2882,12 +2837,12 @@ static int handle_submsg_sequence #if 0 state = "parse:entity_id"; #endif - DDS_TRACE("ENTITY_ID"); + GVTRACE ("ENTITY_ID"); break; } default: state = "parse:undefined"; - DDS_TRACE("UNDEFINED(%x)", sm->smhdr.submessageId); + GVTRACE ("UNDEFINED(%x)", sm->smhdr.submessageId); if (sm->smhdr.submessageId <= 0x7f) { /* Other submessages in the 0 .. 0x7f range may be added in @@ -2916,13 +2871,13 @@ static int handle_submsg_sequence break; } submsg += submsg_size; - DDS_TRACE("\n"); + GVTRACE ("\n"); } if (submsg != end) { state = "parse:shortmsg"; state_smkind = SMID_PAD; - DDS_TRACE("short (size %"PRIuSIZE" exp %p act %p)", submsg_size, (void *) submsg, (void *) end); + GVTRACE ("short (size %"PRIuSIZE" exp %p act %p)", submsg_size, (void *) submsg, (void *) end); goto malformed_asleep; } thread_state_asleep (ts1); @@ -2936,23 +2891,17 @@ malformed: assert (thread_is_asleep ()); malformed_asleep: assert (thread_is_asleep ()); - malformed_packet_received (msg, submsg, len, state, state_smkind, hdr->vendorid); + malformed_packet_received (rst->gv, msg, submsg, len, state, state_smkind, hdr->vendorid); if (deferred_wakeup) dd_dqueue_enqueue_trigger (deferred_wakeup); return -1; } -static bool do_packet -( - struct thread_state1 * const ts1, - ddsi_tran_conn_t conn, - const nn_guid_prefix_t * guidprefix, - struct nn_rbufpool *rbpool -) +static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const nn_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool) { /* UDP max packet size is 64kB */ - const size_t maxsz = config.rmsg_chunk_size < 65536 ? config.rmsg_chunk_size : 65536; + const size_t maxsz = gv->config.rmsg_chunk_size < 65536 ? gv->config.rmsg_chunk_size : 65536; const size_t ddsi_msg_len_size = 8; const size_t stream_hdr_size = RTPS_MESSAGE_HEADER_SIZE + ddsi_msg_len_size; ssize_t sz; @@ -3009,7 +2958,7 @@ static bool do_packet if (ml->smhdr.submessageId != SMID_PT_MSG_LEN) { - malformed_packet_received_nosubmsg (buff, sz, "header", hdr->vendorid); + malformed_packet_received_nosubmsg (gv, buff, sz, "header", hdr->vendorid); sz = -1; } else @@ -3029,7 +2978,7 @@ static bool do_packet sz = ddsi_conn_read (conn, buff, buff_len, true, &srcloc); } - if (sz > 0 && !gv.deaf) + if (sz > 0 && !gv->deaf) { nn_rmsg_setsize (rmsg, (uint32_t) sz); assert (thread_is_asleep ()); @@ -3041,24 +2990,24 @@ static bool do_packet else if (hdr->version.major != RTPS_MAJOR || (hdr->version.major == RTPS_MAJOR && hdr->version.minor < RTPS_MINOR_MINIMUM)) { if ((hdr->version.major == RTPS_MAJOR && hdr->version.minor < RTPS_MINOR_MINIMUM)) - DDS_TRACE("HDR(%"PRIx32":%"PRIx32":%"PRIx32" vendor %d.%d) len %lu\n, version mismatch: %d.%d\n", - PGUIDPREFIX (hdr->guid_prefix), hdr->vendorid.id[0], hdr->vendorid.id[1], (unsigned long) sz, hdr->version.major, hdr->version.minor); - if (NN_PEDANTIC_P) - malformed_packet_received_nosubmsg (buff, sz, "header", hdr->vendorid); + GVTRACE ("HDR(%"PRIx32":%"PRIx32":%"PRIx32" vendor %d.%d) len %lu\n, version mismatch: %d.%d\n", + PGUIDPREFIX (hdr->guid_prefix), hdr->vendorid.id[0], hdr->vendorid.id[1], (unsigned long) sz, hdr->version.major, hdr->version.minor); + if (NN_PEDANTIC_P (gv->config)) + malformed_packet_received_nosubmsg (gv, buff, sz, "header", hdr->vendorid); } else { hdr->guid_prefix = nn_ntoh_guid_prefix (hdr->guid_prefix); - if (dds_get_log_mask() & DDS_LC_TRACE) + if (gv->logconfig.c.mask & DDS_LC_TRACE) { char addrstr[DDSI_LOCSTRLEN]; - ddsi_locator_to_string(addrstr, sizeof(addrstr), &srcloc); - DDS_TRACE("HDR(%"PRIx32":%"PRIx32":%"PRIx32" vendor %d.%d) len %lu from %s\n", - PGUIDPREFIX (hdr->guid_prefix), hdr->vendorid.id[0], hdr->vendorid.id[1], (unsigned long) sz, addrstr); + ddsi_locator_to_string(gv, addrstr, sizeof(addrstr), &srcloc); + GVTRACE ("HDR(%"PRIx32":%"PRIx32":%"PRIx32" vendor %d.%d) len %lu from %s\n", + PGUIDPREFIX (hdr->guid_prefix), hdr->vendorid.id[0], hdr->vendorid.id[1], (unsigned long) sz, addrstr); } - handle_submsg_sequence (ts1, conn, &srcloc, now (), now_et (), &hdr->guid_prefix, guidprefix, buff, (size_t) sz, buff + RTPS_MESSAGE_HEADER_SIZE, rmsg); + handle_submsg_sequence (ts1, gv, conn, &srcloc, now (), now_et (), &hdr->guid_prefix, guidprefix, buff, (size_t) sz, buff + RTPS_MESSAGE_HEADER_SIZE, rmsg); } } nn_rmsg_commit (rmsg); @@ -3107,15 +3056,15 @@ static size_t dedup_sorted_array (void *base, size_t nel, size_t width, int (*co struct local_participant_set { struct local_participant_desc *ps; - unsigned nps; + uint32_t nps; uint32_t gen; }; -static void local_participant_set_init (struct local_participant_set *lps) +static void local_participant_set_init (struct local_participant_set *lps, ddsrt_atomic_uint32_t *ppset_generation) { lps->ps = NULL; lps->nps = 0; - lps->gen = ddsrt_atomic_ld32 (&gv.participant_set_generation) - 1; + lps->gen = ddsrt_atomic_ld32 (ppset_generation) - 1; } static void local_participant_set_fini (struct local_participant_set *lps) @@ -3123,23 +3072,23 @@ static void local_participant_set_fini (struct local_participant_set *lps) ddsrt_free (lps->ps); } -static void rebuild_local_participant_set (struct thread_state1 * const ts1, struct local_participant_set *lps) +static void rebuild_local_participant_set (struct thread_state1 * const ts1, struct q_globals *gv, struct local_participant_set *lps) { struct ephash_enum_participant est; struct participant *pp; unsigned nps_alloc; - DDS_TRACE("pp set gen changed: local %"PRIu32" global %"PRIu32"\n", lps->gen, ddsrt_atomic_ld32(&gv.participant_set_generation)); - thread_state_awake (ts1); + GVTRACE ("pp set gen changed: local %"PRIu32" global %"PRIu32"\n", lps->gen, ddsrt_atomic_ld32 (&gv->participant_set_generation)); + thread_state_awake_fixed_domain (ts1); restart: - lps->gen = ddsrt_atomic_ld32 (&gv.participant_set_generation); + lps->gen = ddsrt_atomic_ld32 (&gv->participant_set_generation); /* Actual local set of participants may never be older than the local generation count => membar to guarantee the ordering */ ddsrt_atomic_fence_acq (); - nps_alloc = gv.nparticipants; + nps_alloc = gv->nparticipants; ddsrt_free (lps->ps); lps->nps = 0; lps->ps = (nps_alloc == 0) ? NULL : ddsrt_malloc (nps_alloc * sizeof (*lps->ps)); - ephash_enum_participant_init (&est); + ephash_enum_participant_init (&est, gv->guid_hash); while ((pp = ephash_enum_participant_next (&est)) != NULL) { if (lps->nps == nps_alloc) @@ -3149,14 +3098,14 @@ static void rebuild_local_participant_set (struct thread_state1 * const ts1, str turns out we didn't allocate enough memory [an alternative would be to realloc on the fly]. */ ephash_enum_participant_fini (&est); - DDS_TRACE(" need more memory - restarting\n"); + GVTRACE (" need more memory - restarting\n"); goto restart; } else { lps->ps[lps->nps].m_conn = pp->m_conn; lps->ps[lps->nps].guid_prefix = pp->e.guid.prefix; - DDS_TRACE(" pp "PGUIDFMT" handle %"PRIdSOCK"\n", PGUID (pp->e.guid), ddsi_conn_handle (pp->m_conn)); + GVTRACE (" pp "PGUIDFMT" handle %"PRIdSOCK"\n", PGUID (pp->e.guid), ddsi_conn_handle (pp->m_conn)); lps->nps++; } } @@ -3169,9 +3118,9 @@ static void rebuild_local_participant_set (struct thread_state1 * const ts1, str explicit destination. Membar because we must have completed the loop before testing the generation again. */ ddsrt_atomic_fence_acq (); - if (lps->gen != ddsrt_atomic_ld32 (&gv.participant_set_generation)) + if (lps->gen != ddsrt_atomic_ld32 (&gv->participant_set_generation)) { - DDS_TRACE(" set changed - restarting\n"); + GVTRACE (" set changed - restarting\n"); goto restart; } thread_state_asleep (ts1); @@ -3186,22 +3135,23 @@ static void rebuild_local_participant_set (struct thread_state1 * const ts1, str qsort (lps->ps, lps->nps, sizeof (*lps->ps), local_participant_cmp); lps->nps = (unsigned) dedup_sorted_array (lps->ps, lps->nps, sizeof (*lps->ps), local_participant_cmp); } - DDS_TRACE(" nparticipants %u\n", lps->nps); + GVTRACE (" nparticipants %u\n", lps->nps); } -uint32_t listen_thread (struct ddsi_tran_listener * listener) +uint32_t listen_thread (struct ddsi_tran_listener *listener) { + struct q_globals *gv = listener->m_base.gv; ddsi_tran_conn_t conn; - while (gv.rtps_keepgoing) + while (ddsrt_atomic_ld32 (&gv->rtps_keepgoing)) { /* Accept connection from listener */ conn = ddsi_listener_accept (listener); if (conn) { - os_sockWaitsetAdd (gv.recv_threads[0].arg.u.many.ws, conn); - os_sockWaitsetTrigger (gv.recv_threads[0].arg.u.many.ws); + os_sockWaitsetAdd (gv->recv_threads[0].arg.u.many.ws, conn); + os_sockWaitsetTrigger (gv->recv_threads[0].arg.u.many.ws); } } return 0; @@ -3209,13 +3159,16 @@ uint32_t listen_thread (struct ddsi_tran_listener * listener) static int recv_thread_waitset_add_conn (os_sockWaitset ws, ddsi_tran_conn_t conn) { - unsigned i; if (conn == NULL) return 0; - for (i = 0; i < gv.n_recv_threads; i++) - if (gv.recv_threads[i].arg.mode == RTM_SINGLE && gv.recv_threads[i].arg.u.single.conn == conn) - return 0; - return os_sockWaitsetAdd (ws, conn); + else + { + struct q_globals *gv = conn->m_base.gv; + for (uint32_t i = 0; i < gv->n_recv_threads; i++) + if (gv->recv_threads[i].arg.mode == RTM_SINGLE && gv->recv_threads[i].arg.u.single.conn == conn) + return 0; + return os_sockWaitsetAdd (ws, conn); + } } enum local_deaf_state_recover { @@ -3229,12 +3182,12 @@ struct local_deaf_state { nn_mtime_t tnext; }; -static int check_and_handle_deafness_recover(struct local_deaf_state *st, unsigned num_fixed_uc) +static int check_and_handle_deafness_recover (struct q_globals *gv, struct local_deaf_state *st, unsigned num_fixed_uc) { int rebuildws = 0; if (now_mt().v < st->tnext.v) { - DDS_TRACE("check_and_handle_deafness_recover: state %d too early\n", (int)st->state); + GVTRACE ("check_and_handle_deafness_recover: state %d too early\n", (int)st->state); return 0; } switch (st->state) @@ -3243,21 +3196,21 @@ static int check_and_handle_deafness_recover(struct local_deaf_state *st, unsign assert(0); break; case LDSR_DEAF: { - ddsi_tran_conn_t disc = gv.disc_conn_mc, data = gv.data_conn_mc; - DDS_TRACE("check_and_handle_deafness_recover: state %d create new sockets\n", (int)st->state); - if (!create_multicast_sockets()) + ddsi_tran_conn_t disc = gv->disc_conn_mc, data = gv->data_conn_mc; + GVTRACE ("check_and_handle_deafness_recover: state %d create new sockets\n", (int) st->state); + if (!create_multicast_sockets (gv)) goto error; - DDS_TRACE("check_and_handle_deafness_recover: state %d transfer group membership admin\n", (int)st->state); - ddsi_transfer_group_membership(disc, gv.disc_conn_mc); - ddsi_transfer_group_membership(data, gv.data_conn_mc); - DDS_TRACE("check_and_handle_deafness_recover: state %d drop from waitset and add new\n", (int)st->state); + GVTRACE ("check_and_handle_deafness_recover: state %d transfer group membership admin\n", (int) st->state); + ddsi_transfer_group_membership (gv->mship, disc, gv->disc_conn_mc); + ddsi_transfer_group_membership (gv->mship, data, gv->data_conn_mc); + GVTRACE ("check_and_handle_deafness_recover: state %d drop from waitset and add new\n", (int) st->state); /* see waitset construction code in recv_thread */ - os_sockWaitsetPurge (gv.recv_threads[0].arg.u.many.ws, num_fixed_uc); - if (recv_thread_waitset_add_conn (gv.recv_threads[0].arg.u.many.ws, gv.disc_conn_mc) < 0) + os_sockWaitsetPurge (gv->recv_threads[0].arg.u.many.ws, num_fixed_uc); + if (recv_thread_waitset_add_conn (gv->recv_threads[0].arg.u.many.ws, gv->disc_conn_mc) < 0) DDS_FATAL("check_and_handle_deafness_recover: failed to add disc_conn_mc to waitset\n"); - if (recv_thread_waitset_add_conn (gv.recv_threads[0].arg.u.many.ws, gv.data_conn_mc) < 0) + if (recv_thread_waitset_add_conn (gv->recv_threads[0].arg.u.many.ws, gv->data_conn_mc) < 0) DDS_FATAL("check_and_handle_deafness_recover: failed to add data_conn_mc to waitset\n"); - DDS_TRACE("check_and_handle_deafness_recover: state %d close sockets\n", (int)st->state); + GVTRACE ("check_and_handle_deafness_recover: state %d close sockets\n", (int)st->state); ddsi_conn_free(disc); ddsi_conn_free(data); rebuildws = 1; @@ -3265,73 +3218,72 @@ static int check_and_handle_deafness_recover(struct local_deaf_state *st, unsign } /* FALLS THROUGH */ case LDSR_REJOIN: - DDS_TRACE("check_and_handle_deafness_recover: state %d rejoin on disc socket\n", (int)st->state); - if (ddsi_rejoin_transferred_mcgroups(gv.disc_conn_mc) < 0) + GVTRACE ("check_and_handle_deafness_recover: state %d rejoin on disc socket\n", (int)st->state); + if (ddsi_rejoin_transferred_mcgroups (gv, gv->mship, gv->disc_conn_mc) < 0) goto error; - DDS_TRACE("check_and_handle_deafness_recover: state %d rejoin on data socket\n", (int)st->state); - if (ddsi_rejoin_transferred_mcgroups(gv.data_conn_mc) < 0) + GVTRACE ("check_and_handle_deafness_recover: state %d rejoin on data socket\n", (int)st->state); + if (ddsi_rejoin_transferred_mcgroups (gv, gv->mship, gv->data_conn_mc) < 0) goto error; - DDS_TRACE("check_and_handle_deafness_recover: state %d done\n", (int)st->state); + GVTRACE ("check_and_handle_deafness_recover: state %d done\n", (int)st->state); st->state = LDSR_NORMAL; break; } - DDS_TRACE("check_and_handle_deafness_recover: state %d returning %d\n", (int)st->state, rebuildws); + GVTRACE ("check_and_handle_deafness_recover: state %d returning %d\n", (int)st->state, rebuildws); return rebuildws; error: -DDS_TRACE("check_and_handle_deafness_recover: state %d failed, returning %d\n", (int)st->state, rebuildws); + GVTRACE ("check_and_handle_deafness_recover: state %d failed, returning %d\n", (int)st->state, rebuildws); st->state = LDSR_DEAF; st->tnext = add_duration_to_mtime(now_mt(), T_SECOND); return rebuildws; } -static int check_and_handle_deafness(struct local_deaf_state *st, unsigned num_fixed_uc) +static int check_and_handle_deafness (struct q_globals *gv, struct local_deaf_state *st, unsigned num_fixed_uc) { - const int gv_deaf = gv.deaf; + const int gv_deaf = gv->deaf; assert (gv_deaf == 0 || gv_deaf == 1); if (gv_deaf == (int)st->state) return 0; else if (gv_deaf) { - DDS_TRACE("check_and_handle_deafness: going deaf (%d -> %d)\n", (int)st->state, (int)LDSR_DEAF); + GVTRACE ("check_and_handle_deafness: going deaf (%d -> %d)\n", (int)st->state, (int)LDSR_DEAF); st->state = LDSR_DEAF; st->tnext = now_mt(); return 0; } - else if (!config.allowMulticast) + else if (!gv->config.allowMulticast) { - DDS_TRACE("check_and_handle_deafness: no longer deaf (multicast disabled)\n"); + GVTRACE ("check_and_handle_deafness: no longer deaf (multicast disabled)\n"); st->state = LDSR_NORMAL; return 0; } else { - return check_and_handle_deafness_recover(st, num_fixed_uc); + return check_and_handle_deafness_recover (gv, st, num_fixed_uc); } } -void trigger_recv_threads (void) +void trigger_recv_threads (const struct q_globals *gv) { - unsigned i; - for (i = 0; i < gv.n_recv_threads; i++) + for (uint32_t i = 0; i < gv->n_recv_threads; i++) { - if (gv.recv_threads[i].ts == NULL) + if (gv->recv_threads[i].ts == NULL) continue; - switch (gv.recv_threads[i].arg.mode) + switch (gv->recv_threads[i].arg.mode) { case RTM_SINGLE: { char buf[DDSI_LOCSTRLEN]; char dummy = 0; - const nn_locator_t *dst = gv.recv_threads[i].arg.u.single.loc; + const nn_locator_t *dst = gv->recv_threads[i].arg.u.single.loc; ddsrt_iovec_t iov; iov.iov_base = &dummy; iov.iov_len = 1; - DDS_TRACE("trigger_recv_threads: %d single %s\n", i, ddsi_locator_to_string (buf, sizeof (buf), dst)); - ddsi_conn_write (gv.data_conn_uc, dst, 1, &iov, 0); + GVTRACE ("trigger_recv_threads: %d single %s\n", i, ddsi_locator_to_string (gv, buf, sizeof (buf), dst)); + ddsi_conn_write (gv->data_conn_uc, dst, 1, &iov, 0); break; } case RTM_MANY: { - DDS_TRACE("trigger_recv_threads: %d many %p\n", i, (void *) gv.recv_threads[i].arg.u.many.ws); - os_sockWaitsetTrigger (gv.recv_threads[i].arg.u.many.ws); + GVTRACE ("trigger_recv_threads: %d many %p\n", i, (void *) gv->recv_threads[i].arg.u.many.ws); + os_sockWaitsetTrigger (gv->recv_threads[i].arg.u.many.ws); break; } } @@ -3342,6 +3294,7 @@ uint32_t recv_thread (void *vrecv_thread_arg) { struct thread_state1 * const ts1 = lookup_thread_state (); struct recv_thread_arg *recv_thread_arg = vrecv_thread_arg; + struct q_globals * const gv = recv_thread_arg->gv; struct nn_rbufpool *rbpool = recv_thread_arg->rbpool; os_sockWaitset waitset = recv_thread_arg->mode == RTM_MANY ? recv_thread_arg->u.many.ws : NULL; nn_mtime_t next_thread_cputime = { 0 }; @@ -3349,10 +3302,11 @@ uint32_t recv_thread (void *vrecv_thread_arg) nn_rbufpool_setowner (rbpool, ddsrt_thread_self ()); if (waitset == NULL) { - while (gv.rtps_keepgoing) + struct ddsi_tran_conn *conn = recv_thread_arg->u.single.conn; + while (ddsrt_atomic_ld32 (&gv->rtps_keepgoing)) { - LOG_THREAD_CPUTIME (next_thread_cputime); - (void) do_packet (ts1, recv_thread_arg->u.single.conn, NULL, rbpool); + LOG_THREAD_CPUTIME (&gv->logconfig, next_thread_cputime); + (void) do_packet (ts1, gv, conn, NULL, rbpool); } } else @@ -3360,50 +3314,49 @@ uint32_t recv_thread (void *vrecv_thread_arg) struct local_participant_set lps; unsigned num_fixed = 0, num_fixed_uc = 0; os_sockWaitsetCtx ctx; - unsigned i; struct local_deaf_state lds; - lds.state = gv.deaf ? LDSR_DEAF : LDSR_NORMAL; + lds.state = gv->deaf ? LDSR_DEAF : LDSR_NORMAL; lds.tnext = now_mt(); - local_participant_set_init (&lps); - if (gv.m_factory->m_connless) + local_participant_set_init (&lps, &gv->participant_set_generation); + if (gv->m_factory->m_connless) { int rc; - if ((rc = recv_thread_waitset_add_conn (waitset, gv.disc_conn_uc)) < 0) + if ((rc = recv_thread_waitset_add_conn (waitset, gv->disc_conn_uc)) < 0) DDS_FATAL("recv_thread: failed to add disc_conn_uc to waitset\n"); num_fixed_uc += (unsigned)rc; - if ((rc = recv_thread_waitset_add_conn (waitset, gv.data_conn_uc)) < 0) + if ((rc = recv_thread_waitset_add_conn (waitset, gv->data_conn_uc)) < 0) DDS_FATAL("recv_thread: failed to add data_conn_uc to waitset\n"); num_fixed_uc += (unsigned)rc; num_fixed += num_fixed_uc; - if ((rc = recv_thread_waitset_add_conn (waitset, gv.disc_conn_mc)) < 0) + if ((rc = recv_thread_waitset_add_conn (waitset, gv->disc_conn_mc)) < 0) DDS_FATAL("recv_thread: failed to add disc_conn_mc to waitset\n"); num_fixed += (unsigned)rc; - if ((rc = recv_thread_waitset_add_conn (waitset, gv.data_conn_mc)) < 0) + if ((rc = recv_thread_waitset_add_conn (waitset, gv->data_conn_mc)) < 0) DDS_FATAL("recv_thread: failed to add data_conn_mc to waitset\n"); num_fixed += (unsigned)rc; } - while (gv.rtps_keepgoing) + while (ddsrt_atomic_ld32 (&gv->rtps_keepgoing)) { int rebuildws; - LOG_THREAD_CPUTIME (next_thread_cputime); - rebuildws = check_and_handle_deafness(&lds, num_fixed_uc); - if (config.many_sockets_mode != MSM_MANY_UNICAST) + LOG_THREAD_CPUTIME (&gv->logconfig, next_thread_cputime); + rebuildws = check_and_handle_deafness (gv, &lds, num_fixed_uc); + if (gv->config.many_sockets_mode != MSM_MANY_UNICAST) { /* no other sockets to check */ } - else if (ddsrt_atomic_ld32 (&gv.participant_set_generation) != lps.gen) + else if (ddsrt_atomic_ld32 (&gv->participant_set_generation) != lps.gen) { rebuildws = 1; } - if (rebuildws && waitset && config.many_sockets_mode == MSM_MANY_UNICAST) + if (rebuildws && waitset && gv->config.many_sockets_mode == MSM_MANY_UNICAST) { /* first rebuild local participant set - unless someone's toggling "deafness", this only happens when the participant set has changed, so might as well rebuild it */ - rebuild_local_participant_set (ts1, &lps); + rebuild_local_participant_set (ts1, gv, &lps); os_sockWaitsetPurge (waitset, num_fixed); - for (i = 0; i < lps.nps; i++) + for (uint32_t i = 0; i < lps.nps; i++) { if (lps.ps[i].m_conn) os_sockWaitsetAdd (waitset, lps.ps[i].m_conn); @@ -3417,12 +3370,12 @@ uint32_t recv_thread (void *vrecv_thread_arg) while ((idx = os_sockWaitsetNextEvent (ctx, &conn)) >= 0) { const nn_guid_prefix_t *guid_prefix; - if (((unsigned)idx < num_fixed) || config.many_sockets_mode != MSM_MANY_UNICAST) + if (((unsigned)idx < num_fixed) || gv->config.many_sockets_mode != MSM_MANY_UNICAST) guid_prefix = NULL; else guid_prefix = &lps.ps[(unsigned)idx - num_fixed].guid_prefix; /* Process message and clean out connection if failed or closed */ - if (!do_packet (ts1, conn, guid_prefix, rbpool) && !conn->m_connless) + if (!do_packet (ts1, gv, conn, guid_prefix, rbpool) && !conn->m_connless) ddsi_conn_free (conn); } } diff --git a/src/core/ddsi/src/ddsi_rhc_plugin.c b/src/core/ddsi/src/q_rhc.c similarity index 50% rename from src/core/ddsi/src/ddsi_rhc_plugin.c rename to src/core/ddsi/src/q_rhc.c index 969c753..187521f 100644 --- a/src/core/ddsi/src/ddsi_rhc_plugin.c +++ b/src/core/ddsi/src/q_rhc.c @@ -9,11 +9,17 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_rhc.h" #include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/ddsi_rhc_plugin.h" +#include "dds/ddsi/q_entity.h" -DDS_EXPORT void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct nn_xqos *xqos) +extern inline void rhc_free (struct rhc *rhc); +extern inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); +extern inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info); +extern inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid); +extern inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos); + +void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos) { pwr_info->guid = e->guid; pwr_info->ownership_strength = xqos->ownership_strength.value; diff --git a/src/core/ddsi/src/q_security.c b/src/core/ddsi/src/q_security.c index 408c077..0a94204 100644 --- a/src/core/ddsi/src/q_security.c +++ b/src/core/ddsi/src/q_security.c @@ -14,7 +14,6 @@ #include "dds/ddsi/q_security.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_error.h" #include "os/os_stdlib.h" #include "os/os_process.h" #include "os/os_thread.h" @@ -1657,16 +1656,15 @@ static os_ssize_t q_security_sendmsg char stbuf[2048], *buf; size_t sz, data_size; uint32_t sz32, data_size32; - ssize_t ret = Q_ERR_UNSPECIFIED; + ssize_t ret = DDS_RETCODE_ERROR; PT_InfoContainer_t * securityHeader; - unsigned i; assert (niov > 2); securityHeader = iov[1].iov_base; /* first determine the size of the message, then select the on-stack buffer or allocate one on the heap ... */ sz = q_securityEncoderSetHeaderSize (*codec); /* reserve appropriate headersize */ - for (i = 2; i < niov; i++) + for (uint32_t i = 2; i < niov; i++) { sz += iov[i].iov_len; } @@ -1680,7 +1678,7 @@ static os_ssize_t q_security_sendmsg } /* ... then copy data into buffer */ data_size = 0; - for (i = 2; i < niov; i++) + for (uint32_t i = 2; i < niov; i++) { memcpy (buf + data_size, iov[i].iov_base, iov[i].iov_len); data_size += iov[i].iov_len; diff --git a/src/core/ddsi/src/q_sockwaitset.c b/src/core/ddsi/src/q_sockwaitset.c index f8a761f..e0cecef 100644 --- a/src/core/ddsi/src/q_sockwaitset.c +++ b/src/core/ddsi/src/q_sockwaitset.c @@ -118,7 +118,7 @@ os_sockWaitset os_sockWaitsetNew (void) ws->ctx.nevs = 0; ws->ctx.index = 0; ws->ctx.evs_sz = sz; - if ((ws->ctx.evs = malloc (ws->ctx.evs_sz * sizeof (*ws->ctx.evs))) == NULL) + if ((ws->ctx.evs = ddsrt_malloc (ws->ctx.evs_sz * sizeof (*ws->ctx.evs))) == NULL) goto fail_ctx_evs; if ((ws->kqueue = kqueue ()) == -1) goto fail_kqueue; @@ -311,9 +311,7 @@ os_sockWaitset os_sockWaitsetNew (void) void os_sockWaitsetFree (os_sockWaitset ws) { - unsigned i; - - for (i = 0; i < ws->ctx.n; i++) + for (unsigned i = 0; i < ws->ctx.n; i++) { WSACloseEvent (ws->ctx.events[i]); } @@ -323,10 +321,8 @@ void os_sockWaitsetFree (os_sockWaitset ws) void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index) { - unsigned i; - ddsrt_mutex_lock (&ws->mutex); - for (i = index + 1; i < ws->ctx.n; i++) + for (unsigned i = index + 1; i < ws->ctx.n; i++) { ws->ctx.conns[i] = NULL; if (!WSACloseEvent (ws->ctx.events[i])) @@ -340,10 +336,8 @@ void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index) void os_sockWaitsetRemove (os_sockWaitset ws, ddsi_tran_conn_t conn) { - unsigned i; - ddsrt_mutex_lock (&ws->mutex); - for (i = 0; i < ws->ctx.n; i++) + for (unsigned i = 0; i < ws->ctx.n; i++) { if (conn == ws->ctx.conns[i]) { @@ -509,7 +503,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 @@ -524,7 +518,7 @@ int os_sockWaitsetNextEvent (os_sockWaitsetCtx ctx, ddsi_tran_conn_t * conn) #include #endif -#endif /* _WIN32 */ +#endif /* !_WIN32 && !LWIP_SOCKET */ typedef struct os_sockWaitsetSet { @@ -586,7 +580,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 +603,7 @@ fail_open0: fail_pipedev: return -1; } -#else +#elif !defined(LWIP_SOCKET) static int make_pipe (int pfd[2]) { return pipe (pfd); @@ -644,7 +638,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 +677,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 +720,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 +742,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 +757,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) @@ -791,13 +799,12 @@ int os_sockWaitsetAdd (os_sockWaitset ws, ddsi_tran_conn_t conn) void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index) { - unsigned i; os_sockWaitsetSet * set = &ws->set; ddsrt_mutex_lock (&ws->mutex); if (index + 1 <= set->n) { - for (i = index + 1; i < set->n; i++) + for (unsigned i = index + 1; i < set->n; i++) { set->conns[i] = NULL; set->fds[i] = 0; @@ -809,11 +816,10 @@ void os_sockWaitsetPurge (os_sockWaitset ws, unsigned index) void os_sockWaitsetRemove (os_sockWaitset ws, ddsi_tran_conn_t conn) { - unsigned i; os_sockWaitsetSet * set = &ws->set; ddsrt_mutex_lock (&ws->mutex); - for (i = 0; i < set->n; i++) + for (unsigned i = 0; i < set->n; i++) { if (conn == set->conns[i]) { @@ -863,14 +869,23 @@ 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 { - dds_retcode_t rc = ddsrt_select (fdmax, rdset, NULL, NULL, DDS_INFINITY, &n); + dds_return_t rc = ddsrt_select (fdmax, rdset, NULL, NULL, DDS_INFINITY, &n); if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_INTERRUPTED && rc != DDS_RETCODE_TRY_AGAIN) { DDS_WARNING("os_sockWaitsetWait: select failed, retcode = %"PRId32, rc); @@ -883,6 +898,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 +914,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 +944,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 diff --git a/src/core/ddsi/src/q_thread.c b/src/core/ddsi/src/q_thread.c index 6cf4a47..171888a 100644 --- a/src/core/ddsi/src/q_thread.c +++ b/src/core/ddsi/src/q_thread.c @@ -23,7 +23,6 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/ddsi_threadmon.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_globals.h" @@ -42,12 +41,14 @@ extern inline struct thread_state1 *lookup_thread_state (void); extern inline bool thread_is_asleep (void); extern inline bool thread_is_awake (void); extern inline void thread_state_asleep (struct thread_state1 *ts1); -extern inline void thread_state_awake (struct thread_state1 *ts1); +extern inline void thread_state_awake (struct thread_state1 *ts1, const struct q_globals *gv); +extern inline void thread_state_awake_domain_ok (struct thread_state1 *ts1); +extern inline void thread_state_awake_fixed_domain (struct thread_state1 *ts1); extern inline void thread_state_awake_to_awake_no_nest (struct thread_state1 *ts1); -static struct thread_state1 *init_thread_state (const char *tname, enum thread_state state); +static struct thread_state1 *init_thread_state (const char *tname, const struct q_globals *gv, enum thread_state state); -void *ddsrt_malloc_aligned_cacheline (size_t size) +static void *ddsrt_malloc_aligned_cacheline (size_t size) { /* This wastes some space, but we use it only once and it isn't a huge amount of memory, just a little over a cache line. @@ -76,35 +77,32 @@ static void ddsrt_free_aligned (void *ptr) void thread_states_init_static (void) { static struct thread_state1 ts = { - .state = THREAD_STATE_ALIVE, .vtime = 0u, .name = "(anon)" + .state = THREAD_STATE_ALIVE, .vtime = DDSRT_ATOMIC_UINT32_INIT (0), .name = "(anon)" }; tsd_thread_state = &ts; } void thread_states_init (unsigned maxthreads) { - unsigned i; - ddsrt_mutex_init (&thread_states.lock); thread_states.nthreads = maxthreads; thread_states.ts = ddsrt_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts)); memset (thread_states.ts, 0, maxthreads * sizeof (*thread_states.ts)); -/* The compiler doesn't realize that ts is large enough. */ -DDSRT_WARNING_MSVC_OFF(6386); - for (i = 0; i < thread_states.nthreads; i++) + /* The compiler doesn't realize that ts is large enough. */ + DDSRT_WARNING_MSVC_OFF(6386); + for (uint32_t i = 0; i < thread_states.nthreads; i++) { thread_states.ts[i].state = THREAD_STATE_ZERO; - thread_states.ts[i].vtime = 0u; - thread_states.ts[i].name = NULL; + ddsrt_atomic_st32 (&thread_states.ts[i].vtime, 0); + memset (thread_states.ts[i].name, 0, sizeof (thread_states.ts[i].name)); } -DDSRT_WARNING_MSVC_ON(6386); + DDSRT_WARNING_MSVC_ON(6386); } void thread_states_fini (void) { - unsigned i; - for (i = 0; i < thread_states.nthreads; i++) + for (uint32_t i = 0; i < thread_states.nthreads; i++) assert (thread_states.ts[i].state != THREAD_STATE_ALIVE); ddsrt_mutex_destroy (&thread_states.lock); ddsrt_free_aligned (thread_states.ts); @@ -117,14 +115,14 @@ void thread_states_fini (void) thread_states.ts = NULL; } +ddsrt_attribute_no_sanitize (("thread")) static struct thread_state1 *find_thread_state (ddsrt_thread_t tid) { if (thread_states.ts) { - unsigned i; - for (i = 0; i < thread_states.nthreads; i++) { - if (ddsrt_thread_equal (thread_states.ts[i].tid, tid)) { + for (uint32_t i = 0; i < thread_states.nthreads; i++) + { + if (ddsrt_thread_equal (thread_states.ts[i].tid, tid)) return &thread_states.ts[i]; - } } } return NULL; @@ -137,7 +135,7 @@ static void cleanup_thread_state (void *data) if (ts) { assert(ts->state == THREAD_STATE_LAZILY_CREATED); - assert(vtime_asleep_p(ts->vtime)); + assert(vtime_asleep_p(ddsrt_atomic_ld32 (&ts->vtime))); reset_thread_state(ts); } ddsrt_fini(); @@ -152,11 +150,11 @@ static struct thread_state1 *lazy_create_thread_state (ddsrt_thread_t self) char name[128]; ddsrt_thread_getname (name, sizeof (name)); ddsrt_mutex_lock (&thread_states.lock); - if ((ts1 = init_thread_state (name, THREAD_STATE_LAZILY_CREATED)) != NULL) { + if ((ts1 = init_thread_state (name, NULL, THREAD_STATE_LAZILY_CREATED)) != NULL) { ddsrt_init (); ts1->extTid = self; ts1->tid = self; - DDS_TRACE ("started application thread %s\n", name); + DDS_LOG (DDS_LC_TRACE, "started application thread %s\n", name); ddsrt_thread_cleanup_push (&cleanup_thread_state, NULL); } ddsrt_mutex_unlock (&thread_states.lock); @@ -187,7 +185,9 @@ static uint32_t create_thread_wrapper (void *ptr) { uint32_t ret; struct thread_context *ctx = ptr; - DDS_TRACE ("started new thread %"PRIdTID": %s\n", ddsrt_gettid (), ctx->self->name); + struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&ctx->self->gv); + if (gv) + GVTRACE ("started new thread %"PRIdTID": %s\n", ddsrt_gettid (), ctx->self->name); ctx->self->tid = ddsrt_thread_self (); ret = ctx->f (ctx->arg); ddsrt_free (ctx); @@ -196,10 +196,10 @@ static uint32_t create_thread_wrapper (void *ptr) static int find_free_slot (const char *name) { - for (unsigned i = 0; i < thread_states.nthreads; i++) + for (uint32_t i = 0; i < thread_states.nthreads; i++) if (thread_states.ts[i].state == THREAD_STATE_ZERO) return (int) i; - DDS_FATAL("create_thread: %s: no free slot\n", name ? name : "(anon)"); + DDS_FATAL ("create_thread: %s: no free slot\n", name ? name : "(anon)"); return -1; } @@ -212,24 +212,27 @@ void upgrade_main_thread (void) abort (); ts1 = &thread_states.ts[cand]; if (ts1->state == THREAD_STATE_ZERO) - assert (vtime_asleep_p (ts1->vtime)); + assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime))); ts1->state = THREAD_STATE_LAZILY_CREATED; ts1->tid = ddsrt_thread_self (); - ts1->name = main_thread_name; + DDSRT_WARNING_MSVC_OFF(4996); + strncpy (ts1->name, main_thread_name, sizeof (ts1->name)); + DDSRT_WARNING_MSVC_ON(4996); + ts1->name[sizeof (ts1->name) - 1] = 0; ddsrt_mutex_unlock (&thread_states.lock); tsd_thread_state = ts1; } -const struct config_thread_properties_listelem *lookup_thread_properties (const char *name) +const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name) { const struct config_thread_properties_listelem *e; - for (e = config.thread_properties; e != NULL; e = e->next) + for (e = config->thread_properties; e != NULL; e = e->next) if (strcmp (e->name, name) == 0) break; return e; } -static struct thread_state1 *init_thread_state (const char *tname, enum thread_state state) +static struct thread_state1 *init_thread_state (const char *tname, const struct q_globals *gv, enum thread_state state) { int cand; struct thread_state1 *ts; @@ -238,23 +241,26 @@ static struct thread_state1 *init_thread_state (const char *tname, enum thread_s return NULL; ts = &thread_states.ts[cand]; - assert (vtime_asleep_p (ts->vtime)); - ts->name = ddsrt_strdup (tname); + ddsrt_atomic_stvoidp (&ts->gv, (struct q_globals *) gv); + assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts->vtime))); + DDSRT_WARNING_MSVC_OFF(4996); + strncpy (ts->name, tname, sizeof (ts->name)); + DDSRT_WARNING_MSVC_ON(4996); + ts->name[sizeof (ts->name) - 1] = 0; ts->state = state; return ts; } -dds_retcode_t create_thread (struct thread_state1 **ts1, const char *name, uint32_t (*f) (void *arg), void *arg) +static dds_return_t create_thread_int (struct thread_state1 **ts1, const struct q_globals *gv, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg) { - struct config_thread_properties_listelem const * const tprops = lookup_thread_properties (name); ddsrt_threadattr_t tattr; ddsrt_thread_t tid; struct thread_context *ctxt; ctxt = ddsrt_malloc (sizeof (*ctxt)); ddsrt_mutex_lock (&thread_states.lock); - *ts1 = init_thread_state (name, THREAD_STATE_ALIVE); + *ts1 = init_thread_state (name, gv, THREAD_STATE_ALIVE); if (*ts1 == NULL) goto fatal; @@ -270,18 +276,21 @@ dds_retcode_t create_thread (struct thread_state1 **ts1, const char *name, uint3 if (!tprops->stack_size.isdefault) tattr.stackSize = tprops->stack_size.value; } - DDS_TRACE("create_thread: %s: class %d priority %"PRId32" stack %"PRIu32"\n", name, (int) tattr.schedClass, tattr.schedPriority, tattr.stackSize); + if (gv) + { + GVTRACE ("create_thread: %s: class %d priority %"PRId32" stack %"PRIu32"\n", name, (int) tattr.schedClass, tattr.schedPriority, tattr.stackSize); + } if (ddsrt_thread_create (&tid, name, &tattr, &create_thread_wrapper, ctxt) != DDS_RETCODE_OK) { (*ts1)->state = THREAD_STATE_ZERO; - DDS_FATAL("create_thread: %s: ddsrt_thread_create failed\n", name); + DDS_FATAL ("create_thread: %s: ddsrt_thread_create failed\n", name); goto fatal; } (*ts1)->extTid = tid; /* overwrite the temporary value with the correct external one */ ddsrt_mutex_unlock (&thread_states.lock); return DDS_RETCODE_OK; - fatal: +fatal: ddsrt_mutex_unlock (&thread_states.lock); ddsrt_free (ctxt); *ts1 = NULL; @@ -289,56 +298,57 @@ dds_retcode_t create_thread (struct thread_state1 **ts1, const char *name, uint3 return DDS_RETCODE_ERROR; } -static void reap_thread_state (struct thread_state1 *ts1, int sync_with_servicelease) +dds_return_t create_thread_with_properties (struct thread_state1 **ts1, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg) +{ + return create_thread_int (ts1, NULL, tprops, name, f, arg); +} + +dds_return_t create_thread (struct thread_state1 **ts1, const struct q_globals *gv, const char *name, uint32_t (*f) (void *arg), void *arg) +{ + struct config_thread_properties_listelem const * const tprops = lookup_thread_properties (&gv->config, name); + return create_thread_int (ts1, gv, tprops, name, f, arg); +} + +static void reap_thread_state (struct thread_state1 *ts1) { ddsrt_mutex_lock (&thread_states.lock); ts1->state = THREAD_STATE_ZERO; - if (sync_with_servicelease && gv.threadmon) - ddsi_threadmon_statechange_barrier (gv.threadmon); - if (ts1->name != main_thread_name) - ddsrt_free (ts1->name); ddsrt_mutex_unlock (&thread_states.lock); } -int join_thread (struct thread_state1 *ts1) +dds_return_t join_thread (struct thread_state1 *ts1) { - int ret; + dds_return_t ret; assert (ts1->state == THREAD_STATE_ALIVE); - if (ddsrt_thread_join (ts1->extTid, NULL) == DDS_RETCODE_OK) - ret = 0; - else - ret = Q_ERR_UNSPECIFIED; - assert (vtime_asleep_p (ts1->vtime)); - reap_thread_state (ts1, 1); + ret = ddsrt_thread_join (ts1->extTid, NULL); + assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime))); + reap_thread_state (ts1); return ret; } void reset_thread_state (struct thread_state1 *ts1) { if (ts1) - { - reap_thread_state (ts1, 1); - ts1->name = NULL; - } + reap_thread_state (ts1); } void downgrade_main_thread (void) { struct thread_state1 *ts1 = lookup_thread_state (); - assert (vtime_asleep_p (ts1->vtime)); + assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime))); /* no need to sync with service lease: already stopped */ - reap_thread_state (ts1, 0); + reap_thread_state (ts1); thread_states_init_static (); } -void log_stack_traces (void) +void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct q_globals *gv) { - unsigned i; - for (i = 0; i < thread_states.nthreads; i++) + for (uint32_t i = 0; i < thread_states.nthreads; i++) { - if (thread_states.ts[i].state != THREAD_STATE_ZERO) + if (thread_states.ts[i].state != THREAD_STATE_ZERO && + (gv == NULL || ddsrt_atomic_ldvoidp (&thread_states.ts[i].gv) == gv)) { - log_stacktrace (thread_states.ts[i].name, thread_states.ts[i].tid); + log_stacktrace (logcfg, thread_states.ts[i].name, thread_states.ts[i].tid); } } } diff --git a/src/core/ddsi/src/q_time.c b/src/core/ddsi/src/q_time.c index 05878b3..79cfcf3 100644 --- a/src/core/ddsi/src/q_time.c +++ b/src/core/ddsi/src/q_time.c @@ -14,10 +14,6 @@ #include "dds/ddsrt/time.h" #include "dds/ddsi/q_time.h" -const nn_ddsi_time_t invalid_ddsi_timestamp = { -1, UINT32_MAX }; -const nn_ddsi_time_t ddsi_time_infinite = { INT32_MAX, UINT32_MAX }; -const nn_duration_t duration_infinite = { INT32_MAX, UINT32_MAX }; - nn_wctime_t now (void) { /* This function uses the wall clock. @@ -131,21 +127,21 @@ nn_etime_t add_duration_to_etime (nn_etime_t t, int64_t d) return u; } -int valid_ddsi_timestamp (nn_ddsi_time_t t) +int valid_ddsi_timestamp (ddsi_time_t t) { - return t.seconds != invalid_ddsi_timestamp.seconds && t.fraction != invalid_ddsi_timestamp.fraction; + return t.seconds != DDSI_TIME_INVALID.seconds && t.fraction != DDSI_TIME_INVALID.fraction; } -static nn_ddsi_time_t nn_to_ddsi_time (int64_t t) +static ddsi_time_t nn_to_ddsi_time (int64_t t) { if (t == T_NEVER) - return ddsi_time_infinite; + return DDSI_TIME_INFINITE; else { /* ceiling(ns * 2^32/10^9) -- can't change the ceiling to round-to-nearest because that would break backwards compatibility, but round-to-nearest of the inverse is correctly rounded anyway, so it shouldn't ever matter. */ - nn_ddsi_time_t x; + ddsi_time_t x; int ns = (int) (t % T_SECOND); x.seconds = (int) (t / T_SECOND); x.fraction = (unsigned) (((T_SECOND-1) + ((int64_t) ns << 32)) / T_SECOND); @@ -153,14 +149,14 @@ static nn_ddsi_time_t nn_to_ddsi_time (int64_t t) } } -nn_ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t) +ddsi_time_t nn_wctime_to_ddsi_time (nn_wctime_t t) { return nn_to_ddsi_time (t.v); } -static int64_t nn_from_ddsi_time (nn_ddsi_time_t x) +static int64_t nn_from_ddsi_time (ddsi_time_t x) { - if (x.seconds == ddsi_time_infinite.seconds && x.fraction == ddsi_time_infinite.fraction) + if (x.seconds == DDSI_TIME_INFINITE.seconds && x.fraction == DDSI_TIME_INFINITE.fraction) return T_NEVER; else { @@ -170,19 +166,19 @@ static int64_t nn_from_ddsi_time (nn_ddsi_time_t x) } } -nn_wctime_t nn_wctime_from_ddsi_time (nn_ddsi_time_t x) +nn_wctime_t nn_wctime_from_ddsi_time (ddsi_time_t x) { nn_wctime_t t; t.v = nn_from_ddsi_time (x); return t; } -nn_duration_t nn_to_ddsi_duration (int64_t x) +ddsi_duration_t nn_to_ddsi_duration (int64_t x) { return nn_to_ddsi_time (x); } -int64_t nn_from_ddsi_duration (nn_duration_t x) +int64_t nn_from_ddsi_duration (ddsi_duration_t x) { return nn_from_ddsi_time (x); } diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c index cc086a6..2bdaa70 100644 --- a/src/core/ddsi/src/q_transmit.c +++ b/src/core/ddsi/src/q_transmit.c @@ -14,6 +14,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" +#include "dds/ddsrt/static_assert.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/q_entity.h" @@ -26,12 +27,10 @@ #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_globals.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_hbcontrol.h" -#include "dds/ddsi/q_static_assert.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" @@ -39,16 +38,6 @@ #include "dds/ddsi/sysdeps.h" #include "dds__whc.h" -#if __STDC_VERSION__ >= 199901L -#define POS_INFINITY_DOUBLE INFINITY -#elif defined HUGE_VAL -/* Hope for the best -- the only consequence of getting this wrong is - that T_NEVER may be printed as a fugly value instead of as +inf. */ -#define POS_INFINITY_DOUBLE (HUGE_VAL + HUGE_VAL) -#else -#define POS_INFINITY_DOUBLE 1e1000 -#endif - static const struct wr_prd_match *root_rdmatch (const struct writer *wr) { return ddsrt_avl_root (&wr_readers_treedef, &wr->readers); @@ -88,14 +77,15 @@ static void writer_hbcontrol_note_hb (struct writer *wr, nn_mtime_t tnow, int an int64_t writer_hbcontrol_intv (const struct writer *wr, const struct whc_state *whcst, UNUSED_ARG (nn_mtime_t tnow)) { + struct q_globals const * const gv = wr->e.gv; struct hbcontrol const * const hbc = &wr->hbcontrol; - int64_t ret = config.const_hb_intv_sched; + int64_t ret = gv->config.const_hb_intv_sched; size_t n_unacked; if (hbc->hbs_since_last_write > 2) { unsigned cnt = hbc->hbs_since_last_write; - while (cnt-- > 2 && 2 * ret < config.const_hb_intv_sched_max) + while (cnt-- > 2 && 2 * ret < gv->config.const_hb_intv_sched_max) ret *= 2; } @@ -106,13 +96,14 @@ int64_t writer_hbcontrol_intv (const struct writer *wr, const struct whc_state * ret /= 2; if (wr->throttling) ret /= 2; - if (ret < config.const_hb_intv_sched_min) - ret = config.const_hb_intv_sched_min; + if (ret < gv->config.const_hb_intv_sched_min) + ret = gv->config.const_hb_intv_sched_min; return ret; } void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow) { + struct q_globals const * const gv = wr->e.gv; struct hbcontrol * const hbc = &wr->hbcontrol; nn_mtime_t tnext; @@ -122,7 +113,7 @@ void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow) /* We know this is new data, so we want a heartbeat event after one base interval */ - tnext.v = tnow.v + config.const_hb_intv_sched; + tnext.v = tnow.v + gv->config.const_hb_intv_sched; if (tnext.v < hbc->tsched.v) { /* Insertion of a message with WHC locked => must now have at @@ -141,6 +132,7 @@ int writer_hbcontrol_must_send (const struct writer *wr, const struct whc_state struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, int hbansreq, int issync) { + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg *msg; const nn_guid_t *prd_guid; @@ -148,7 +140,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru assert (wr->reliable); assert (hbansreq >= 0); - if ((msg = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) + if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) /* out of memory at worst slows down traffic */ return NULL; @@ -185,12 +177,12 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru } } - DDS_TRACE("writer_hbcontrol: wr "PGUIDFMT" ", PGUID (wr->e.guid)); + ETRACE (wr, "writer_hbcontrol: wr "PGUIDFMT" ", PGUID (wr->e.guid)); if (prd_guid == NULL) - DDS_TRACE("multicasting "); + ETRACE (wr, "multicasting "); else - DDS_TRACE("unicasting to prd "PGUIDFMT" ", PGUID (*prd_guid)); - DDS_TRACE("(rel-prd %d seq-eq-max %d seq %"PRId64" maxseq %"PRId64")\n", + ETRACE (wr, "unicasting to prd "PGUIDFMT" ", PGUID (*prd_guid)); + ETRACE (wr, "(rel-prd %d seq-eq-max %d seq %"PRId64" maxseq %"PRId64")\n", wr->num_reliable_readers, ddsrt_avl_is_empty (&wr->readers) ? -1 : root_rdmatch (wr)->num_reliable_readers_where_seq_equals_max, wr->seq, @@ -207,9 +199,9 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru else { struct proxy_reader *prd; - if ((prd = ephash_lookup_proxy_reader_guid (prd_guid)) == NULL) + if ((prd = ephash_lookup_proxy_reader_guid (gv->guid_hash, prd_guid)) == NULL) { - DDS_TRACE("writer_hbcontrol: wr "PGUIDFMT" unknown prd "PGUIDFMT"\n", PGUID (wr->e.guid), PGUID (*prd_guid)); + ETRACE (wr, "writer_hbcontrol: wr "PGUIDFMT" unknown prd "PGUIDFMT"\n", PGUID (wr->e.guid), PGUID (*prd_guid)); nn_xmsg_free (msg); return NULL; } @@ -232,8 +224,9 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru static int writer_hbcontrol_ack_required_generic (const struct writer *wr, const struct whc_state *whcst, nn_mtime_t tlast, nn_mtime_t tnow, int piggyback) { + struct q_globals const * const gv = wr->e.gv; struct hbcontrol const * const hbc = &wr->hbcontrol; - const int64_t hb_intv_ack = config.const_hb_intv_sched; + const int64_t hb_intv_ack = gv->config.const_hb_intv_sched; assert(wr->heartbeat_xevent != NULL && whcst != NULL); if (piggyback) @@ -256,9 +249,9 @@ static int writer_hbcontrol_ack_required_generic (const struct writer *wr, const if (whcst->unacked_bytes >= wr->whc_low + (wr->whc_high - wr->whc_low) / 2) { - if (tnow.v >= hbc->t_of_last_ackhb.v + config.const_hb_intv_sched_min) + if (tnow.v >= hbc->t_of_last_ackhb.v + gv->config.const_hb_intv_sched_min) return 2; - else if (tnow.v >= hbc->t_of_last_ackhb.v + config.const_hb_intv_min) + else if (tnow.v >= hbc->t_of_last_ackhb.v + gv->config.const_hb_intv_min) return 1; } @@ -271,10 +264,10 @@ int writer_hbcontrol_ack_required (const struct writer *wr, const struct whc_sta return writer_hbcontrol_ack_required_generic (wr, whcst, hbc->t_of_last_write, tnow, 0); } -struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, unsigned packetid, int *hbansreq) +struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_state *whcst, nn_mtime_t tnow, uint32_t packetid, int *hbansreq) { struct hbcontrol * const hbc = &wr->hbcontrol; - unsigned last_packetid; + uint32_t last_packetid; nn_mtime_t tlast; struct nn_xmsg *msg; @@ -308,10 +301,10 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_ if (msg) { - DDS_TRACE("heartbeat(wr "PGUIDFMT"%s) piggybacked, resched in %g s (min-ack %"PRId64"%s, avail-seq %"PRId64", xmit %"PRId64")\n", + ETRACE (wr, "heartbeat(wr "PGUIDFMT"%s) piggybacked, resched in %g s (min-ack %"PRId64"%s, avail-seq %"PRId64", xmit %"PRId64")\n", PGUID (wr->e.guid), *hbansreq ? "" : " final", - (hbc->tsched.v == T_NEVER) ? POS_INFINITY_DOUBLE : (double) (hbc->tsched.v - tnow.v) / 1e9, + (hbc->tsched.v == T_NEVER) ? INFINITY : (double) (hbc->tsched.v - tnow.v) / 1e9, ddsrt_avl_is_empty (&wr->readers) ? -1 : root_rdmatch (wr)->min_seq, ddsrt_avl_is_empty (&wr->readers) || root_rdmatch (wr)->all_have_replied_to_hb ? "" : "!", whcst->max_seq, READ_SEQ_XMIT(wr)); @@ -322,6 +315,7 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, nn_entityid_t dst, int issync) { + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; Heartbeat_t * hb; seqno_t max = 0, min = 1; @@ -331,7 +325,7 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta assert (wr->reliable); assert (hbansreq >= 0); - if (config.meas_hb_to_ack_latency) + if (gv->config.meas_hb_to_ack_latency) { /* If configured to measure heartbeat-to-ack latency, we must add a timestamp. No big deal if it fails. */ @@ -387,12 +381,13 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta nn_xmsg_submsg_setnext (msg, sm_marker); } -static int create_fragment_message_simple (struct writer *wr, seqno_t seq, struct ddsi_serdata *serdata, struct nn_xmsg **pmsg) +static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t seq, struct ddsi_serdata *serdata, struct nn_xmsg **pmsg) { #define TEST_KEYHASH 0 /* actual expected_inline_qos_size is typically 0, but always claiming 32 bytes won't make a difference, so no point in being precise */ const size_t expected_inline_qos_size = /* statusinfo */ 8 + /* keyhash */ 20 + /* sentinel */ 4; + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; unsigned char contentflag = 0; Data_t *data; @@ -416,8 +411,8 @@ static int create_fragment_message_simple (struct writer *wr, seqno_t seq, struc ASSERT_MUTEX_HELD (&wr->e.lock); /* INFO_TS: 12 bytes, Data_t: 24 bytes, expected inline QoS: 32 => should be single chunk */ - if ((*pmsg = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (Data_t) + expected_inline_qos_size, NN_XMSG_KIND_DATA)) == NULL) - return Q_ERR_OUT_OF_MEMORY; + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (Data_t) + expected_inline_qos_size, NN_XMSG_KIND_DATA)) == NULL) + return DDS_RETCODE_OUT_OF_RESOURCES; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS /* use the partition_id from the writer to select the proper encoder */ @@ -425,7 +420,7 @@ static int create_fragment_message_simple (struct writer *wr, seqno_t seq, struc #endif nn_xmsg_setdstN (*pmsg, wr->as, wr->as_group); - nn_xmsg_setmaxdelay (*pmsg, nn_from_ddsi_duration (wr->xqos->latency_budget.duration)); + nn_xmsg_setmaxdelay (*pmsg, wr->xqos->latency_budget.duration); nn_xmsg_add_timestamp (*pmsg, serdata->timestamp); data = nn_xmsg_append (*pmsg, &sm_marker, sizeof (Data_t)); @@ -461,7 +456,7 @@ static int create_fragment_message_simple (struct writer *wr, seqno_t seq, struc return 0; } -int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd, struct nn_xmsg **pmsg, int isnew) +dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd, struct nn_xmsg **pmsg, int isnew) { /* We always fragment into FRAGMENT_SIZEd fragments, which are near the smallest allowed fragment size & can't be bothered (yet) to @@ -477,6 +472,7 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli actual expected_inline_qos_size is typically 0, but always claiming 32 bytes won't make a difference, so no point in being precise */ const size_t expected_inline_qos_size = /* statusinfo */ 8 + /* keyhash */ 20 + /* sentinel */ 4; + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; void *sm; Data_DataFrag_common_t *ddcmn; @@ -484,25 +480,25 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli uint32_t fragstart, fraglen; enum nn_xmsg_kind xmsg_kind = isnew ? NN_XMSG_KIND_DATA : NN_XMSG_KIND_DATA_REXMIT; const uint32_t size = ddsi_serdata_size (serdata); - int ret = 0; + dds_return_t ret = 0; (void)plist; ASSERT_MUTEX_HELD (&wr->e.lock); - if (fragnum * config.fragment_size >= size && size > 0) + if (fragnum * gv->config.fragment_size >= size && size > 0) { /* This is the first chance to detect an attempt at retransmitting an non-existent fragment, which a malicious (or buggy) remote reader can trigger. So we return an error instead of asserting as we used to. */ - return Q_ERR_INVALID; + return DDS_RETCODE_BAD_PARAMETER; } - fragging = (config.fragment_size < size); + fragging = (gv->config.fragment_size < size); /* INFO_TS: 12 bytes, DataFrag_t: 36 bytes, expected inline QoS: 32 => should be single chunk */ - if ((*pmsg = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (DataFrag_t) + expected_inline_qos_size, xmsg_kind)) == NULL) - return Q_ERR_OUT_OF_MEMORY; + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (DataFrag_t) + expected_inline_qos_size, xmsg_kind)) == NULL) + return DDS_RETCODE_OUT_OF_RESOURCES; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS /* use the partition_id from the writer to select the proper encoder */ @@ -515,14 +511,14 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli { nn_xmsg_free (*pmsg); *pmsg = NULL; - return Q_ERR_NO_ADDRESS; + return DDS_RETCODE_PRECONDITION_NOT_MET; } /* retransmits: latency budget doesn't apply */ } else { nn_xmsg_setdstN (*pmsg, wr->as, wr->as_group); - nn_xmsg_setmaxdelay (*pmsg, nn_from_ddsi_duration (wr->xqos->latency_budget.duration)); + nn_xmsg_setmaxdelay (*pmsg, wr->xqos->latency_budget.duration); } /* Timestamp only needed once, for the first fragment */ @@ -565,18 +561,18 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli frag->fragmentStartingNum = fragnum + 1; frag->fragmentsInSubmessage = 1; - frag->fragmentSize = (unsigned short) config.fragment_size; + frag->fragmentSize = (unsigned short) gv->config.fragment_size; frag->sampleSize = (uint32_t)size; - fragstart = fragnum * config.fragment_size; + fragstart = fragnum * gv->config.fragment_size; #if MULTIPLE_FRAGS_IN_SUBMSG /* ugly hack for testing only */ - if (fragstart + config.fragment_size < ddsi_serdata_size (serdata) && - fragstart + 2 * config.fragment_size >= ddsi_serdata_size (serdata)) + if (fragstart + gv->config.fragment_size < ddsi_serdata_size (serdata) && + fragstart + 2 * gv->config.fragment_size >= ddsi_serdata_size (serdata)) frag->fragmentsInSubmessage++; ret = frag->fragmentsInSubmessage; #endif - fraglen = config.fragment_size * frag->fragmentsInSubmessage; + fraglen = gv->config.fragment_size * frag->fragmentsInSubmessage; if (fragstart + fraglen > size) fraglen = (uint32_t)(size - fragstart); ddcmn->octetsToInlineQos = (unsigned short) ((char*) (frag+1) - ((char*) &ddcmn->octetsToInlineQos + 2)); @@ -599,7 +595,7 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli if (xmsg_kind == NN_XMSG_KIND_DATA_REXMIT) nn_xmsg_set_data_readerId (*pmsg, &ddcmn->readerId); - Q_STATIC_ASSERT_CODE (DATA_FLAG_INLINE_QOS == DATAFRAG_FLAG_INLINE_QOS); + DDSRT_STATIC_ASSERT_CODE (DATA_FLAG_INLINE_QOS == DATAFRAG_FLAG_INLINE_QOS); assert (!(ddcmn->smhdr.flags & DATAFRAG_FLAG_INLINE_QOS)); if (fragnum == 0) @@ -625,9 +621,9 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli nn_xmsg_serdata (*pmsg, serdata, fragstart, fraglen); nn_xmsg_submsg_setnext (*pmsg, sm_marker); #if 0 - DDS_TRACE("queue data%s "PGUIDFMT" #%lld/%u[%u..%u)\n", - fragging ? "frag" : "", PGUID (wr->e.guid), - seq, fragnum+1, fragstart, fragstart + fraglen); + GVTRACE ("queue data%s "PGUIDFMT" #%lld/%u[%u..%u)\n", + fragging ? "frag" : "", PGUID (wr->e.guid), + seq, fragnum+1, fragstart, fragstart + fraglen); #endif return ret; @@ -635,10 +631,11 @@ int create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_pli static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragnum, struct proxy_reader *prd, struct nn_xmsg **pmsg) { + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; HeartbeatFrag_t *hbf; ASSERT_MUTEX_HELD (&wr->e.lock); - if ((*pmsg = nn_xmsg_new (gv.xmsgpool, &wr->e.guid.prefix, sizeof (HeartbeatFrag_t), NN_XMSG_KIND_CONTROL)) == NULL) + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (HeartbeatFrag_t), NN_XMSG_KIND_CONTROL)) == NULL) return; /* ignore out-of-memory: HeartbeatFrag is only advisory anyway */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS nn_xmsg_setencoderid (*pmsg, wr->partition_id); @@ -692,16 +689,15 @@ static int must_skip_frag (const char *frags_to_skip, unsigned frag) } #endif -static void transmit_sample_lgmsg_unlocked (struct nn_xpack *xp, struct writer *wr, const struct whc_state *whcst, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew, unsigned nfrags) +static void transmit_sample_lgmsg_unlocked (struct nn_xpack *xp, struct writer *wr, const struct whc_state *whcst, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew, uint32_t nfrags) { - unsigned i; #if 0 const char *frags_to_skip = getenv ("SKIPFRAGS"); #endif assert(xp); assert((wr->heartbeat_xevent != NULL) == (whcst != NULL)); - for (i = 0; i < nfrags; i++) + for (uint32_t i = 0; i < nfrags; i++) { struct nn_xmsg *fmsg = NULL; struct nn_xmsg *hmsg = NULL; @@ -753,17 +749,18 @@ static void transmit_sample_lgmsg_unlocked (struct nn_xpack *xp, struct writer * static void transmit_sample_unlocks_wr (struct nn_xpack *xp, struct writer *wr, const struct whc_state *whcst, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew) { /* on entry: &wr->e.lock held; on exit: lock no longer held */ + struct q_globals const * const gv = wr->e.gv; struct nn_xmsg *fmsg; uint32_t sz; assert(xp); assert((wr->heartbeat_xevent != NULL) == (whcst != NULL)); sz = ddsi_serdata_size (serdata); - if (sz > config.fragment_size || !isnew || plist != NULL || prd != NULL) + if (sz > gv->config.fragment_size || !isnew || plist != NULL || prd != NULL) { uint32_t nfrags; ddsrt_mutex_unlock (&wr->e.lock); - nfrags = (sz + config.fragment_size - 1) / config.fragment_size; + nfrags = (sz + gv->config.fragment_size - 1) / gv->config.fragment_size; transmit_sample_lgmsg_unlocked (xp, wr, whcst, seq, plist, serdata, prd, isnew, nfrags); return; } @@ -794,13 +791,14 @@ static void transmit_sample_unlocks_wr (struct nn_xpack *xp, struct writer *wr, int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew) { + struct q_globals const * const gv = wr->e.gv; uint32_t i, sz, nfrags; int enqueued = 1; ASSERT_MUTEX_HELD (&wr->e.lock); sz = ddsi_serdata_size (serdata); - nfrags = (sz + config.fragment_size - 1) / config.fragment_size; + nfrags = (sz + gv->config.fragment_size - 1) / gv->config.fragment_size; if (nfrags == 0) { /* end-of-transaction messages are empty, but still need to be sent */ @@ -853,7 +851,7 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist ASSERT_MUTEX_HELD (&wr->e.lock); - if (dds_get_log_mask() & DDS_LC_TRACE) + if (wr->e.gv->logconfig.c.mask & DDS_LC_TRACE) { char ppbuf[1024]; int tmp; @@ -861,10 +859,10 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist const char *ttname = wr->topic ? wr->topic->type_name : "(null)"; ppbuf[0] = '\0'; tmp = sizeof (ppbuf) - 1; - DDS_TRACE("write_sample "PGUIDFMT" #%"PRId64, PGUID (wr->e.guid), seq); + ETRACE (wr, "write_sample "PGUIDFMT" #%"PRId64, PGUID (wr->e.guid), seq); if (plist != 0 && (plist->present & PP_COHERENT_SET)) - DDS_TRACE(" C#%"PRId64"", fromSN (plist->coherent_set_seqno)); - DDS_TRACE(": ST%"PRIu32" %s/%s:%s%s\n", serdata->statusinfo, tname, ttname, ppbuf, tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); + ETRACE (wr, " C#%"PRId64"", fromSN (plist->coherent_set_seqno)); + ETRACE (wr, ": ST%"PRIu32" %s/%s:%s%s\n", serdata->statusinfo, tname, ttname, ppbuf, tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); } assert (wr->reliable || have_reliable_subs (wr) == 0); @@ -901,7 +899,7 @@ static int writer_may_continue (const struct writer *wr, const struct whc_state } -static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr) +static dds_return_t throttle_writer (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr) { /* Sleep (cond_wait) without updating the thread's vtime: the garbage collector won't free the writer while we leave it @@ -936,10 +934,10 @@ static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct n resent to them, until a ACKNACK is received from that reader. This implicitly clears the whc and unblocks the writer. */ - - dds_retcode_t result = DDS_RETCODE_OK; + struct q_globals const * const gv = wr->e.gv; + dds_return_t result = DDS_RETCODE_OK; nn_mtime_t tnow = now_mt (); - const nn_mtime_t abstimeout = add_duration_to_mtime (tnow, nn_from_ddsi_duration (wr->xqos->reliability.max_blocking_time)); + const nn_mtime_t abstimeout = add_duration_to_mtime (tnow, wr->xqos->reliability.max_blocking_time); struct whc_state whcst; whc_get_state (wr->whc, &whcst); @@ -950,7 +948,9 @@ static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct n assert (!is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE)); } - DDS_LOG(DDS_LC_THROTTLE, "writer "PGUIDFMT" waiting for whc to shrink below low-water mark (whc %"PRIuSIZE" low=%"PRIu32" high=%"PRIu32")\n", PGUID (wr->e.guid), whcst.unacked_bytes, wr->whc_low, wr->whc_high); + GVLOG (DDS_LC_THROTTLE, + "writer "PGUIDFMT" waiting for whc to shrink below low-water mark (whc %"PRIuSIZE" low=%"PRIu32" high=%"PRIu32")\n", + PGUID (wr->e.guid), whcst.unacked_bytes, wr->whc_low, wr->whc_high); wr->throttling++; wr->throttle_count++; @@ -970,7 +970,7 @@ static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct n whc_get_state (wr->whc, &whcst); } - while (gv.rtps_keepgoing && !writer_may_continue (wr, &whcst)) + while (ddsrt_atomic_ld32 (&gv->rtps_keepgoing) && !writer_may_continue (wr, &whcst)) { int64_t reltimeout; tnow = now_mt (); @@ -981,7 +981,7 @@ static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct n thread_state_asleep (ts1); if (ddsrt_cond_waitfor (&wr->throttle_cond, &wr->e.lock, reltimeout)) result = DDS_RETCODE_OK; - thread_state_awake (ts1); + thread_state_awake_domain_ok (ts1); whc_get_state(wr->whc, &whcst); } if (result == DDS_RETCODE_TIMEOUT) @@ -997,20 +997,23 @@ static dds_retcode_t throttle_writer (struct thread_state1 * const ts1, struct n ddsrt_cond_broadcast (&wr->throttle_cond); } - DDS_LOG(DDS_LC_THROTTLE, "writer "PGUIDFMT" done waiting for whc to shrink below low-water mark (whc %"PRIuSIZE" low=%"PRIu32" high=%"PRIu32")\n", PGUID (wr->e.guid), whcst.unacked_bytes, wr->whc_low, wr->whc_high); + GVLOG (DDS_LC_THROTTLE, + "writer "PGUIDFMT" done waiting for whc to shrink below low-water mark (whc %"PRIuSIZE" low=%"PRIu32" high=%"PRIu32")\n", + PGUID (wr->e.guid), whcst.unacked_bytes, wr->whc_low, wr->whc_high); return result; } static int maybe_grow_whc (struct writer *wr) { - if (!wr->retransmitting && config.whc_adaptive && wr->whc_high < config.whc_highwater_mark) + struct q_globals const * const gv = wr->e.gv; + if (!wr->retransmitting && gv->config.whc_adaptive && wr->whc_high < gv->config.whc_highwater_mark) { nn_etime_t tnow = now_et(); nn_etime_t tgrow = add_duration_to_etime (wr->t_whc_high_upd, 10 * T_MILLISECOND); if (tnow.v >= tgrow.v) { - uint32_t m = (config.whc_highwater_mark - wr->whc_high) / 32; - wr->whc_high = (m == 0) ? config.whc_highwater_mark : wr->whc_high + m; + uint32_t m = (gv->config.whc_highwater_mark - wr->whc_high) / 32; + wr->whc_high = (m == 0) ? gv->config.whc_highwater_mark : wr->whc_high + m; wr->t_whc_high_upd = tnow; return 1; } @@ -1020,15 +1023,16 @@ static int maybe_grow_whc (struct writer *wr) static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, int end_of_txn, int gc_allowed) { + struct q_globals const * const gv = wr->e.gv; int r; seqno_t seq; nn_mtime_t tnow; /* If GC not allowed, we must be sure to never block when writing. That is only the case for (true, aggressive) KEEP_LAST writers, and also only if there is no limit to how much unacknowledged data the WHC may contain. */ - assert(gc_allowed || (wr->xqos->history.kind == NN_KEEP_LAST_HISTORY_QOS && wr->whc_low == INT32_MAX)); - (void)gc_allowed; + assert (gc_allowed || (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST && wr->whc_low == INT32_MAX)); + (void) gc_allowed; - if (ddsi_serdata_size (serdata) > config.max_sample_size) + if (ddsi_serdata_size (serdata) > gv->config.max_sample_size) { char ppbuf[1024]; int tmp; @@ -1036,11 +1040,11 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * const char *ttname = wr->topic ? wr->topic->type_name : "(null)"; ppbuf[0] = '\0'; tmp = sizeof (ppbuf) - 1; - DDS_WARNING ("dropping oversize (%"PRIu32" > %"PRIu32") sample from local writer "PGUIDFMT" %s/%s:%s%s\n", - ddsi_serdata_size (serdata), config.max_sample_size, - PGUID (wr->e.guid), tname, ttname, ppbuf, - tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); - r = Q_ERR_INVALID_DATA; + GVWARNING ("dropping oversize (%"PRIu32" > %"PRIu32") sample from local writer "PGUIDFMT" %s/%s:%s%s\n", + ddsi_serdata_size (serdata), gv->config.max_sample_size, + PGUID (wr->e.guid), tname, ttname, ppbuf, + tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); + r = DDS_RETCODE_BAD_PARAMETER; goto drop; } @@ -1057,9 +1061,9 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * whc_get_state(wr->whc, &whcst); if (whcst.unacked_bytes > wr->whc_high) { - dds_retcode_t ores; + dds_return_t ores; assert(gc_allowed); /* also see beginning of the function */ - if (config.prioritize_retransmit && wr->retransmitting) + if (gv->config.prioritize_retransmit && wr->retransmitting) ores = throttle_writer (ts1, xp, wr); else { @@ -1072,7 +1076,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * if (ores == DDS_RETCODE_TIMEOUT) { ddsrt_mutex_unlock (&wr->e.lock); - r = Q_ERR_TIMEOUT; + r = DDS_RETCODE_TIMEOUT; goto drop; } } @@ -1105,6 +1109,22 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * ddsrt_free (plist); } } + else if (addrset_empty (wr->as) && (wr->as_group == NULL || addrset_empty (wr->as_group))) + { + /* No network destination, so no point in doing all the work involved + in going all the way. We do have to record that we "transmitted" + this sample, or it might not be retransmitted on request. + + (Note that no network destination is very nearly the same as no + matching proxy readers. The exception is the SPDP writer.) */ + UPDATE_SEQ_XMIT_LOCKED (wr, seq); + ddsrt_mutex_unlock (&wr->e.lock); + if (plist != NULL) + { + nn_plist_fini (plist); + ddsrt_free (plist); + } + } else { /* Note the subtlety of enqueueing with the lock held but @@ -1173,9 +1193,9 @@ int write_sample_gc_notk (struct thread_state1 * const ts1, struct nn_xpack *xp, struct ddsi_tkmap_instance *tk; int res; assert (thread_is_awake ()); - tk = ddsi_tkmap_lookup_instance_ref (serdata); + tk = ddsi_tkmap_lookup_instance_ref (wr->e.gv->m_tkmap, serdata); res = write_sample_eot (ts1, xp, wr, NULL, serdata, tk, 0, 1); - ddsi_tkmap_instance_unref (tk); + ddsi_tkmap_instance_unref (wr->e.gv->m_tkmap, tk); return res; } @@ -1184,9 +1204,8 @@ int write_sample_nogc_notk (struct thread_state1 * const ts1, struct nn_xpack *x struct ddsi_tkmap_instance *tk; int res; assert (thread_is_awake ()); - tk = ddsi_tkmap_lookup_instance_ref (serdata); + tk = ddsi_tkmap_lookup_instance_ref (wr->e.gv->m_tkmap, serdata); res = write_sample_eot (ts1, xp, wr, NULL, serdata, tk, 0, 0); - ddsi_tkmap_instance_unref (tk); + ddsi_tkmap_instance_unref (wr->e.gv->m_tkmap, tk); return res; } - diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c index dc959c0..e38361a 100644 --- a/src/core/ddsi/src/q_xevent.c +++ b/src/core/ddsi/src/q_xevent.c @@ -30,7 +30,6 @@ #include "dds/ddsi/q_globals.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_transmit.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_misc.h" @@ -45,18 +44,12 @@ #include "dds/ddsi/sysdeps.h" +#define EVQTRACE(...) DDS_CTRACE (&evq->gv->logconfig, __VA_ARGS__) + /* This is absolute bottom for signed integers, where -x = x and yet x != 0 -- and note that it had better be 2's complement machine! */ #define TSCHED_DELETE ((int64_t) ((uint64_t) 1 << 63)) -#if __STDC_VERSION__ >= 199901L -#define POS_INFINITY_DOUBLE INFINITY -#else -/* Hope for the best -- the only consequence of getting this wrong is - that T_NEVER may be printed as a fugly value instead of as +inf. */ -#define POS_INFINITY_DOUBLE (HUGE_VAL + HUGE_VAL) -#endif - enum xeventkind { XEVK_HEARTBEAT, @@ -148,6 +141,7 @@ struct xeventq { size_t max_queued_rexmit_msgs; int terminate; struct thread_state1 *ts; + struct q_globals *gv; ddsrt_mutex_t lock; ddsrt_cond_t cond; ddsi_tran_conn_t tev_conn; @@ -158,6 +152,7 @@ static uint32_t xevent_thread (struct xeventq *xevq); static nn_mtime_t earliest_in_xeventq (struct xeventq *evq); static int msg_xevents_cmp (const void *a, const void *b); static int compare_xevent_tsched (const void *va, const void *vb); +static void handle_nontimed_xevent (struct xevent_nt *xev, struct nn_xpack *xp); static const ddsrt_avl_treedef_t msg_xevents_treedef = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY (offsetof (struct xevent_nt, u.msg_rexmit.msg_avlnode), offsetof (struct xevent_nt, u.msg_rexmit.msg), msg_xevents_cmp, 0); @@ -173,7 +168,7 @@ static int compare_xevent_tsched (const void *va, const void *vb) static void update_rexmit_counts (struct xeventq *evq, struct xevent_nt *ev) { #if 0 - DDS_TRACE(("ZZZ(%p,%"PA_PRIuSIZE")", (void *) ev, ev->u.msg_rexmit.queued_rexmit_bytes); + EVQTRACE ("ZZZ(%p,%"PRIuSIZE")", (void *) ev, ev->u.msg_rexmit.queued_rexmit_bytes); #endif assert (ev->kind == XEVK_MSG_REXMIT); assert (ev->u.msg_rexmit.queued_rexmit_bytes <= evq->queued_rexmit_bytes); @@ -183,7 +178,7 @@ static void update_rexmit_counts (struct xeventq *evq, struct xevent_nt *ev) } #if 0 -static void trace_msg (const char *func, const struct nn_xmsg *m) +static void trace_msg (struct xeventq *evq, const char *func, const struct nn_xmsg *m) { if (dds_get_log_mask() & DDS_LC_TRACE) { @@ -191,11 +186,11 @@ static void trace_msg (const char *func, const struct nn_xmsg *m) seqno_t wrseq; nn_fragment_number_t wrfragid; nn_xmsg_guid_seq_fragid (m, &wrguid, &wrseq, &wrfragid); - DDS_TRACE(" %s("PGUIDFMT"/%"PRId64"/%u)", func, PGUID (wrguid), wrseq, wrfragid); + EVQTRACE(" %s("PGUIDFMT"/%"PRId64"/%u)", func, PGUID (wrguid), wrseq, wrfragid); } } #else -static void trace_msg (UNUSED_ARG (const char *func), UNUSED_ARG (const struct nn_xmsg *m)) +static void trace_msg (UNUSED_ARG (struct xeventq *evq), UNUSED_ARG (const char *func), UNUSED_ARG (const struct nn_xmsg *m)) { } #endif @@ -203,21 +198,21 @@ static void trace_msg (UNUSED_ARG (const char *func), UNUSED_ARG (const struct n static struct xevent_nt *lookup_msg (struct xeventq *evq, struct nn_xmsg *msg) { assert (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT); - trace_msg ("lookup-msg", msg); + trace_msg (evq, "lookup-msg", msg); return ddsrt_avl_lookup (&msg_xevents_treedef, &evq->msg_xevents, msg); } static void remember_msg (struct xeventq *evq, struct xevent_nt *ev) { assert (ev->kind == XEVK_MSG_REXMIT); - trace_msg ("remember-msg", ev->u.msg_rexmit.msg); + trace_msg (evq, "remember-msg", ev->u.msg_rexmit.msg); ddsrt_avl_insert (&msg_xevents_treedef, &evq->msg_xevents, ev); } static void forget_msg (struct xeventq *evq, struct xevent_nt *ev) { assert (ev->kind == XEVK_MSG_REXMIT); - trace_msg ("forget-msg", ev->u.msg_rexmit.msg); + trace_msg (evq, "forget-msg", ev->u.msg_rexmit.msg); ddsrt_avl_delete (&msg_xevents_treedef, &evq->msg_xevents, ev); } @@ -315,26 +310,6 @@ static void free_xevent (struct xeventq *evq, struct xevent *ev) ddsrt_free (ev); } -static void free_xevent_nt (struct xeventq *evq, struct xevent_nt *ev) -{ - assert (!nontimed_xevent_in_queue (evq, ev)); - switch (ev->kind) - { - case XEVK_MSG: - nn_xmsg_free (ev->u.msg.msg); - break; - case XEVK_MSG_REXMIT: - assert (ddsrt_avl_lookup (&msg_xevents_treedef, &evq->msg_xevents, ev->u.msg_rexmit.msg) == NULL); - update_rexmit_counts (evq, ev); - nn_xmsg_free (ev->u.msg_rexmit.msg); - break; - case XEVK_ENTITYID: - nn_xmsg_free (ev->u.entityid.msg); - break; - } - ddsrt_free (ev); -} - void delete_xevent (struct xevent *ev) { struct xeventq *evq = ev->evq; @@ -393,7 +368,7 @@ int resched_xevent_if_earlier (struct xevent *ev, nn_mtime_t tsched) return is_resched; } -static struct xevent * qxev_common (struct xeventq *evq, nn_mtime_t tsched, enum xeventkind kind) +static struct xevent *qxev_common (struct xeventq *evq, nn_mtime_t tsched, enum xeventkind kind) { /* qxev_common is the route by which all timed xevents are created. */ @@ -403,10 +378,10 @@ static struct xevent * qxev_common (struct xeventq *evq, nn_mtime_t tsched, enum ASSERT_MUTEX_HELD (&evq->lock); /* round up the scheduled time if required */ - if (tsched.v != T_NEVER && config.schedule_time_rounding != 0) + if (tsched.v != T_NEVER && evq->gv->config.schedule_time_rounding != 0) { - nn_mtime_t tsched_rounded = mtime_round_up (tsched, config.schedule_time_rounding); - DDS_TRACE("rounded event scheduled for %"PRId64" to %"PRId64"\n", tsched.v, tsched_rounded.v); + nn_mtime_t tsched_rounded = mtime_round_up (tsched, evq->gv->config.schedule_time_rounding); + EVQTRACE ("rounded event scheduled for %"PRId64" to %"PRId64"\n", tsched.v, tsched_rounded.v); tsched = tsched_rounded; } @@ -459,7 +434,7 @@ static void qxev_insert_nt (struct xevent_nt *ev) struct xeventq *evq = ev->evq; ASSERT_MUTEX_HELD (&evq->lock); add_to_non_timed_xmit_list (evq, ev); - DDS_TRACE("non-timed queue now has %d items\n", compute_non_timed_xmit_list_size (evq)); + EVQTRACE ("non-timed queue now has %d items\n", compute_non_timed_xmit_list_size (evq)); } static int msg_xevents_cmp (const void *a, const void *b) @@ -491,14 +466,15 @@ struct xeventq * xeventq_new evq->queued_rexmit_bytes = 0; evq->queued_rexmit_msgs = 0; evq->tev_conn = conn; + evq->gv = conn->m_base.gv; ddsrt_mutex_init (&evq->lock); ddsrt_cond_init (&evq->cond); return evq; } -int xeventq_start (struct xeventq *evq, const char *name) +dds_return_t xeventq_start (struct xeventq *evq, const char *name) { - dds_retcode_t rc; + dds_return_t rc; char * evqname = "tev"; assert (evq->ts == NULL); @@ -510,13 +486,13 @@ int xeventq_start (struct xeventq *evq, const char *name) } evq->terminate = 0; - rc = create_thread (&evq->ts, evqname, (uint32_t (*) (void *)) xevent_thread, evq); + rc = create_thread (&evq->ts, evq->gv, evqname, (uint32_t (*) (void *)) xevent_thread, evq); if (name) { ddsrt_free (evqname); } - return (rc != DDS_RETCODE_OK) ? Q_ERR_UNSPECIFIED : 0; + return rc; } void xeventq_stop (struct xeventq *evq) @@ -546,13 +522,27 @@ void xeventq_free (struct xeventq *evq) { union { void *v; void (*f) (struct xevent *ev, void *arg, nn_mtime_t tnow); } fp; fp.f = ev->u.callback.cb; - DDS_WARNING("xeventq_free: callback %p did not schedule deletion as required, deleting event anyway\n", fp.v); + DDS_CWARNING (&evq->gv->logconfig, "xeventq_free: callback %p did not schedule deletion as required, deleting event anyway\n", fp.v); delete_xevent (ev); } } } - while (!non_timed_xmit_list_is_empty(evq)) - free_xevent_nt (evq, getnext_from_non_timed_xmit_list (evq)); + + { + struct nn_xpack *xp = nn_xpack_new (evq->tev_conn, evq->auxiliary_bandwidth_limit, false); + thread_state_awake (lookup_thread_state (), evq->gv); + ddsrt_mutex_lock (&evq->lock); + while (!non_timed_xmit_list_is_empty (evq)) + { + thread_state_awake_to_awake_no_nest (lookup_thread_state ()); + handle_nontimed_xevent (getnext_from_non_timed_xmit_list (evq), xp); + } + ddsrt_mutex_unlock (&evq->lock); + nn_xpack_send (xp, false); + nn_xpack_free (xp); + thread_state_asleep (lookup_thread_state ()); + } + assert (ddsrt_avl_is_empty (&evq->msg_xevents)); ddsrt_cond_destroy (&evq->cond); ddsrt_mutex_destroy (&evq->lock); @@ -590,21 +580,21 @@ static void handle_xevk_entityid (struct nn_xpack *xp, struct xevent_nt *ev) static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, nn_mtime_t tnow /* monotonic */) { + struct q_globals const * const gv = ev->evq->gv; struct nn_xmsg *msg; struct writer *wr; nn_mtime_t t_next; int hbansreq = 0; struct whc_state whcst; - if ((wr = ephash_lookup_writer_guid (&ev->u.heartbeat.wr_guid)) == NULL) + if ((wr = ephash_lookup_writer_guid (gv->guid_hash, &ev->u.heartbeat.wr_guid)) == NULL) { - DDS_TRACE("heartbeat(wr "PGUIDFMT") writer gone\n", - PGUID (ev->u.heartbeat.wr_guid)); + GVTRACE("heartbeat(wr "PGUIDFMT") writer gone\n", PGUID (ev->u.heartbeat.wr_guid)); return; } - assert (wr->reliable); ddsrt_mutex_lock (&wr->e.lock); + assert (wr->reliable); whc_get_state(wr->whc, &whcst); if (!writer_must_have_hb_scheduled (wr, &whcst)) { @@ -625,14 +615,14 @@ static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, nn_mt t_next.v = tnow.v + writer_hbcontrol_intv (wr, &whcst, tnow); } - DDS_TRACE("heartbeat(wr "PGUIDFMT"%s) %s, resched in %g s (min-ack %"PRId64"%s, avail-seq %"PRId64", xmit %"PRId64")\n", - PGUID (wr->e.guid), - hbansreq ? "" : " final", - msg ? "sent" : "suppressed", - (t_next.v == T_NEVER) ? POS_INFINITY_DOUBLE : (double)(t_next.v - tnow.v) / 1e9, - ddsrt_avl_is_empty (&wr->readers) ? (seqno_t) -1 : ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->min_seq, - ddsrt_avl_is_empty (&wr->readers) || ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->all_have_replied_to_hb ? "" : "!", - whcst.max_seq, READ_SEQ_XMIT(wr)); + GVTRACE ("heartbeat(wr "PGUIDFMT"%s) %s, resched in %g s (min-ack %"PRId64"%s, avail-seq %"PRId64", xmit %"PRId64")\n", + PGUID (wr->e.guid), + hbansreq ? "" : " final", + msg ? "sent" : "suppressed", + (t_next.v == T_NEVER) ? INFINITY : (double)(t_next.v - tnow.v) / 1e9, + ddsrt_avl_is_empty (&wr->readers) ? (seqno_t) -1 : ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->min_seq, + ddsrt_avl_is_empty (&wr->readers) || ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->all_have_replied_to_hb ? "" : "!", + whcst.max_seq, READ_SEQ_XMIT(wr)); resched_xevent_if_earlier (ev, t_next); wr->hbcontrol.tsched = t_next; ddsrt_mutex_unlock (&wr->e.lock); @@ -709,13 +699,13 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p struct nn_reorder *reorder; AckNack_t *an; struct nn_xmsg_marker sm_marker; - unsigned i, numbits; + uint32_t i, numbits; seqno_t base; - unsigned ui; - union { - struct nn_fragment_number_set set; - char pad[NN_FRAGMENT_NUMBER_SET_SIZE (256)]; + DDSRT_STATIC_ASSERT ((NN_FRAGMENT_NUMBER_SET_MAX_BITS % 32) == 0); + struct { + struct nn_fragment_number_set_header set; + uint32_t bits[NN_FRAGMENT_NUMBER_SET_MAX_BITS / 32]; } nackfrag; int nackfrag_numbits; seqno_t nackfrag_seq = 0; @@ -728,7 +718,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p if (rwn->in_sync != PRMSS_OUT_OF_SYNC) { reorder = pwr->reorder; - if (!config.late_ack_mode) + if (!pwr->e.gv->config.late_ack_mode) bitmap_base = nn_reorder_next_seq (reorder); else { @@ -750,7 +740,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p /* Make bitmap; note that we've made sure to have room for the maximum bitmap size. */ - numbits = nn_reorder_nackmap (reorder, bitmap_base, pwr->last_seq, &an->readerSNState, max_numbits, notail); + numbits = nn_reorder_nackmap (reorder, bitmap_base, pwr->last_seq, &an->readerSNState, an->bits, max_numbits, notail); base = fromSN (an->readerSNState.bitmap_base); /* Scan through bitmap, cutting it off at the first missing sample @@ -761,13 +751,13 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p { uint32_t fragnum; nackfrag_seq = base + i; - if (!nn_bitset_isset (numbits, an->readerSNState.bits, i)) + if (!nn_bitset_isset (numbits, an->bits, i)) continue; if (nackfrag_seq == pwr->last_seq) fragnum = pwr->last_fragnum; else fragnum = UINT32_MAX; - nackfrag_numbits = nn_defrag_nackmap (pwr->defrag, nackfrag_seq, fragnum, &nackfrag.set, max_numbits); + nackfrag_numbits = nn_defrag_nackmap (pwr->defrag, nackfrag_seq, fragnum, &nackfrag.set, nackfrag.bits, max_numbits); } if (nackfrag_numbits >= 0) { /* Cut the NACK short, NACKFRAG will be added after the NACK's is @@ -802,8 +792,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p { /* Count field is at a variable offset ... silly DDSI spec. */ nn_count_t *countp = - (nn_count_t *) ((char *) an + offsetof (AckNack_t, readerSNState) + - NN_SEQUENCE_NUMBER_SET_SIZE (an->readerSNState.numbits)); + (nn_count_t *) ((char *) an + offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (an->readerSNState.numbits)); *countp = ++rwn->count; /* Reset submessage size, now that we know the real size, and update @@ -811,11 +800,11 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p nn_xmsg_shrink (msg, sm_marker, ACKNACK_SIZE (an->readerSNState.numbits)); nn_xmsg_submsg_setnext (msg, sm_marker); - DDS_TRACE("acknack "PGUIDFMT" -> "PGUIDFMT": #%"PRId32":%"PRId64"/%"PRIu32":", + ETRACE (pwr, "acknack "PGUIDFMT" -> "PGUIDFMT": #%"PRId32":%"PRId64"/%"PRIu32":", PGUID (rwn->rd_guid), PGUID (pwr->e.guid), rwn->count, base, an->readerSNState.numbits); - for (ui = 0; ui != an->readerSNState.numbits; ui++) - DDS_TRACE("%c", nn_bitset_isset (numbits, an->readerSNState.bits, ui) ? '1' : '0'); + for (uint32_t ui = 0; ui != an->readerSNState.numbits; ui++) + ETRACE (pwr, "%c", nn_bitset_isset (numbits, an->bits, ui) ? '1' : '0'); } if (nackfrag_numbits > 0) @@ -834,21 +823,21 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p nf->writerSN = toSN (nackfrag_seq); nf->fragmentNumberState.bitmap_base = nackfrag.set.bitmap_base + 1; nf->fragmentNumberState.numbits = nackfrag.set.numbits; - memcpy (nf->fragmentNumberState.bits, nackfrag.set.bits, NN_FRAGMENT_NUMBER_SET_BITS_SIZE (nackfrag_numbits)); + memcpy (nf->bits, nackfrag.bits, NN_FRAGMENT_NUMBER_SET_BITS_SIZE (nackfrag_numbits)); { nn_count_t *countp = - (nn_count_t *) ((char *) nf + offsetof (NackFrag_t, fragmentNumberState) + NN_FRAGMENT_NUMBER_SET_SIZE (nf->fragmentNumberState.numbits)); + (nn_count_t *) ((char *) nf + offsetof (NackFrag_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (nf->fragmentNumberState.numbits)); *countp = ++pwr->nackfragcount; nn_xmsg_submsg_setnext (msg, sm_marker); - DDS_TRACE(" + nackfrag #%"PRId32":%"PRId64"/%u/%"PRIu32":", *countp, fromSN (nf->writerSN), nf->fragmentNumberState.bitmap_base, nf->fragmentNumberState.numbits); - for (ui = 0; ui != nf->fragmentNumberState.numbits; ui++) - DDS_TRACE("%c", nn_bitset_isset (nf->fragmentNumberState.numbits, nf->fragmentNumberState.bits, ui) ? '1' : '0'); + ETRACE (pwr, " + nackfrag #%"PRId32":%"PRId64"/%u/%"PRIu32":", *countp, fromSN (nf->writerSN), nf->fragmentNumberState.bitmap_base, nf->fragmentNumberState.numbits); + for (uint32_t ui = 0; ui != nf->fragmentNumberState.numbits; ui++) + ETRACE (pwr, "%c", nn_bitset_isset (nf->fragmentNumberState.numbits, nf->bits, ui) ? '1' : '0'); } } - DDS_TRACE("\n"); + ETRACE (pwr, "\n"); } static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, nn_mtime_t tnow) @@ -862,12 +851,13 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent A little snag is that the defragmenter can throw out partial samples in favour of others, so MUST ensure that the defragmenter won't start threshing and fail to make progress! */ + struct q_globals *gv = ev->evq->gv; struct proxy_writer *pwr; struct nn_xmsg *msg; struct pwr_rd_match *rwn; nn_locator_t loc; - if ((pwr = ephash_lookup_proxy_writer_guid (&ev->u.acknack.pwr_guid)) == NULL) + if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, &ev->u.acknack.pwr_guid)) == NULL) { return; } @@ -882,10 +872,10 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent if (addrset_any_uc (pwr->c.as, &loc) || addrset_any_mc (pwr->c.as, &loc)) { seqno_t nack_seq; - if ((msg = nn_xmsg_new (gv.xmsgpool, &ev->u.acknack.rd_guid.prefix, ACKNACK_SIZE_MAX, NN_XMSG_KIND_CONTROL)) == NULL) + if ((msg = nn_xmsg_new (gv->xmsgpool, &ev->u.acknack.rd_guid.prefix, ACKNACK_SIZE_MAX, NN_XMSG_KIND_CONTROL)) == NULL) goto outofmem; nn_xmsg_setdst1 (msg, &ev->u.acknack.pwr_guid.prefix, &loc); - if (config.meas_hb_to_ack_latency && rwn->hb_timestamp.v) + if (gv->config.meas_hb_to_ack_latency && rwn->hb_timestamp.v) { /* If HB->ACK latency measurement is enabled, and we have a timestamp available, add it and clear the time stamp. There @@ -905,15 +895,15 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent HEARTBEAT, I've seen too many cases of not sending an NACK because the writing side got confused ... Better to recover eventually. */ - resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, config.auto_resched_nack_delay)); + resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, gv->config.auto_resched_nack_delay)); } - DDS_TRACE("send acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT")\n", - PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid)); + GVTRACE ("send acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT")\n", + PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid)); } else { - DDS_TRACE("skip acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT"): no address\n", - PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid)); + GVTRACE ("skip acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT"): no address\n", + PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid)); msg = NULL; } @@ -952,18 +942,19 @@ static bool resend_spdp_sample_by_guid_key (struct writer *wr, const nn_guid_t * /* Look up data in (transient-local) WHC by key value -- FIXME: clearly a slightly more efficient and elegant way of looking up the key value is to be preferred */ + struct q_globals *gv = wr->e.gv; bool sample_found; nn_plist_t ps; nn_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = *guid; - struct nn_xmsg *mpayload = nn_xmsg_new (gv.xmsgpool, &guid->prefix, 0, NN_XMSG_KIND_DATA); + struct nn_xmsg *mpayload = nn_xmsg_new (gv->xmsgpool, &guid->prefix, 0, NN_XMSG_KIND_DATA); nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); nn_xmsg_addpar_sentinel (mpayload); nn_plist_fini (&ps); struct ddsi_plist_sample plist_sample; nn_xmsg_payload_to_plistsample (&plist_sample, PID_PARTICIPANT_GUID, mpayload); - struct ddsi_serdata *sd = ddsi_serdata_from_sample (gv.plist_topic, SDK_KEY, &plist_sample); + struct ddsi_serdata *sd = ddsi_serdata_from_sample (gv->plist_topic, SDK_KEY, &plist_sample); struct whc_borrowed_sample sample; nn_xmsg_free (mpayload); @@ -987,15 +978,15 @@ static bool resend_spdp_sample_by_guid_key (struct writer *wr, const nn_guid_t * static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, nn_mtime_t tnow) { /* Like the writer pointer in the heartbeat event, the participant pointer in the spdp event is assumed valid. */ + struct q_globals *gv = ev->evq->gv; struct participant *pp; struct proxy_reader *prd; struct writer *spdp_wr; bool do_write; - if ((pp = ephash_lookup_participant_guid (&ev->u.spdp.pp_guid)) == NULL) + if ((pp = ephash_lookup_participant_guid (gv->guid_hash, &ev->u.spdp.pp_guid)) == NULL) { - DDS_TRACE("handle_xevk_spdp "PGUIDFMT" - unknown guid\n", - PGUID (ev->u.spdp.pp_guid)); + GVTRACE ("handle_xevk_spdp "PGUIDFMT" - unknown guid\n", PGUID (ev->u.spdp.pp_guid)); if (ev->u.spdp.directed) delete_xevent (ev); return; @@ -1003,8 +994,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e if ((spdp_wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) { - DDS_TRACE("handle_xevk_spdp "PGUIDFMT" - spdp writer of participant not found\n", - PGUID (ev->u.spdp.pp_guid)); + GVTRACE ("handle_xevk_spdp "PGUIDFMT" - spdp writer of participant not found\n", PGUID (ev->u.spdp.pp_guid)); if (ev->u.spdp.directed) delete_xevent (ev); return; @@ -1022,10 +1012,10 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e nn_guid_t guid; guid.prefix = ev->u.spdp.dest_proxypp_guid_prefix; guid.entityid.u = NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER; - prd = ephash_lookup_proxy_reader_guid (&guid); + prd = ephash_lookup_proxy_reader_guid (gv->guid_hash, &guid); do_write = (prd != NULL); if (!do_write) - DDS_TRACE("xmit spdp: no proxy reader "PGUIDFMT"\n", PGUID (guid)); + GVTRACE ("xmit spdp: no proxy reader "PGUIDFMT"\n", PGUID (guid)); } if (do_write && !resend_spdp_sample_by_guid_key (spdp_wr, &ev->u.spdp.pp_guid, prd)) @@ -1050,8 +1040,8 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e } else { - DDS_TRACE("xmit spdp: suppressing early spdp response from "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x\n", - PGUID (pp->e.guid), PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_PARTICIPANT); + GVTRACE ("xmit spdp: suppressing early spdp response from "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x\n", + PGUID (pp->e.guid), PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_PARTICIPANT); } #endif } @@ -1060,15 +1050,15 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e { /* Directed events are used to send SPDP packets to newly discovered peers, and used just once. */ - if (--ev->u.spdp.directed == 0 || config.spdp_interval < T_SECOND || pp->lease_duration < T_SECOND) + if (--ev->u.spdp.directed == 0 || gv->config.spdp_interval < T_SECOND || pp->lease_duration < T_SECOND) delete_xevent (ev); else { nn_mtime_t tnext = add_duration_to_mtime (tnow, T_SECOND); - DDS_TRACE("xmit spdp "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x (resched %gs)\n", - PGUID (pp->e.guid), - PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER, - (double)(tnext.v - tnow.v) / 1e9); + GVTRACE ("xmit spdp "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x (resched %gs)\n", + PGUID (pp->e.guid), + PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER, + (double)(tnext.v - tnow.v) / 1e9); resched_xevent_if_earlier (ev, tnext); } } @@ -1077,8 +1067,8 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e /* schedule next when 80% of the interval has elapsed, or 2s before the lease ends, whichever comes first (similar to PMD), but never wait longer than spdp_interval */ - const int64_t mindelta = 10 * T_MILLISECOND; - const int64_t ldur = pp->lease_duration; + const dds_duration_t mindelta = 10 * T_MILLISECOND; + const dds_duration_t ldur = pp->lease_duration; nn_mtime_t tnext; int64_t intv; @@ -1088,14 +1078,14 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e intv = 4 * ldur / 5; else intv = ldur - 2 * T_SECOND; - if (intv > config.spdp_interval) - intv = config.spdp_interval; + if (intv > gv->config.spdp_interval) + intv = gv->config.spdp_interval; tnext = add_duration_to_mtime (tnow, intv); - DDS_TRACE("xmit spdp "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x (resched %gs)\n", - PGUID (pp->e.guid), - PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER, - (double)(tnext.v - tnow.v) / 1e9); + GVTRACE ("xmit spdp "PGUIDFMT" to %"PRIx32":%"PRIx32":%"PRIx32":%x (resched %gs)\n", + PGUID (pp->e.guid), + PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER, + (double)(tnext.v - tnow.v) / 1e9); resched_xevent_if_earlier (ev, tnext); } } @@ -1103,6 +1093,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e static void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind) { #define PMD_DATA_LENGTH 1 + struct q_globals * const gv = pp->e.gv; struct writer *wr; union { ParticipantMessageData_t pmd; @@ -1113,7 +1104,7 @@ static void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER)) == NULL) { - DDS_TRACE("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid)); + GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid)); return; } @@ -1128,22 +1119,23 @@ static void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack .key = &u.pmd, .keysize = 16 }; - serdata = ddsi_serdata_from_sample (gv.rawcdr_topic, SDK_DATA, &raw); + serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw); serdata->timestamp = now (); - tk = ddsi_tkmap_lookup_instance_ref(serdata); + tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata); write_sample_nogc (ts1, xp, wr, serdata, tk); - ddsi_tkmap_instance_unref(tk); + ddsi_tkmap_instance_unref (gv->m_tkmap, tk); #undef PMD_DATA_LENGTH } static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_xpack *xp, struct xevent *ev, nn_mtime_t tnow) { + struct q_globals * const gv = ev->evq->gv; struct participant *pp; - int64_t intv; + dds_duration_t intv; nn_mtime_t tnext; - if ((pp = ephash_lookup_participant_guid (&ev->u.pmd_update.pp_guid)) == NULL) + if ((pp = ephash_lookup_participant_guid (gv->guid_hash, &ev->u.pmd_update.pp_guid)) == NULL) { return; } @@ -1163,7 +1155,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_ if (intv == T_NEVER) { tnext.v = T_NEVER; - DDS_TRACE("resched pmd("PGUIDFMT"): never\n", PGUID (pp->e.guid)); + GVTRACE ("resched pmd("PGUIDFMT"): never\n", PGUID (pp->e.guid)); } else { @@ -1173,7 +1165,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_ tnext.v = tnow.v + intv - 2 * T_SECOND; else tnext.v = tnow.v + 4 * intv / 5; - DDS_TRACE("resched pmd("PGUIDFMT"): %gs\n", PGUID (pp->e.guid), (double)(tnext.v - tnow.v) / 1e9); + GVTRACE ("resched pmd("PGUIDFMT"): %gs\n", PGUID (pp->e.guid), (double)(tnext.v - tnow.v) / 1e9); } resched_xevent_if_earlier (ev, tnext); @@ -1183,8 +1175,9 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_ static void handle_xevk_delete_writer (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, UNUSED_ARG (nn_mtime_t tnow)) { /* don't worry if the writer is already gone by the time we get here. */ - DDS_TRACE("handle_xevk_delete_writer: "PGUIDFMT"\n", PGUID (ev->u.delete_writer.guid)); - delete_writer_nolinger (&ev->u.delete_writer.guid); + struct q_globals * const gv = ev->evq->gv; + GVTRACE ("handle_xevk_delete_writer: "PGUIDFMT"\n", PGUID (ev->u.delete_writer.guid)); + delete_writer_nolinger (gv, &ev->u.delete_writer.guid); delete_xevent (ev); } @@ -1332,16 +1325,16 @@ static uint32_t xevent_thread (struct xeventq * xevq) struct nn_xpack *xp; nn_mtime_t next_thread_cputime = { 0 }; - xp = nn_xpack_new (xevq->tev_conn, xevq->auxiliary_bandwidth_limit, config.xpack_send_async); + xp = nn_xpack_new (xevq->tev_conn, xevq->auxiliary_bandwidth_limit, xevq->gv->config.xpack_send_async); ddsrt_mutex_lock (&xevq->lock); while (!xevq->terminate) { nn_mtime_t tnow = now_mt (); - LOG_THREAD_CPUTIME (next_thread_cputime); + LOG_THREAD_CPUTIME (&xevq->gv->logconfig, next_thread_cputime); - thread_state_awake (ts1); + thread_state_awake_fixed_domain (ts1); handle_xevents (ts1, xevq, xp, tnow); /* Send to the network unlocked, as it may sleep due to bandwidth limitation */ ddsrt_mutex_unlock (&xevq->lock); @@ -1394,25 +1387,26 @@ void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg) ddsrt_mutex_unlock (&evq->lock); } -void qxev_prd_entityid (struct proxy_reader * prd, nn_guid_prefix_t * id) +void qxev_prd_entityid (struct proxy_reader *prd, nn_guid_prefix_t *id) { + struct q_globals * const gv = prd->e.gv; struct nn_xmsg *msg; struct xevent_nt *ev; /* For connected transports, may need to establish and identify connection */ - if (! gv.xevents->tev_conn->m_connless) + if (! gv->xevents->tev_conn->m_connless) { - msg = nn_xmsg_new (gv.xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); + msg = nn_xmsg_new (gv->xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPRD (msg, prd) == 0) { - DDS_TRACE(" qxev_prd_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); + GVTRACE (" qxev_prd_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); nn_xmsg_add_entityid (msg); - ddsrt_mutex_lock (&gv.xevents->lock); - ev = qxev_common_nt (gv.xevents, XEVK_ENTITYID); + ddsrt_mutex_lock (&gv->xevents->lock); + ev = qxev_common_nt (gv->xevents, XEVK_ENTITYID); ev->u.entityid.msg = msg; qxev_insert_nt (ev); - ddsrt_mutex_unlock (&gv.xevents->lock); + ddsrt_mutex_unlock (&gv->xevents->lock); } else { @@ -1421,8 +1415,9 @@ void qxev_prd_entityid (struct proxy_reader * prd, nn_guid_prefix_t * id) } } -void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id) +void qxev_pwr_entityid (struct proxy_writer *pwr, nn_guid_prefix_t *id) { + struct q_globals * const gv = pwr->e.gv; struct nn_xmsg *msg; struct xevent_nt *ev; @@ -1430,10 +1425,10 @@ void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id) if (! pwr->evq->tev_conn->m_connless) { - msg = nn_xmsg_new (gv.xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); + msg = nn_xmsg_new (gv->xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPWR (msg, pwr) == 0) { - DDS_TRACE(" qxev_pwr_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); + GVTRACE (" qxev_pwr_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); nn_xmsg_add_entityid (msg); ddsrt_mutex_lock (&pwr->evq->lock); ev = qxev_common_nt (pwr->evq, XEVK_ENTITYID); @@ -1450,13 +1445,14 @@ void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id) int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int force) { + struct q_globals * const gv = evq->gv; size_t msg_size = nn_xmsg_size (msg); struct xevent_nt *ev; assert (evq); assert (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT); ddsrt_mutex_lock (&evq->lock); - if ((ev = lookup_msg (evq, msg)) != NULL && nn_xmsg_merge_rexmit_destinations_wrlock_held (ev->u.msg_rexmit.msg, msg)) + if ((ev = lookup_msg (evq, msg)) != NULL && nn_xmsg_merge_rexmit_destinations_wrlock_held (gv, ev->u.msg_rexmit.msg, msg)) { /* MSG got merged with a pending retransmit, so it has effectively been queued */ ddsrt_mutex_unlock (&evq->lock); @@ -1471,8 +1467,8 @@ int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int f ddsrt_mutex_unlock (&evq->lock); nn_xmsg_free (msg); #if 0 - DDS_TRACE(" qxev_msg_rexmit%s drop (sz %"PA_PRIuSIZE" qb %"PA_PRIuSIZE" qm %"PA_PRIuSIZE")", force ? "!" : "", - msg_size, evq->queued_rexmit_bytes, evq->queued_rexmit_msgs); + GVTRACE (" qxev_msg_rexmit%s drop (sz %"PA_PRIuSIZE" qb %"PA_PRIuSIZE" qm %"PA_PRIuSIZE")", force ? "!" : "", + msg_size, evq->queued_rexmit_bytes, evq->queued_rexmit_msgs); #endif return 0; } @@ -1485,7 +1481,7 @@ int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int f evq->queued_rexmit_msgs++; qxev_insert_nt (ev); #if 0 - DDS_TRACE("AAA(%p,%"PA_PRIuSIZE")", (void *) ev, msg_size); + GVTRACE ("AAA(%p,%"PA_PRIuSIZE")", (void *) ev, msg_size); #endif ddsrt_mutex_unlock (&evq->lock); return 2; @@ -1520,11 +1516,11 @@ struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_gu return ev; } -struct xevent *qxev_spdp (nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *dest_proxypp_guid) +struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *dest_proxypp_guid) { struct xevent *ev; - ddsrt_mutex_lock (&gv.xevents->lock); - ev = qxev_common (gv.xevents, tsched, XEVK_SPDP); + ddsrt_mutex_lock (&evq->lock); + ev = qxev_common (evq, tsched, XEVK_SPDP); ev->u.spdp.pp_guid = *pp_guid; if (dest_proxypp_guid == NULL) ev->u.spdp.directed = 0; @@ -1534,40 +1530,40 @@ struct xevent *qxev_spdp (nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_ ev->u.spdp.directed = 4; } qxev_insert (ev); - ddsrt_mutex_unlock (&gv.xevents->lock); + ddsrt_mutex_unlock (&evq->lock); return ev; } -struct xevent *qxev_pmd_update (nn_mtime_t tsched, const nn_guid_t *pp_guid) +struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid) { struct xevent *ev; - ddsrt_mutex_lock (&gv.xevents->lock); - ev = qxev_common (gv.xevents, tsched, XEVK_PMD_UPDATE); + ddsrt_mutex_lock (&evq->lock); + ev = qxev_common (evq, tsched, XEVK_PMD_UPDATE); ev->u.pmd_update.pp_guid = *pp_guid; qxev_insert (ev); - ddsrt_mutex_unlock (&gv.xevents->lock); + ddsrt_mutex_unlock (&evq->lock); return ev; } -struct xevent *qxev_delete_writer (nn_mtime_t tsched, const nn_guid_t *guid) +struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *guid) { struct xevent *ev; - ddsrt_mutex_lock (&gv.xevents->lock); - ev = qxev_common (gv.xevents, tsched, XEVK_DELETE_WRITER); + ddsrt_mutex_lock (&evq->lock); + ev = qxev_common (evq, tsched, XEVK_DELETE_WRITER); ev->u.delete_writer.guid = *guid; qxev_insert (ev); - ddsrt_mutex_unlock (&gv.xevents->lock); + ddsrt_mutex_unlock (&evq->lock); return ev; } -struct xevent *qxev_callback (nn_mtime_t tsched, void (*cb) (struct xevent *ev, void *arg, nn_mtime_t tnow), void *arg) +struct xevent *qxev_callback (struct xeventq *evq, nn_mtime_t tsched, void (*cb) (struct xevent *ev, void *arg, nn_mtime_t tnow), void *arg) { struct xevent *ev; - ddsrt_mutex_lock (&gv.xevents->lock); - ev = qxev_common (gv.xevents, tsched, XEVK_CALLBACK); + ddsrt_mutex_lock (&evq->lock); + ev = qxev_common (evq, tsched, XEVK_CALLBACK); ev->u.callback.cb = cb; ev->u.callback.arg = arg; qxev_insert (ev); - ddsrt_mutex_unlock (&gv.xevents->lock); + ddsrt_mutex_unlock (&evq->lock); return ev; } diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index 3c0eae0..3e34458 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -31,7 +31,6 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_addrset.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_unused.h" @@ -53,7 +52,7 @@ struct nn_xmsgpool { struct nn_xmsg_data { InfoSRC_t src; InfoDST_t dst; - char payload[1]; /* of size maxsz */ + char payload[]; /* of size maxsz */ }; struct nn_xmsg_chain_elem { @@ -135,7 +134,7 @@ struct nn_xmsg_chain { #define NN_BW_UNLIMITED (0) struct nn_bw_limiter { - uint32_t bandwidth; /*Config in bytes/s (0 = UNLIMITED)*/ + uint32_t bandwidth; /*gv.config in bytes/s (0 = UNLIMITED)*/ int64_t balance; nn_mtime_t last_update; }; @@ -148,7 +147,7 @@ typedef struct { ddsrt_cond_t cv; } ddsi_sem_t; -dds_retcode_t +static dds_return_t ddsi_sem_init (ddsi_sem_t *sem, uint32_t value) { sem->value = value; @@ -157,7 +156,7 @@ ddsi_sem_init (ddsi_sem_t *sem, uint32_t value) return DDS_RETCODE_OK; } -dds_retcode_t +static dds_return_t ddsi_sem_destroy (ddsi_sem_t *sem) { ddsrt_cond_destroy (&sem->cv); @@ -165,7 +164,7 @@ ddsi_sem_destroy (ddsi_sem_t *sem) return DDS_RETCODE_OK; } -dds_retcode_t +static dds_return_t ddsi_sem_post (ddsi_sem_t *sem) { ddsrt_mutex_lock (&sem->mtx); @@ -175,7 +174,7 @@ ddsi_sem_post (ddsi_sem_t *sem) return DDS_RETCODE_OK; } -dds_retcode_t +static dds_return_t ddsi_sem_wait (ddsi_sem_t *sem) { ddsrt_mutex_lock (&sem->mtx); @@ -201,8 +200,9 @@ struct nn_xpack ddsi_tran_conn_t conn; ddsi_sem_t sem; size_t niov; - ddsrt_iovec_t iov[NN_XMSG_MAX_MESSAGE_IOVECS]; + ddsrt_iovec_t *iov; enum nn_xmsg_dstmode dstmode; + struct q_globals *gv; union { @@ -264,7 +264,6 @@ static void nn_xmsg_realfree_wrap (void *elem) void nn_xmsgpool_free (struct nn_xmsgpool *pool) { nn_freelist_fini (&pool->freelist, nn_xmsg_realfree_wrap); - DDS_TRACE("xmsgpool_free(%p)\n", (void *)pool); ddsrt_free (pool); } @@ -507,7 +506,7 @@ void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker mar return msg->data->payload + marker.offset; } -void * nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz) +void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz) { static const size_t a = 4; @@ -586,7 +585,7 @@ void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_lo m->data->dst.guid_prefix = nn_hton_guid_prefix (*gp); } -int nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd) +dds_return_t nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd) { nn_locator_t loc; if (addrset_any_uc (prd->c.as, &loc) || addrset_any_mc (prd->c.as, &loc)) @@ -596,12 +595,12 @@ int nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd) } else { - DDS_WARNING("nn_xmsg_setdstPRD: no address for "PGUIDFMT"", PGUID (prd->e.guid)); - return Q_ERR_NO_ADDRESS; + DDS_CWARNING (&prd->e.gv->logconfig, "nn_xmsg_setdstPRD: no address for "PGUIDFMT"", PGUID (prd->e.guid)); + return DDS_RETCODE_PRECONDITION_NOT_MET; } } -int nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr) +dds_return_t nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr) { nn_locator_t loc; if (addrset_any_uc (pwr->c.as, &loc) || addrset_any_mc (pwr->c.as, &loc)) @@ -609,8 +608,8 @@ int nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pwr) nn_xmsg_setdst1 (m, &pwr->e.guid.prefix, &loc); return 0; } - DDS_WARNING("nn_xmsg_setdstPRD: no address for "PGUIDFMT, PGUID (pwr->e.guid)); - return Q_ERR_NO_ADDRESS; + DDS_CWARNING (&pwr->e.gv->logconfig, "nn_xmsg_setdstPRD: no address for "PGUIDFMT, PGUID (pwr->e.guid)); + return DDS_RETCODE_PRECONDITION_NOT_MET; } void nn_xmsg_setdstN (struct nn_xmsg *m, struct addrset *as, struct addrset *as_group) @@ -652,7 +651,7 @@ static int readerId_compatible (const struct nn_xmsg *m, const struct nn_xmsg *m return e.u == NN_ENTITYID_UNKNOWN || e.u == eadd.u; } -int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const struct nn_xmsg *madd) +int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct q_globals *gv, struct nn_xmsg *m, const struct nn_xmsg *madd) { assert (m->kindspecific.data.wrseq >= 1); assert (m->kindspecific.data.wrguid.prefix.u[0] != 0); @@ -665,8 +664,7 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const stru assert (m->kindspecific.data.readerId_off != 0); assert (madd->kindspecific.data.readerId_off != 0); - DDS_TRACE(" ("PGUIDFMT"#%"PRId64"/%u:", - PGUID (m->kindspecific.data.wrguid), m->kindspecific.data.wrseq, m->kindspecific.data.wrfragid + 1); + GVTRACE (" ("PGUIDFMT"#%"PRId64"/%u:", PGUID (m->kindspecific.data.wrguid), m->kindspecific.data.wrseq, m->kindspecific.data.wrfragid + 1); switch (m->dstmode) { @@ -675,7 +673,7 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const stru return 0; case NN_XMSG_DST_ALL: - DDS_TRACE("*->*)"); + GVTRACE ("*->*)"); return 1; case NN_XMSG_DST_ONE: @@ -686,7 +684,7 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const stru return 0; case NN_XMSG_DST_ALL: - DDS_TRACE("1+*->*)"); + GVTRACE ("1+*->*)"); clear_readerId (m); m->dstmode = NN_XMSG_DST_ALL; m->dstaddr.all.as = ref_addrset (madd->dstaddr.all.as); @@ -703,14 +701,14 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const stru an addrset in rebuild_writer_addrset: then we don't need the lock anymore, and the '_wrlock_held' suffix can go and everyone's life will become easier! */ - if ((wr = ephash_lookup_writer_guid (&m->kindspecific.data.wrguid)) == NULL) + if ((wr = ephash_lookup_writer_guid (gv->guid_hash, &m->kindspecific.data.wrguid)) == NULL) { - DDS_TRACE("writer-dead)"); + GVTRACE ("writer-dead)"); return 0; } else { - DDS_TRACE("1+1->*)"); + GVTRACE ("1+1->*)"); clear_readerId (m); m->dstmode = NN_XMSG_DST_ALL; m->dstaddr.all.as = ref_addrset (wr->as); @@ -720,12 +718,12 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct nn_xmsg *m, const stru } else if (readerId_compatible (m, madd)) { - DDS_TRACE("1+1->1)"); + GVTRACE ("1+1->1)"); return 1; } else { - DDS_TRACE("1+1->2)"); + GVTRACE ("1+1->2)"); clear_readerId (m); return 1; } @@ -764,99 +762,24 @@ void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const nn_guid_t *wrguid, msg->kindspecific.data.wrfragid = wrfragid; } -size_t nn_xmsg_add_string_padded(unsigned char *buf, char *str) +void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len) { - size_t len = strlen (str) + 1; - assert (len <= UINT32_MAX); - if (buf) { - /* Add cdr string */ - struct cdrstring *p = (struct cdrstring *) buf; - p->length = (uint32_t)len; - memcpy (p->contents, str, len); - /* clear padding */ - if (len < align4u (len)) { - memset (p->contents + len, 0, align4u (len) - len); - } - } - len = 4 + /* cdr string len arg + */ - align4u(len); /* strlen + possible padding */ - return len; -} - -size_t nn_xmsg_add_octseq_padded(unsigned char *buf, nn_octetseq_t *seq) -{ - unsigned len = seq->length; - if (buf) { - /* Add cdr octet seq */ - *((unsigned *)buf) = len; - buf += sizeof (int); - memcpy (buf, seq->value, len); - /* clear padding */ - if (len < align4u (len)) { - memset (buf + len, 0, align4u (len) - len); - } - } - return 4 + /* cdr sequence len arg + */ - align4u(len); /* seqlen + possible padding */ -} - -void * nn_xmsg_addpar (struct nn_xmsg *m, unsigned pid, size_t len) -{ - const size_t len4 = (len + 3) & (size_t)-4; /* must alloc a multiple of 4 */ + const size_t len4 = (len + 3) & ~(size_t)3; /* must alloc a multiple of 4 */ nn_parameter_t *phdr; char *p; + assert (len4 < UINT16_MAX); /* FIXME: return error */ m->have_params = 1; phdr = nn_xmsg_append (m, NULL, sizeof (nn_parameter_t) + len4); - phdr->parameterid = (nn_parameterid_t) pid; - phdr->length = (unsigned short) len4; + phdr->parameterid = pid; + phdr->length = (uint16_t) len4; p = (char *) (phdr + 1); - if (len4 > len) - { - /* zero out padding bytes added to satisfy parameter alignment -- - alternative: zero out, but this way valgrind/purify can tell us - where we forgot to initialize something */ - memset (p + len, 0, len4 - len); - } + /* zero out padding bytes added to satisfy parameter alignment: this way + valgrind can tell us where we forgot to initialize something */ + while (len < len4) + p[len++] = 0; return p; } -void nn_xmsg_addpar_string (struct nn_xmsg *m, unsigned pid, const char *str) -{ - struct cdrstring *p; - unsigned len = (unsigned) strlen (str) + 1; - p = nn_xmsg_addpar (m, pid, 4 + len); - p->length = len; - memcpy (p->contents, str, len); -} - -void nn_xmsg_addpar_octetseq (struct nn_xmsg *m, unsigned pid, const nn_octetseq_t *oseq) -{ - char *p = nn_xmsg_addpar (m, pid, 4 + oseq->length); - *((unsigned *) p) = oseq->length; - memcpy (p + sizeof (int), oseq->value, oseq->length); -} - -void nn_xmsg_addpar_stringseq (struct nn_xmsg *m, unsigned pid, const nn_stringseq_t *sseq) -{ - unsigned char *tmp; - uint32_t i; - size_t len = 0; - - for (i = 0; i < sseq->n; i++) - { - len += nn_xmsg_add_string_padded(NULL, sseq->strs[i]); - } - - tmp = nn_xmsg_addpar (m, pid, 4 + len); - - *((uint32_t *) tmp) = sseq->n; - tmp += sizeof (uint32_t); - for (i = 0; i < sseq->n; i++) - { - tmp += nn_xmsg_add_string_padded(tmp, sseq->strs[i]); - } -} - void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata) { if (serdata->kind != SDK_EMPTY) @@ -867,62 +790,9 @@ void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serda } } -void nn_xmsg_addpar_guid (struct nn_xmsg *m, unsigned pid, const nn_guid_t *guid) +static void nn_xmsg_addpar_BE4u (struct nn_xmsg *m, nn_parameterid_t pid, uint32_t x) { - unsigned *pu; - int i; - pu = nn_xmsg_addpar (m, pid, 16); - for (i = 0; i < 3; i++) - { - pu[i] = toBE4u (guid->prefix.u[i]); - } - pu[i] = toBE4u (guid->entityid.u); -} - -void nn_xmsg_addpar_reliability (struct nn_xmsg *m, unsigned pid, const struct nn_reliability_qospolicy *rq) -{ - struct nn_external_reliability_qospolicy *p; - p = nn_xmsg_addpar (m, pid, sizeof (*p)); - if (NN_PEDANTIC_P) - { - switch (rq->kind) - { - case NN_BEST_EFFORT_RELIABILITY_QOS: - p->kind = NN_PEDANTIC_BEST_EFFORT_RELIABILITY_QOS; - break; - case NN_RELIABLE_RELIABILITY_QOS: - p->kind = NN_PEDANTIC_RELIABLE_RELIABILITY_QOS; - break; - default: - assert (0); - } - } - else - { - switch (rq->kind) - { - case NN_BEST_EFFORT_RELIABILITY_QOS: - p->kind = NN_INTEROP_BEST_EFFORT_RELIABILITY_QOS; - break; - case NN_RELIABLE_RELIABILITY_QOS: - p->kind = NN_INTEROP_RELIABLE_RELIABILITY_QOS; - break; - default: - assert (0); - } - } - p->max_blocking_time = rq->max_blocking_time; -} - -void nn_xmsg_addpar_4u (struct nn_xmsg *m, unsigned pid, unsigned x) -{ - unsigned *p = nn_xmsg_addpar (m, pid, 4); - *p = x; -} - -void nn_xmsg_addpar_BE4u (struct nn_xmsg *m, unsigned pid, unsigned x) -{ - unsigned *p = nn_xmsg_addpar (m, pid, 4); + unsigned *p = nn_xmsg_addpar (m, pid, sizeof (x)); *p = toBE4u (x); } @@ -942,62 +812,6 @@ void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo) } } - -void nn_xmsg_addpar_share (struct nn_xmsg *m, unsigned pid, const struct nn_share_qospolicy *q) -{ - /* Written thus to allow q->name to be a null pointer if enable = false */ - const unsigned fixed_len = 4 + 4; - const unsigned len = (q->enable ? (unsigned) strlen (q->name) : 0) + 1; - unsigned char *p; - struct cdrstring *ps; - p = nn_xmsg_addpar (m, pid, fixed_len + len); - p[0] = q->enable; - p[1] = 0; - p[2] = 0; - p[3] = 0; - ps = (struct cdrstring *) (p + 4); - ps->length = len; - if (q->enable) - memcpy (ps->contents, q->name, len); - else - ps->contents[0] = 0; -} - -void nn_xmsg_addpar_subscription_keys (struct nn_xmsg *m, unsigned pid, const struct nn_subscription_keys_qospolicy *q) -{ - unsigned char *tmp; - size_t len = 8; /* use_key_list, length of key_list */ - unsigned i; - - for (i = 0; i < q->key_list.n; i++) - { - size_t len1 = strlen (q->key_list.strs[i]) + 1; - len += 4 + align4u (len1); - } - - tmp = nn_xmsg_addpar (m, pid, len); - - tmp[0] = q->use_key_list; - for (i = 1; i < sizeof (int); i++) - { - tmp[i] = 0; - } - tmp += sizeof (int); - *((uint32_t *) tmp) = q->key_list.n; - tmp += sizeof (uint32_t); - for (i = 0; i < q->key_list.n; i++) - { - struct cdrstring *p = (struct cdrstring *) tmp; - size_t len1 = strlen (q->key_list.strs[i]) + 1; - assert (len1 <= UINT32_MAX); - p->length = (uint32_t)len1; - memcpy (p->contents, q->key_list.strs[i], len1); - if (len1 < align4u (len1)) - memset (p->contents + len1, 0, align4u (len1) - len1); - tmp += 4 + align4u (len1); - } -} - void nn_xmsg_addpar_sentinel (struct nn_xmsg * m) { nn_xmsg_addpar (m, PID_SENTINEL, 0); @@ -1013,40 +827,6 @@ int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg * m) return 0; } -void nn_xmsg_addpar_parvinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_participant_version_info *pvi) -{ - int i; - unsigned slen; - unsigned *pu; - struct cdrstring *ps; - - /* pvi->internals cannot be NULL here */ - slen = (unsigned) strlen(pvi->internals) + 1; /* +1 for '\0' terminator */ - pu = nn_xmsg_addpar (m, pid, NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE + slen); - pu[0] = pvi->version; - pu[1] = pvi->flags; - for (i = 0; i < 3; i++) - { - pu[i+2] = (pvi->unused[i]); - } - ps = (struct cdrstring *)&pu[5]; - ps->length = slen; - memcpy(ps->contents, pvi->internals, slen); -} - -void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, unsigned pid, const struct nn_prismtech_eotinfo *txnid) -{ - uint32_t *pu, i; - pu = nn_xmsg_addpar (m, pid, 2 * sizeof (uint32_t) + txnid->n * sizeof (txnid->tids[0])); - pu[0] = txnid->transactionId; - pu[1] = txnid->n; - for (i = 0; i < txnid->n; i++) - { - pu[2*i + 2] = toBE4u (txnid->tids[i].writer_entityid.u); - pu[2*i + 3] = txnid->tids[i].transactionId; - } -} - /* XMSG_CHAIN ---------------------------------------------------------- Xpacks refer to xmsgs and need to release these after having been @@ -1056,7 +836,7 @@ void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, unsigned pid, const struct nn_pr pointer we compute the address of the xmsg from the address of the chain element, &c. */ -static void nn_xmsg_chain_release (struct nn_xmsg_chain *chain) +static void nn_xmsg_chain_release (struct q_globals *gv, struct nn_xmsg_chain *chain) { nn_guid_t wrguid; memset (&wrguid, 0, sizeof (wrguid)); @@ -1087,7 +867,7 @@ static void nn_xmsg_chain_release (struct nn_xmsg_chain *chain) struct writer *wr; assert (m->kindspecific.data.wrseq != 0); wrguid = m->kindspecific.data.wrguid; - if ((wr = ephash_lookup_writer_guid (&m->kindspecific.data.wrguid)) != NULL) + if ((wr = ephash_lookup_writer_guid (gv->guid_hash, &m->kindspecific.data.wrguid)) != NULL) UPDATE_SEQ_XMIT_UNLOCKED(wr, m->kindspecific.data.wrseq); } } @@ -1114,7 +894,7 @@ static void nn_xmsg_chain_add (struct nn_xmsg_chain *chain, struct nn_xmsg *m) #define NN_BW_LIMIT_MAX_BUFFER (-30 * T_MILLISECOND) #define NN_BW_LIMIT_MIN_SLEEP (2 * T_MILLISECOND) -static void nn_bw_limit_sleep_if_needed(struct nn_bw_limiter* this, ssize_t size) +static void nn_bw_limit_sleep_if_needed (struct q_globals const * const gv, struct nn_bw_limiter *this, ssize_t size) { if ( this->bandwidth > 0 ) { nn_mtime_t tnow = now_mt(); @@ -1130,27 +910,27 @@ static void nn_bw_limit_sleep_if_needed(struct nn_bw_limiter* this, ssize_t size this->balance += (target_interval - actual_interval); - DDS_TRACE(" balance < NN_BW_LIMIT_MAX_BUFFER ) { /* We're below the bandwidth limit, do not further accumulate */ this->balance = NN_BW_LIMIT_MAX_BUFFER; - DDS_TRACE(":%"PRId64":max",this->balance/1000); + GVTRACE (":%"PRId64":max",this->balance/1000); } else if ( this->balance > NN_BW_LIMIT_MIN_SLEEP ) { /* We're over the bandwidth limit far enough, to warrent a sleep. */ - DDS_TRACE(":%"PRId64":sleep",this->balance/1000); + GVTRACE (":%"PRId64":sleep",this->balance/1000); thread_state_blocked (lookup_thread_state ()); dds_sleepfor (this->balance); thread_state_unblocked (lookup_thread_state ()); } else { - DDS_TRACE(":%"PRId64"",this->balance/1000); + GVTRACE (":%"PRId64"",this->balance/1000); } - DDS_TRACE(">"); + GVTRACE (">"); } } @@ -1192,11 +972,13 @@ struct nn_xpack * nn_xpack_new (ddsi_tran_conn_t conn, uint32_t bw_limit, bool a /* Disallow setting async_mode if not configured to enable async mode: this way we can avoid starting the async send thread altogether */ - assert (!async_mode || config.xpack_send_async); + assert (!async_mode || conn->m_base.gv->config.xpack_send_async); xp = ddsrt_malloc (sizeof (*xp)); memset (xp, 0, sizeof (*xp)); xp->async_mode = async_mode; + xp->iov = NULL; + xp->gv = conn->m_base.gv; /* Fixed header fields, initialized just once */ xp->hdr.protocol.id[0] = 'R'; @@ -1216,7 +998,7 @@ struct nn_xpack * nn_xpack_new (ddsi_tran_conn_t conn, uint32_t bw_limit, bool a xp->conn = conn; nn_xpack_reinit (xp); - if (gv.thread_pool) + if (xp->gv->thread_pool) ddsi_sem_init (&xp->sem, 0); #ifdef DDSI_INCLUDE_ENCRYPTION @@ -1247,29 +1029,31 @@ void nn_xpack_free (struct nn_xpack *xp) (q_security_plugin.free_encoder) (xp->codec); } #endif - if (gv.thread_pool) + if (xp->gv->thread_pool) ddsi_sem_destroy (&xp->sem); + ddsrt_free (xp->iov); ddsrt_free (xp); } static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) { - struct nn_xpack * xp = varg; + struct nn_xpack *xp = varg; + struct q_globals const * const gv = xp->gv; ssize_t nbytes = 0; - if (dds_get_log_mask() & DDS_LC_TRACE) + if (gv->logconfig.c.mask & DDS_LC_TRACE) { char buf[DDSI_LOCSTRLEN]; - DDS_TRACE(" %s", ddsi_locator_to_string (buf, sizeof(buf), loc)); + GVTRACE (" %s", ddsi_locator_to_string (gv, buf, sizeof(buf), loc)); } - if (config.xmit_lossiness > 0) + if (gv->config.xmit_lossiness > 0) { /* We drop APPROXIMATELY a fraction of xmit_lossiness * 10**(-3) of all packets to be sent */ - if ((ddsrt_random () % 1000) < (uint32_t) config.xmit_lossiness) + if ((ddsrt_random () % 1000) < (uint32_t) gv->config.xmit_lossiness) { - DDS_TRACE("(dropped)"); + GVTRACE ("(dropped)"); xp->call_flags = 0; return 0; } @@ -1285,7 +1069,7 @@ static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) else #endif { - if (!gv.mute) + if (!gv->mute) { nbytes = ddsi_conn_write (xp->conn, loc, xp->niov, xp->iov, xp->call_flags); #ifndef NDEBUG @@ -1300,7 +1084,7 @@ static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) } else { - DDS_TRACE("(dropped)"); + GVTRACE ("(dropped)"); nbytes = (ssize_t) xp->msg_len.length; } } @@ -1312,7 +1096,7 @@ static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING if (nbytes > 0) { - nn_bw_limit_sleep_if_needed (&xp->limiter, nbytes); + nn_bw_limit_sleep_if_needed (gv, &xp->limiter, nbytes); } #endif @@ -1346,11 +1130,12 @@ static void nn_xpack_send1_threaded (const nn_locator_t *loc, void * varg) arg->xp = (struct nn_xpack *) varg; arg->loc = loc; ddsrt_atomic_inc32 (&arg->xp->calls); - ddsrt_thread_pool_submit (gv.thread_pool, nn_xpack_send1_thread, arg); + ddsrt_thread_pool_submit (arg->xp->gv->thread_pool, nn_xpack_send1_thread, arg); } -static void nn_xpack_send_real (struct nn_xpack * xp) +static void nn_xpack_send_real (struct nn_xpack *xp) { + struct q_globals const * const gv = xp->gv; size_t calls; assert (xp->niov <= NN_XMSG_MAX_MESSAGE_IOVECS); @@ -1362,17 +1147,17 @@ static void nn_xpack_send_real (struct nn_xpack * xp) assert (xp->dstmode != NN_XMSG_DST_UNSET); - if (dds_get_log_mask() & DDS_LC_TRACE) + if (gv->logconfig.c.mask & DDS_LC_TRACE) { int i; - DDS_TRACE("nn_xpack_send %"PRIu32":", xp->msg_len.length); + GVTRACE ("nn_xpack_send %"PRIu32":", xp->msg_len.length); for (i = 0; i < (int) xp->niov; i++) { - DDS_TRACE(" %p:%lu", (void *) xp->iov[i].iov_base, (unsigned long) xp->iov[i].iov_len); + GVTRACE (" %p:%lu", (void *) xp->iov[i].iov_base, (unsigned long) xp->iov[i].iov_len); } } - DDS_TRACE(" ["); + GVTRACE (" ["); if (xp->dstmode == NN_XMSG_DST_ONE) { calls = 1; @@ -1386,7 +1171,7 @@ static void nn_xpack_send_real (struct nn_xpack * xp) calls = 0; if (xp->dstaddr.all.as) { - if (gv.thread_pool == NULL) + if (xp->gv->thread_pool == NULL) { calls = addrset_forall_count (xp->dstaddr.all.as, nn_xpack_send1v, xp); } @@ -1415,12 +1200,12 @@ static void nn_xpack_send_real (struct nn_xpack * xp) unref_addrset (xp->dstaddr.all.as_group); } } - DDS_TRACE(" ]\n"); + GVTRACE (" ]\n"); if (calls) { - DDS_LOG(DDS_LC_TRAFFIC, "traffic-xmit (%lu) %"PRIu32"\n", (unsigned long) calls, xp->msg_len.length); + GVLOG (DDS_LC_TRAFFIC, "traffic-xmit (%lu) %"PRIu32"\n", (unsigned long) calls, xp->msg_len.length); } - nn_xmsg_chain_release (&xp->included_msgs); + nn_xmsg_chain_release (xp->gv, &xp->included_msgs); nn_xpack_reinit (xp); } @@ -1428,60 +1213,61 @@ static void nn_xpack_send_real (struct nn_xpack * xp) #define SENDQ_HW 10 #define SENDQ_LW 0 -static uint32_t nn_xpack_sendq_thread (UNUSED_ARG (void *arg)) +static uint32_t nn_xpack_sendq_thread (void *vgv) { - ddsrt_mutex_lock (&gv.sendq_lock); - while (!(gv.sendq_stop && gv.sendq_head == NULL)) + struct q_globals *gv = vgv; + ddsrt_mutex_lock (&gv->sendq_lock); + while (!(gv->sendq_stop && gv->sendq_head == NULL)) { struct nn_xpack *xp; - if ((xp = gv.sendq_head) == NULL) + if ((xp = gv->sendq_head) == NULL) { - ddsrt_cond_waitfor (&gv.sendq_cond, &gv.sendq_lock, 1000000); + ddsrt_cond_waitfor (&gv->sendq_cond, &gv->sendq_lock, 1000000); } else { - gv.sendq_head = xp->sendq_next; - if (--gv.sendq_length == SENDQ_LW) - ddsrt_cond_broadcast (&gv.sendq_cond); - ddsrt_mutex_unlock (&gv.sendq_lock); + gv->sendq_head = xp->sendq_next; + if (--gv->sendq_length == SENDQ_LW) + ddsrt_cond_broadcast (&gv->sendq_cond); + ddsrt_mutex_unlock (&gv->sendq_lock); nn_xpack_send_real (xp); nn_xpack_free (xp); - ddsrt_mutex_lock (&gv.sendq_lock); + ddsrt_mutex_lock (&gv->sendq_lock); } } - ddsrt_mutex_unlock (&gv.sendq_lock); + ddsrt_mutex_unlock (&gv->sendq_lock); return 0; } -void nn_xpack_sendq_init (void) +void nn_xpack_sendq_init (struct q_globals *gv) { - gv.sendq_stop = 0; - gv.sendq_head = NULL; - gv.sendq_tail = NULL; - gv.sendq_length = 0; - ddsrt_mutex_init (&gv.sendq_lock); - ddsrt_cond_init (&gv.sendq_cond); + gv->sendq_stop = 0; + gv->sendq_head = NULL; + gv->sendq_tail = NULL; + gv->sendq_length = 0; + ddsrt_mutex_init (&gv->sendq_lock); + ddsrt_cond_init (&gv->sendq_cond); } -void nn_xpack_sendq_start (void) +void nn_xpack_sendq_start (struct q_globals *gv) { - create_thread (&gv.sendq_ts, "sendq", nn_xpack_sendq_thread, NULL); + create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL); } -void nn_xpack_sendq_stop (void) +void nn_xpack_sendq_stop (struct q_globals *gv) { - ddsrt_mutex_lock (&gv.sendq_lock); - gv.sendq_stop = 1; - ddsrt_cond_broadcast (&gv.sendq_cond); - ddsrt_mutex_unlock (&gv.sendq_lock); + ddsrt_mutex_lock (&gv->sendq_lock); + gv->sendq_stop = 1; + ddsrt_cond_broadcast (&gv->sendq_cond); + ddsrt_mutex_unlock (&gv->sendq_lock); } -void nn_xpack_sendq_fini (void) +void nn_xpack_sendq_fini (struct q_globals *gv) { - assert (gv.sendq_head == NULL); - join_thread(gv.sendq_ts); - ddsrt_cond_destroy(&gv.sendq_cond); - ddsrt_mutex_destroy(&gv.sendq_lock); + assert (gv->sendq_head == NULL); + join_thread (gv->sendq_ts); + ddsrt_cond_destroy (&gv->sendq_cond); + ddsrt_mutex_destroy (&gv->sendq_lock); } void nn_xpack_send (struct nn_xpack *xp, bool immediately) @@ -1492,27 +1278,28 @@ void nn_xpack_send (struct nn_xpack *xp, bool immediately) } else { + struct q_globals * const gv = xp->gv; struct nn_xpack *xp1 = ddsrt_malloc (sizeof (*xp)); memcpy (xp1, xp, sizeof (*xp1)); nn_xpack_reinit (xp); xp1->sendq_next = NULL; - ddsrt_mutex_lock (&gv.sendq_lock); - if (immediately || gv.sendq_length == SENDQ_HW) - ddsrt_cond_broadcast (&gv.sendq_cond); - if (gv.sendq_length >= SENDQ_MAX) + ddsrt_mutex_lock (&gv->sendq_lock); + if (immediately || gv->sendq_length == SENDQ_HW) + ddsrt_cond_broadcast (&gv->sendq_cond); + if (gv->sendq_length >= SENDQ_MAX) { - while (gv.sendq_length > SENDQ_LW) - ddsrt_cond_wait (&gv.sendq_cond, &gv.sendq_lock); + while (gv->sendq_length > SENDQ_LW) + ddsrt_cond_wait (&gv->sendq_cond, &gv->sendq_lock); } - if (gv.sendq_head) - gv.sendq_tail->sendq_next = xp1; + if (gv->sendq_head) + gv->sendq_tail->sendq_next = xp1; else { - gv.sendq_head = xp1; + gv->sendq_head = xp1; } - gv.sendq_tail = xp1; - gv.sendq_length++; - ddsrt_mutex_unlock (&gv.sendq_lock); + gv->sendq_tail = xp1; + gv->sendq_length++; + ddsrt_mutex_unlock (&gv->sendq_lock); } } @@ -1554,7 +1341,7 @@ static int addressing_info_eq_onesidederr (const struct nn_xpack *xp, const stru static int nn_xpack_mayaddmsg (const struct nn_xpack *xp, const struct nn_xmsg *m, const uint32_t flags) { - unsigned max_msg_size = config.max_msg_size; + unsigned max_msg_size = xp->gv->config.max_msg_size; unsigned payload_size; if (xp->niov == 0) @@ -1606,7 +1393,7 @@ static int guid_prefix_eq (const nn_guid_prefix_t *a, const nn_guid_prefix_t *b) int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flags) { /* Returns > 0 if pack got sent out before adding m */ - + struct q_globals const * const gv = xp->gv; static InfoDST_t static_zero_dst = { { SMID_INFO_DST, (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? SMFLAG_ENDIANNESS : 0), sizeof (nn_guid_prefix_t) }, { { 0,0,0,0, 0,0,0,0, 0,0,0,0 } } @@ -1630,6 +1417,9 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag assert ((m->sz % 4) == 0); assert (m->refd_payload == NULL || (m->refd_payload_iov.iov_len % 4) == 0); + if (xp->iov == NULL) + xp->iov = malloc (NN_XMSG_MAX_MESSAGE_IOVECS * sizeof (*xp->iov)); + if (!nn_xpack_mayaddmsg (xp, m, flags)) { assert (xp->niov > 0); @@ -1647,22 +1437,22 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag But do make sure we can't run out of iovecs. */ assert (niov + NN_XMSG_MAX_SUBMESSAGE_IOVECS <= NN_XMSG_MAX_MESSAGE_IOVECS); - DDS_TRACE("xpack_addmsg %p %p %"PRIu32"(", (void *) xp, (void *) m, flags); + GVTRACE ("xpack_addmsg %p %p %"PRIu32"(", (void *) xp, (void *) m, flags); switch (m->kind) { case NN_XMSG_KIND_CONTROL: - DDS_TRACE("control"); + GVTRACE ("control"); break; case NN_XMSG_KIND_DATA: case NN_XMSG_KIND_DATA_REXMIT: - DDS_TRACE("%s("PGUIDFMT":#%"PRId64"/%u)", - (m->kind == NN_XMSG_KIND_DATA) ? "data" : "rexmit", - PGUID (m->kindspecific.data.wrguid), - m->kindspecific.data.wrseq, - m->kindspecific.data.wrfragid + 1); + GVTRACE ("%s("PGUIDFMT":#%"PRId64"/%u)", + (m->kind == NN_XMSG_KIND_DATA) ? "data" : "rexmit", + PGUID (m->kindspecific.data.wrguid), + m->kindspecific.data.wrseq, + m->kindspecific.data.wrfragid + 1); break; } - DDS_TRACE("): niov %d sz %"PRIuSIZE, (int) niov, sz); + GVTRACE ("): niov %d sz %"PRIuSIZE, (int) niov, sz); /* If a fresh xp has been provided, add an RTPS header */ @@ -1788,9 +1578,10 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag xp->msg_len.length = (uint32_t) sz; xp->niov = niov; - if (xpo_niov > 0 && sz > config.max_msg_size) + if (xpo_niov > 0 && sz > xp->gv->config.max_msg_size) { - DDS_TRACE(" => now niov %d sz %"PRIuSIZE" > max_msg_size %"PRIu32", nn_xpack_send niov %d sz %"PRIu32" now\n", (int) niov, sz, config.max_msg_size, (int) xpo_niov, xpo_sz); + GVTRACE (" => now niov %d sz %"PRIuSIZE" > max_msg_size %"PRIu32", nn_xpack_send niov %d sz %"PRIu32" now\n", + (int) niov, sz, gv->config.max_msg_size, (int) xpo_niov, xpo_sz); xp->msg_len.length = xpo_sz; xp->niov = xpo_niov; nn_xpack_send (xp, false); @@ -1800,7 +1591,7 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag { xp->call_flags = flags; nn_xmsg_chain_add (&xp->included_msgs, m); - DDS_TRACE(" => now niov %d sz %"PRIuSIZE"\n", (int) niov, sz); + GVTRACE (" => now niov %d sz %"PRIuSIZE"\n", (int) niov, sz); } return result; diff --git a/src/core/ddsi/src/sysdeps.c b/src/core/ddsi/src/sysdeps.c index 13fa3f1..e7b2915 100644 --- a/src/core/ddsi/src/sysdeps.c +++ b/src/core/ddsi/src/sysdeps.c @@ -15,13 +15,11 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/misc.h" -#include "dds/ddsi/q_error.h" #include "dds/ddsi/q_log.h" -#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) -void log_stacktrace (const char *name, ddsrt_thread_t tid) +#if DDSRT_WITH_FREERTOS || !(defined __APPLE__ || defined __linux) || (__GNUC__ > 0 && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40100) +void log_stacktrace (const struct ddsrt_log_cfg *logcfg, const char *name, ddsrt_thread_t tid) { DDSRT_UNUSED_ARG (name); DDSRT_UNUSED_ARG (tid); @@ -46,42 +44,35 @@ static void log_stacktrace_sigh (int sig __attribute__ ((unused))) errno = e; } -void log_stacktrace (const char *name, ddsrt_thread_t tid) +void log_stacktrace (const struct ddsrt_log_cfg *logcfg, const char *name, ddsrt_thread_t tid) { - if (dds_get_log_mask() == 0) - ; /* no op if nothing logged */ - else if (!config.noprogress_log_stacktraces) - DDS_LOG(~DDS_LC_FATAL, "-- stack trace of %s requested, but traces disabled --\n", name); + const dds_time_t d = 1000000; + struct sigaction act, oact; + char **strs; + int i; + DDS_CLOG (~DDS_LC_FATAL, logcfg, "-- stack trace of %s requested --\n", name); + act.sa_handler = log_stacktrace_sigh; + act.sa_flags = 0; + sigfillset (&act.sa_mask); + while (!ddsrt_atomic_cas32 (&log_stacktrace_flag, 0, 1)) + dds_sleepfor (d); + sigaction (SIGXCPU, &act, &oact); + pthread_kill (tid.v, SIGXCPU); + while (!ddsrt_atomic_cas32 (&log_stacktrace_flag, 2, 3) && pthread_kill (tid.v, 0) == 0) + dds_sleepfor (d); + sigaction (SIGXCPU, &oact, NULL); + if (pthread_kill (tid.v, 0) != 0) + DDS_CLOG (~DDS_LC_FATAL, logcfg, "-- thread exited --\n"); else { - const dds_time_t d = 1000000; - struct sigaction act, oact; - char **strs; - int i; - DDS_LOG(~DDS_LC_FATAL, "-- stack trace of %s requested --\n", name); - act.sa_handler = log_stacktrace_sigh; - act.sa_flags = 0; - sigfillset (&act.sa_mask); - while (!ddsrt_atomic_cas32 (&log_stacktrace_flag, 0, 1)) - dds_sleepfor (d); - sigaction (SIGXCPU, &act, &oact); - pthread_kill (tid.v, SIGXCPU); - while (!ddsrt_atomic_cas32 (&log_stacktrace_flag, 2, 3) && pthread_kill (tid.v, 0) == 0) - dds_sleepfor (d); - sigaction (SIGXCPU, &oact, NULL); - if (pthread_kill (tid.v, 0) != 0) - DDS_LOG(~DDS_LC_FATAL, "-- thread exited --\n"); - else - { - DDS_LOG(~DDS_LC_FATAL, "-- stack trace follows --\n"); - strs = backtrace_symbols (log_stacktrace_stk.stk, log_stacktrace_stk.depth); - for (i = 0; i < log_stacktrace_stk.depth; i++) - DDS_LOG(~DDS_LC_FATAL, "%s\n", strs[i]); - free (strs); - DDS_LOG(~DDS_LC_FATAL, "-- end of stack trace --\n"); - } - ddsrt_atomic_st32 (&log_stacktrace_flag, 0); + DDS_CLOG (~DDS_LC_FATAL, logcfg, "-- stack trace follows --\n"); + strs = backtrace_symbols (log_stacktrace_stk.stk, log_stacktrace_stk.depth); + for (i = 0; i < log_stacktrace_stk.depth; i++) + DDS_CLOG (~DDS_LC_FATAL, logcfg, "%s\n", strs[i]); + free (strs); + DDS_CLOG (~DDS_LC_FATAL, logcfg, "-- end of stack trace --\n"); } + ddsrt_atomic_st32 (&log_stacktrace_flag, 0); } #endif diff --git a/src/core/xtests/CMakeLists.txt b/src/core/xtests/CMakeLists.txt index 02b7bfd..72bdb94 100644 --- a/src/core/xtests/CMakeLists.txt +++ b/src/core/xtests/CMakeLists.txt @@ -9,18 +9,5 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(RhcTypes RhcTypes.idl) - -add_executable(rhc_torture rhc_torture.c) - -target_include_directories( - rhc_torture PRIVATE - "$" - "$") - -target_link_libraries(rhc_torture RhcTypes ddsc) - -add_test( - NAME rhc_torture - COMMAND rhc_torture 314159265 0 5000 0) -set_property(TEST rhc_torture PROPERTY TIMEOUT 20) +add_subdirectory(rhc_torture) +add_subdirectory(initsampledeliv) diff --git a/src/core/xtests/cdrtest/CMakeLists.txt b/src/core/xtests/cdrtest/CMakeLists.txt new file mode 100644 index 0000000..1535a9c --- /dev/null +++ b/src/core/xtests/cdrtest/CMakeLists.txt @@ -0,0 +1,40 @@ +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.5) + +add_compile_options("-I${PROJECT_SOURCE_DIR}/src/ddsrt/include") +add_compile_options("-I${PROJECT_SOURCE_DIR}/src/core/ddsc/include") +add_compile_options("-I${PROJECT_SOURCE_DIR}/src/core/ddsc/src") +add_compile_options("-I${PROJECT_SOURCE_DIR}/src/core/ddsi/include") + +add_compile_options("-I$ENV{OSPL_HOME}/src/abstraction/os/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/database/database/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/database/serialization/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/utilities/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/kernel/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/kernel/bld/$ENV{SPLICE_TARGET}") +add_compile_options("-I$ENV{OSPL_HOME}/src/user/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/api/dcps/sac/include") +add_compile_options("-I$ENV{OSPL_HOME}/src/api/dcps/sac/code") + +# This is a convenience function, provided by the CycloneDDS package, +# that will supply a library target related the the given idl file. +# In short, it takes the idl file, generates the source files with +# the proper data types and compiles them into a library. +idlc_generate(xxx_lib "xxx.idl") + +# Both executables have only one related source file. +add_executable(xxx xxx-cyc.c) + +# Both executables need to be linked to the idl data type library and +# the ddsc API library. +target_link_libraries(xxx xxx_lib CycloneDDS::ddsc -L$ENV{OSPL_HOME}/lib/$ENV{SPLICE_TARGET} -Wl,-rpath,$ENV{OSPL_HOME}/lib/$ENV{SPLICE_TARGET} ddskernel dcpssac) diff --git a/src/core/xtests/cdrtest/cdrtest.pl b/src/core/xtests/cdrtest/cdrtest.pl new file mode 100644 index 0000000..e850927 --- /dev/null +++ b/src/core/xtests/cdrtest/cdrtest.pl @@ -0,0 +1,403 @@ +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# + +#use strict; + +use Data::Dumper; +$Data::Dumper::Terse = 1; +$Data::Dumper::Useqq = 1; + +my $outfn = "xxx"; +local $nextident = "a0000"; + +my @types = qw(u0 u1 u2 u3 u4 seq ary str uni); +my @idltype = ("octet", "unsigned short", "unsigned long", "unsigned long long", "string"); +# unions cannot have an octet as a discriminator ... +my @idltype_unidisc = ("char", "unsigned short", "unsigned long", "unsigned long long", "string"); +my @ctype = ("uint8_t", "uint16_t", "uint32_t", "uint64_t", "char *"); +my @probs = do { + my @ps = qw(0.3 0.3 0.3 0.3 0.3 1 1 1 1); + my (@xs, $sum); + for (@ps) { $sum += $_; push @xs, $sum; } + @xs; +}; +my @noaryprobs = do { + my @ps = qw(0.3 0.3 0.3 0.3 0.3 1 0 1 1); + my (@xs, $sum); + for (@ps) { $sum += $_; push @xs, $sum; } + @xs; +}; +my @unicaseprobs = do { + my @ps = qw(0.3 0.3 0.3 0.3 0.3 1 0 1 0); + my (@xs, $sum); + for (@ps) { $sum += $_; push @xs, $sum; } + @xs; +}; + +open IDL, ">${outfn}.idl" or die "can't open ${outfn}.idl"; +open CYC, ">${outfn}-cyc.c" or die "can't open ${outfn}-cyc.c"; +print CYC < +#include +#include +#include +#include "dds/dds.h" +#include "dds/ddsrt/random.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsi/ddsi_serdata_default.h" +#include "dds__stream.h" + +#include "c_base.h" +#include "sd_cdr.h" +#include "sd_serializerXMLTypeinfo.h" +#include "v_copyIn.h" +#include "sac_genericCopyIn.h" + +#include "xxx.h" +int main() +{ + unsigned char garbage[1000]; + struct ddsi_sertopic_default ddd; + uint32_t deser_garbage = 0; + memset (&ddd, 0, sizeof (ddd)); + dds_istream_t is; + c_base base = c_create ("X", NULL, 0, 0); + dds_entity_t dp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + if (dp < 0) abort (); +EOF +; +for (1 .. 300) { + my $t = genstr (0); + my $idl = genidltd ($t); + print IDL $idl; + (my $idlcmt = $idl) =~ s,^,//,mg; + print CYC $idlcmt; + gencyc ($t); +} +print CYC <[1]_desc, \"$t->[1]\", NULL, NULL); + if (tp < 0) abort (); + dds_entity_t rd = dds_create_reader (dp, tp, NULL, NULL); + if (rd < 0) abort (); + dds_entity_t wr = dds_create_writer (dp, tp, NULL, NULL); + if (wr < 0) abort (); +EOF + ; + print CYC geninit ($t); + print CYC <[1]) < 0) abort (); + void *msg = NULL; + dds_sample_info_t info; + if (dds_take (rd, &msg, &info, 1, 1) != 1) abort (); + const $t->[1] *b = msg; +EOF + ; + print CYC gencmp ($t); + print CYC <[1]_desc; + for (uint32_t i = 0; i < 1000; i++) { + for (size_t j = 0; j < sizeof (garbage); j++) + garbage[j] = (unsigned char) ddsrt_random (); + if (dds_stream_normalize (garbage, (uint32_t) sizeof (garbage), false, &ddd, false)) { + is.m_buffer = garbage; + is.m_size = 1000; + is.m_index = 0; + dds_stream_read_sample (&is, msg, &ddd); + deser_garbage++; + } + } + sd_serializer serializer = sd_serializerXMLTypeinfoNew (base, 0); + sd_serializedData meta_data = sd_serializerFromString (serializer, $t->[1]_desc.m_meta); + if (sd_serializerDeserialize (serializer, meta_data) == NULL) abort (); + c_type type = c_resolve (base, "$t->[1]"); if (!type) abort (); + sd_serializedDataFree (meta_data); + sd_serializerFree (serializer); + struct sd_cdrInfo *ci = sd_cdrInfoNew (type); + if (sd_cdrCompile (ci) < 0) abort (); + DDS_copyCache cc = DDS_copyCacheNew ((c_metaObject) type); + struct DDS_srcInfo_s src = { .src = &v$t->[1], cc }; + void *samplecopy = c_new (type); + DDS_copyInStruct (base, &src, samplecopy); + struct sd_cdrSerdata *sd = sd_cdrSerializeBSwap (ci, samplecopy); + const void *blob; + uint32_t blobsz = sd_cdrSerdataBlob (&blob, sd); + /* hack alert: modifying read-only blob ...*/ + if (!dds_stream_normalize ((void *) blob, blobsz, true, &ddd, false)) abort (); + is.m_buffer = blob; + is.m_size = blobsz; + is.m_index = 0; + dds_stream_read_sample (&is, msg, &ddd); + sd_cdrSerdataFree (sd); + sd = sd_cdrSerialize (ci, samplecopy); + blobsz = sd_cdrSerdataBlob (&blob, sd); + if (!dds_stream_normalize ((void *) blob, blobsz, false, &ddd, false)) abort (); + for (uint32_t i = 1; i < blobsz && i <= 16; i++) { + if (dds_stream_normalize ((void *) blob, blobsz - i, false, &ddd, false)) abort (); + } + sd_cdrSerdataFree (sd); +EOF +; + print CYC gencmp ($t); + print CYC <[1] v$t->[1] = $res;\n"; +} + +sub gencmp { + my ($t) = @_; + my $res = gencmp1 ($t, "v$t->[1]", ""); + return $res; +} + +sub geninit1 { + my ($ind, $out, $t, $idxsuf) = @_; + if ($t->[0] =~ /^u([0-3])$/) { + return int (rand (10)); + } elsif ($t->[0] eq "u4") { + return "\"".("x"x(int (rand (8))))."\""; + } elsif ($t->[0] eq "seq") { + my $len = int (rand (10)); + my $bufref; + if ($len == 0) { + $bufref = "0"; + } else { + my $buf = "vb$t->[1]_$idxsuf"; + $bufref = "$buf"; + my $ctype = ($t->[2]->[0] =~ /^u(\d+)$/) ? $ctype[$1] : $t->[2]->[1]; + my $tmp = " $ctype $buf\[\] = {"; + for (1..$len) { + $tmp .= geninit1 ("$ind", $out, $t->[2], "${idxsuf}_$_"); + $tmp .= "," if $_ < $len; + } + $tmp .= "};\n"; + push @$out, $tmp; + } + return "{$len,$len,$bufref,0}"; + } elsif ($t->[0] eq "ary") { + my $len = $t->[3]; die unless $len > 0; + my $tmp = "{"; + for (1..$len) { + $tmp .= geninit1 ("$ind", $out, $t->[2], "${idxsuf}_$_"); + $tmp .= "," if $_ < $len; + } + $tmp .= "}"; + return $tmp; + } elsif ($t->[0] eq "str") { + my $tmp = "{"; + for (my $i = 2; $i < @$t; $i++) { + my ($name, $st) = @{$t->[$i]}; + $tmp .= geninit1 ("", $out, $st, "${idxsuf}_"); + $tmp .= "," if $i + 1 < @$t; + } + $tmp .= "}"; + return $tmp; + } elsif ($t->[0] eq "uni") { # uni name disctype hasdef case... + my $discval = int(rand(@$t - 3)); # -3 so we generate values outside label range as well + my $hasdef = $t->[3]; + my $case = (4 + $discval < @$t) ? $discval : $hasdef ? @$t-1 : 0; + $discval = ("'".chr ($discval + ord ("A"))."'") if $t->[2] eq "u0"; + # $case matches have a label or default; if no default generate an initializer for the + # first case to avoid compiler warnings + my ($name, $st) = @{$t->[4+$case]}; + my $tmp = "{$discval,{.$name="; + $tmp .= geninit1 ("", $out, $st, "${idxsuf}_"); + $tmp .= "}}"; + return $tmp; + } else { + die; + } +} + +sub gencmp1 { + my ($t, $toplevel, $path) = @_; + if ($t->[0] =~ /^u([0-3])$/) { + return " if ($toplevel.$path != b->$path) abort ();\n"; + } elsif ($t->[0] eq "u4") { + return " if (strcmp ($toplevel.$path, b->$path) != 0) abort ();\n"; + } elsif ($t->[0] eq "seq") { + my $idx = "i".length $path; + return ("if ($toplevel.$path._length != b->$path._length) abort ();\n" . + "for (uint32_t $idx = 0; $idx < $toplevel.$path._length; $idx++) {\n" . + gencmp1 ($t->[2], $toplevel, "$path._buffer[$idx]") . + "}\n"); + } elsif ($t->[0] eq "ary") { + my $len = $t->[3]; die unless $len > 0; + my $idx = "i".length $path; + return ("for (uint32_t $idx = 0; $idx < $len; $idx++) {\n" . + gencmp1 ($t->[2], $toplevel, "$path\[$idx]") . + "}\n"); + } elsif ($t->[0] eq "str") { + my $sep = length $path == 0 ? "" : "."; + my $tmp = ""; + for (my $i = 2; $i < @$t; $i++) { + my ($name, $st) = @{$t->[$i]}; + $tmp .= gencmp1 ($st, $toplevel, "$path$sep$name"); + } + return $tmp; + } elsif ($t->[0] eq "uni") { # uni name disctype hasdef case... + my $tmp = "if ($toplevel.$path._d != b->$path._d) abort ();\n"; + my $hasdef = $t->[3]; + $tmp .= "switch ($toplevel.$path._d) {\n"; + for (my $i = 4; $i < @$t; $i++) { + my ($name, $st) = @{$t->[$i]}; + my $discval = $i - 4; + $discval = "'".chr ($discval + ord ("A"))."'" if $t->[2] eq "u0"; + $tmp .= ($i == @$t && $hasdef) ? " default:\n" : " case $discval:\n"; + $tmp .= gencmp1 ($st, $toplevel, "$path._u.$name"); + $tmp .= "break;\n"; + } + $tmp .= "}\n"; + return $tmp; + } else { + die; + } +} + +sub genidltd { + my ($t) = @_; + my @out = (); + my $res = genidl1td ("", \@out, $t); + return (join "", @out) . $res . "#pragma keylist $t->[1]\n//------------\n"; +}; + +sub genidl1 { + my ($ind, $out, $name, $t) = @_; + my $res = ""; + if ($t->[0] =~ /^u(\d+)$/) { + $res = "${ind}$idltype[$1] $name;\n"; + } elsif ($t->[0] eq "seq") { + push @$out, genidl1td ("", $out, $t); + $res = "${ind}$t->[1] $name;\n"; + } elsif ($t->[0] eq "ary") { + if ($t->[2]->[0] =~ /^u(\d+)$/) { + $res = "${ind}$idltype[$1] ${name}[$t->[3]];\n"; + } else { + push @$out, genidl1td ("", $out, $t->[2]); + $res = "${ind}$t->[2]->[1] ${name}[$t->[3]];\n"; + } + } elsif ($t->[0] eq "str") { + push @$out, genidl1td ("", $out, $t); + $res = "${ind}$t->[1] $name;\n"; + } elsif ($t->[0] eq "uni") { + push @$out, genidl1td ("", $out, $t); + $res = "${ind}$t->[1] $name;\n"; + } else { + die; + } + return $res; +} + +sub genidl1td { + my ($ind, $out, $t) = @_; + if ($t->[0] eq "seq") { + if ($t->[2]->[0] =~ /^u(\d+)$/) { + return "${ind}typedef sequence<$idltype[$1]> $t->[1];\n"; + } else { + push @$out, genidl1td ("", $out, $t->[2]); + return "${ind}typedef sequence<$t->[2]->[1]> $t->[1];\n"; + } + } elsif ($t->[0] eq "ary") { + if ($t->[2]->[0] =~ /^u(\d+)$/) { + return "${ind}typedef ${idltype[$1]} $t->[1]"."[$t->[3]];\n"; + } else { + push @$out, genidl1td ("", $out, $t->[2]); + return "${ind}typedef $t->[2]->[1] $t->[1]"."[$t->[3]];\n"; + } + } elsif ($t->[0] eq "str") { + my $res = "struct $t->[1] {\n"; + for (my $i = 2; $i < @$t; $i++) { + $res .= genidl1 ($ind." ", $out, @{$t->[$i]}); + } + $res .= "};\n"; + return $res; + } elsif ($t->[0] eq "uni") { + my $hasdef = $t->[3]; + die unless $t->[2] =~ /^u([0-2])$/; + my $res = "${ind}union $t->[1] switch ($idltype_unidisc[$1]) {\n"; + for (my $i = 4; $i < @$t; $i++) { + my $discval = $i - 4; + $discval = "'".(chr ($discval + ord ("A")))."'" if $t->[2] eq "u0"; + $res .= ($i == @$t && $hasdef) ? "$ind default: " : "$ind case $discval: "; + $res .= genidl1 ($ind." ", $out, @{$t->[$i]}); + } + $res .= "};\n"; + return $res; + } else { + die; + } +}; + +sub genu0 { return ["u0"]; } +sub genu1 { return ["u1"]; } +sub genu2 { return ["u2"]; } +sub genu3 { return ["u3"]; } +sub genu4 { return ["u4"]; } +sub genseq { return ["seq", nextident (), gentype ($_[0] + 1, @probs)]; } +sub genary { return ["ary", nextident (), gentype ($_[0] + 1, @noaryprobs), 1 + int (rand (4))]; } +sub genstr { + my @ts = ("str", nextident ()); + my $n = 1 + int (rand (4)); + push @ts, [ nextident (), gentype ($_[0] + 1, @probs) ] while $n--; + return \@ts; +} +sub genuni { + my @ts = ("uni", nextident (), "u".(int (rand (2))), int (rand (1))); # uni name disctype hasdef case... + my $ncases = 1 + int (rand (4)); + push @ts, [ nextident (), gentype ($_[0] + 1, @unicaseprobs) ] while $ncases--; + return \@ts; +} + +sub gentype { + my $t = choosetype (@_); + my $f = "gen$t"; + return &$f (@_); +} + +sub choosetype { + my ($lev, @probs) = @_; + my $r = rand ($_[0] == 4 ? $probs[3] : $probs[$#probs]); + my $i; + for ($i = 0; $i < $#probs; $i++) { + last if $r < $probs[$i]; + } + return $types[$i]; +} + +sub nextident { + return $nextident++; +} diff --git a/src/core/xtests/initsampledeliv/CMakeLists.txt b/src/core/xtests/initsampledeliv/CMakeLists.txt new file mode 100644 index 0000000..e4804fa --- /dev/null +++ b/src/core/xtests/initsampledeliv/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.5) + +idlc_generate(InitSampleDeliv_lib InitSampleDelivData.idl) + +add_executable(InitSampleDelivPub publisher.c) +add_executable(InitSampleDelivSub subscriber.c) + +target_link_libraries(InitSampleDelivPub InitSampleDeliv_lib ddsc) +target_link_libraries(InitSampleDelivSub InitSampleDeliv_lib ddsc) diff --git a/src/core/xtests/initsampledeliv/InitSampleDelivData.idl b/src/core/xtests/initsampledeliv/InitSampleDelivData.idl new file mode 100644 index 0000000..1064232 --- /dev/null +++ b/src/core/xtests/initsampledeliv/InitSampleDelivData.idl @@ -0,0 +1,19 @@ +// Copyright(c) 2019 ADLINK Technology Limited and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + +struct Msg { + long keyval; + long seq; + long tldepth; + long final_seq; + long seq_at_match[2]; +}; + +#pragma keylist Msg keyval diff --git a/src/core/xtests/initsampledeliv/publisher.c b/src/core/xtests/initsampledeliv/publisher.c new file mode 100644 index 0000000..a690c16 --- /dev/null +++ b/src/core/xtests/initsampledeliv/publisher.c @@ -0,0 +1,163 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/dds.h" +#include "dds/ddsrt/atomics.h" +#include "InitSampleDelivData.h" +#include +#include +#include + +static void oops (const char *file, int line) +{ + fflush (stdout); + fprintf (stderr, "%s:%d\n", file, line); + abort (); +} + +#define oops() oops(__FILE__, __LINE__) + +static void on_pub_matched (dds_entity_t wr, const dds_publication_matched_status_t st, void *varg) +{ + ddsrt_atomic_uint32_t *new_readers = varg; + dds_sample_info_t info; + void *raw = NULL; + dds_entity_t rd; + printf ("pubmatched\n"); + if ((rd = dds_create_reader (dds_get_participant (wr), DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, NULL, NULL)) < 0) + oops (); + if (dds_read_instance (rd, &raw, &info, 1, 1, st.last_subscription_handle) != 1) + oops (); + const dds_builtintopic_endpoint_t *sample = raw; + /* in our test the user data must be present */ + void *ud; + size_t udsz; + if (!dds_qget_userdata (sample->qos, &ud, &udsz)) + oops (); + int rdid = atoi (ud); + if (rdid < 0 || rdid > 31) + oops (); + printf ("pubmatched: %d\n", rdid); + fflush (stdout); + ddsrt_atomic_or32 (new_readers, UINT32_C (1) << rdid); + dds_free (ud); + dds_return_loan (rd, &raw, 1); +} + +static uint32_t get_publication_matched_count (dds_entity_t wr) +{ + dds_publication_matched_status_t status; + if (dds_get_publication_matched_status (wr, &status) < 0) + oops (); + return status.current_count; +} + +int main (int argc, char ** argv) +{ + dds_entity_t ppant; + dds_entity_t tp; + dds_entity_t wr; + dds_qos_t *qos; + ddsrt_atomic_uint32_t newreaders = DDSRT_ATOMIC_UINT32_INIT (0); + int opt; + bool flag_prewrite = false; + bool flag_translocal = false; + const int32_t tlhist = 10; + + while ((opt = getopt (argc, argv, "tp")) != EOF) + { + switch (opt) + { + case 't': + flag_translocal = true; + break; + case 'p': + flag_prewrite = true; + break; + default: + fprintf (stderr, "usage error: see source code\n"); + exit (2); + } + } + + if ((ppant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL)) < 0) + oops (); + + qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10)); + dds_qset_durability (qos, DDS_DURABILITY_TRANSIENT_LOCAL); + if ((tp = dds_create_topic (ppant, &Msg_desc, "Msg", qos, NULL)) < 0) + oops (); + + /* Writer has overrides for history, durability */ + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dds_qset_durability (qos, flag_translocal ? DDS_DURABILITY_TRANSIENT_LOCAL : DDS_DURABILITY_VOLATILE); + dds_qset_durability_service (qos, 0, DDS_HISTORY_KEEP_LAST, tlhist, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED); + + dds_listener_t *list = dds_create_listener (&newreaders); + dds_lset_publication_matched (list, on_pub_matched); + if ((wr = dds_create_writer (ppant, tp, qos, list)) < 0) + oops (); + dds_delete_listener (list); + dds_delete_qos (qos); + + Msg sample = { + .keyval = 0, + .seq = 1, + .tldepth = tlhist, + .final_seq = 30, + .seq_at_match = { 0, 0 } + }; + dds_time_t tlast = 0, tnewrd = 0; + while (sample.seq <= sample.final_seq) + { + uint32_t newrd = ddsrt_atomic_and32_ov (&newreaders, 0); + for (uint32_t i = 0; i < 32; i++) + { + if (newrd & (UINT32_C (1) << i)) + { + if (i >= (uint32_t) (sizeof (sample.seq_at_match) / sizeof (sample.seq_at_match[0]))) + oops (); + if (sample.seq_at_match[i] != 0) + oops (); + sample.seq_at_match[i] = sample.seq; + tnewrd = dds_time (); + printf ("%d.%09d newreader %d: start seq %d\n", (int) (tnewrd / DDS_NSECS_IN_SEC), (int) (tnewrd % DDS_NSECS_IN_SEC), (int) i, (int) sample.seq_at_match[i]); + fflush (stdout); + } + } + + if (get_publication_matched_count (wr) || (flag_prewrite && sample.seq <= tlhist + 1)) + { + dds_time_t tnow = dds_time (); + if (tnow - tlast > DDS_MSECS (100) || newrd) + { + if (dds_write (wr, &sample) < 0) + oops (); + sample.seq++; + tlast = tnow; + if (sample.seq > sample.final_seq) + { + tnow = dds_time (); + printf ("%d.%09d done writing\n", (int) (tnow / DDS_NSECS_IN_SEC), (int) (tnow % DDS_NSECS_IN_SEC)); + fflush (stdout); + } + } + } + + dds_sleepfor (DDS_MSECS (1)); + } + + dds_sleepfor (DDS_MSECS (100)); + dds_wait_for_acks (wr, DDS_INFINITY); + dds_delete (ppant); + return 0; +} diff --git a/src/core/xtests/initsampledeliv/runtest b/src/core/xtests/initsampledeliv/runtest new file mode 100644 index 0000000..9ba03b8 --- /dev/null +++ b/src/core/xtests/initsampledeliv/runtest @@ -0,0 +1,46 @@ +#!/bin/bash +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +ok=true +for sd in "" "-d1" "-d12" ; do + for st in "" "-t" ; do + for sT in "" "-T" ; do + if [ "$st" = "-t" -o "$sT" = "-T" ] ; then + maybeV=false + else + maybeV=true + fi + for sw in "" "-w" ; do + for pt in "" "-t" ; do + for pp in "" "-p" ; do + if [ "$sT" = "" -a "$sd" != "" -a \( "$pt" = "-t" -o $maybeV = true \) ] ; then + if $ok ; then + echo "bin/InitSampleDelivSub $sw $sd $st $sT & bin/InitSampleDelivPub $pt $pp" + bin/InitSampleDelivSub $sw $sd $st $sT & spid=$! + bin/InitSampleDelivPub $pt $pp + wait $spid || ok=false + fi + if $ok ; then + echo "bin/InitSampleDelivPub $pt $pp & sleep 2 ; bin/InitSampleDelivSub $sw $sd $st $sT " + bin/InitSampleDelivPub $pt $pp & ppid=$! + sleep 2 + bin/InitSampleDelivSub $sw $sd $st $sT & spid=$! + wait $spid || ok=false + wait + fi + fi + done + done + done + done + done +done diff --git a/src/core/xtests/initsampledeliv/subscriber.c b/src/core/xtests/initsampledeliv/subscriber.c new file mode 100644 index 0000000..1cb6ad6 --- /dev/null +++ b/src/core/xtests/initsampledeliv/subscriber.c @@ -0,0 +1,198 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/dds.h" +#include "InitSampleDelivData.h" +#include +#include +#include +#include +#include + +static void oops (const char *file, int line) +{ + fflush (stdout); + fprintf (stderr, "%s:%d\n", file, line); + abort (); +} + +#define oops() oops(__FILE__, __LINE__) + +static void wait_for_writer (dds_entity_t ppant) +{ + dds_entity_t rd; + dds_sample_info_t info; + void *raw = NULL; + int32_t n; + if ((rd = dds_create_reader (ppant, DDS_BUILTIN_TOPIC_DCPSPUBLICATION, NULL, NULL)) < 0) + oops (); + bool done = false; + do { + dds_sleepfor (DDS_MSECS (100)); + while ((n = dds_take (rd, &raw, &info, 1, 1)) == 1) + { + const dds_builtintopic_endpoint_t *sample = raw; + if (strcmp (sample->topic_name, "Msg") == 0) + done = true; + dds_return_loan (rd, &raw, n); + } + if (n < 0) oops (); + } while (!done); + dds_delete (rd); +} + +static uint32_t get_subscription_matched_count (dds_entity_t rd) +{ + dds_subscription_matched_status_t status; + if (dds_get_subscription_matched_status (rd, &status) < 0) + oops (); + return status.current_count; +} + +int main (int argc, char ** argv) +{ + dds_entity_t ppant; + dds_entity_t tp; + dds_entity_t rd[2] = { 0, 0 }; + dds_qos_t *qos; + int opt; + bool flag_wait = false; + bool flag_translocal[sizeof (rd) / sizeof (rd[0])] = { false }; + int flag_create_2nd_rd = -1; + + while ((opt = getopt (argc, argv, "d:tTw")) != EOF) + { + switch (opt) + { + case 'd': + flag_create_2nd_rd = atoi (optarg); + break; + case 't': + flag_translocal[0] = true; + break; + case 'T': + flag_translocal[1] = true; + break; + case 'w': + flag_wait = true; + break; + default: + fprintf (stderr, "usage error: see source code\n"); + exit (2); + } + } + + if ((ppant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL)) < 0) + oops (); + + qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (10)); + dds_qset_durability (qos, DDS_DURABILITY_TRANSIENT_LOCAL); + if ((tp = dds_create_topic (ppant, &Msg_desc, "Msg", qos, NULL)) < 0) + oops (); + + if (flag_wait) + { + printf ("waiting for writer ...\n"); + fflush (stdout); + wait_for_writer (ppant); + printf ("writer seen; giving it some time to discover us and publish data ...\n"); + fflush (stdout); + dds_sleepfor (DDS_SECS (1)); + printf ("continuing ...\n"); + fflush (stdout); + } + + /* Reader has overrides for history, durability */ + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dds_qset_durability (qos, flag_translocal[0] ? DDS_DURABILITY_TRANSIENT_LOCAL : DDS_DURABILITY_VOLATILE); + dds_qset_userdata (qos, "0", 1); + if ((rd[0] = dds_create_reader (ppant, tp, qos, NULL)) < 0) + oops (); + + dds_qset_durability (qos, flag_translocal[1] ? DDS_DURABILITY_TRANSIENT_LOCAL : DDS_DURABILITY_VOLATILE); + dds_qset_userdata (qos, "1", 1); + + int32_t firstmsg[2] = { 0 }; + int32_t prevmsg[2] = { 0 }; + int32_t seqatmatch[2] = { 0 }; + int32_t tldepth = 0; + int32_t endmsg = 0; + while (prevmsg[0] == 0 || get_subscription_matched_count (rd[0]) > 0) + { + void *raw = NULL; + dds_sample_info_t info; + int32_t n; + for (int i = 0; i < 2 && rd[i]; i++) + { + if ((n = dds_take (rd[i], &raw, &info, 1, 1)) < 0) + oops (); + else if (n > 0 && info.valid_data) + { + const Msg *msg = raw; + if (prevmsg[i] == 0) + { + /* have to postpone first seq# check for transient-local data because the limit + t-l history means the first sample we read may have an arbitrary sequence + that antedated the matching */ + printf ("reader %d: first seq %d\n", i, (int) msg->seq); + fflush (stdout); + firstmsg[i] = msg->seq; + } + else if (msg->seq != prevmsg[i] + 1) + { + printf ("reader %d: received %d, previous %d\n", i, (int) msg->seq, (int) prevmsg[i]); + oops (); + } + prevmsg[i] = msg->seq; + endmsg = msg->final_seq; + tldepth = msg->tldepth; + if (seqatmatch[i] == 0) + seqatmatch[i] = msg->seq_at_match[i]; + dds_return_loan (rd[i], &raw, n); + } + } + if (rd[1] == 0 && prevmsg[0] == flag_create_2nd_rd) + { + if ((rd[1] = dds_create_reader (ppant, tp, qos, NULL)) < 0) + oops (); + } + dds_sleepfor (DDS_MSECS (10)); + } + if (tldepth == 0 || endmsg == 0) + oops (); + for (int i = 0; i < 2; i++) + { + if (rd[i] == 0) + continue; + if (prevmsg[i] != endmsg) + oops (); + int32_t refseq; + if (!flag_translocal[i]) + refseq = seqatmatch[i]; + else if (seqatmatch[i] <= tldepth) + refseq = 1; + else + refseq = seqatmatch[i] - tldepth; + if (flag_translocal[i] ? (firstmsg[i] > refseq + 1) : firstmsg[i] > refseq) + { + /* allow the rare cases where an additional sample was received for volatile data + (for t-l data, the publisher waits to give so the subscriber can get the data + in time */ + printf ("reader %d: first seq %d but refseq %d\n", i, (int) firstmsg[i], refseq); + oops (); + } + } + + dds_delete_qos (qos); + dds_delete (ppant); + return 0; +} diff --git a/src/core/xtests/rhc_torture/CMakeLists.txt b/src/core/xtests/rhc_torture/CMakeLists.txt new file mode 100644 index 0000000..4aa3a5f --- /dev/null +++ b/src/core/xtests/rhc_torture/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +idlc_generate(RhcTypes RhcTypes.idl) + +add_executable(rhc_torture rhc_torture.c) + +target_include_directories( + rhc_torture PRIVATE + "$" + "$") + +target_link_libraries(rhc_torture RhcTypes ddsc) + +add_test( + NAME rhc_torture + COMMAND rhc_torture 314159265 0 5000 0) +set_property(TEST rhc_torture PROPERTY TIMEOUT 20) diff --git a/src/core/xtests/RhcTypes.idl b/src/core/xtests/rhc_torture/RhcTypes.idl similarity index 100% rename from src/core/xtests/RhcTypes.idl rename to src/core/xtests/rhc_torture/RhcTypes.idl diff --git a/src/core/xtests/rhc_torture.c b/src/core/xtests/rhc_torture/rhc_torture.c similarity index 86% rename from src/core/xtests/rhc_torture.c rename to src/core/xtests/rhc_torture/rhc_torture.c index 245d057..5dba7b4 100644 --- a/src/core/xtests/rhc_torture.c +++ b/src/core/xtests/rhc_torture/rhc_torture.c @@ -31,6 +31,7 @@ #include "dds/ddsi/ddsi_serdata.h" #include "dds__topic.h" #include "dds__rhc.h" +#include "dds__rhc_default.h" #include "dds/ddsi/ddsi_iid.h" #include "RhcTypes.h" @@ -103,13 +104,14 @@ static struct ddsi_serdata *mkkeysample (int32_t keyval, unsigned statusinfo) return sd; } -static uint64_t store (struct rhc *rhc, struct proxy_writer *wr, struct ddsi_serdata *sd, bool print) +static uint64_t store (struct ddsi_tkmap *tkmap, struct dds_rhc *rhc, struct proxy_writer *wr, struct ddsi_serdata *sd, bool print) { /* beware: unrefs sd */ struct ddsi_tkmap_instance *tk; struct proxy_writer_info pwr_info; - thread_state_awake (lookup_thread_state ()); - tk = ddsi_tkmap_lookup_instance_ref(sd); + /* single-domain application ... so domain won't change */ + thread_state_awake_domain_ok (lookup_thread_state ()); + tk = ddsi_tkmap_lookup_instance_ref (tkmap, sd); uint64_t iid = tk->m_iid; if (print) { @@ -131,23 +133,23 @@ static uint64_t store (struct rhc *rhc, struct proxy_writer *wr, struct ddsi_ser pwr_info.iid = wr->e.iid; pwr_info.ownership_strength = wr->c.xqos->ownership_strength.value; dds_rhc_store (rhc, &pwr_info, sd, tk); - ddsi_tkmap_instance_unref (tk); + ddsi_tkmap_instance_unref (tkmap, tk); thread_state_asleep (lookup_thread_state ()); ddsi_serdata_unref (sd); return iid; } -static struct proxy_writer *mkwr (bool auto_dispose) +static struct proxy_writer *mkwr (const struct q_globals *gv, bool auto_dispose) { struct proxy_writer *pwr; - struct nn_xqos *xqos; + struct dds_qos *xqos; uint64_t wr_iid; pwr = ddsrt_malloc (sizeof (*pwr)); xqos = ddsrt_malloc (sizeof (*xqos)); wr_iid = ddsi_iid_gen (); memset (pwr, 0, sizeof (*pwr)); nn_xqos_init_empty (xqos); - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (xqos, &gv->default_xqos_wr, ~(uint64_t)0); xqos->ownership_strength.value = 0; xqos->writer_data_lifecycle.autodispose_unregistered_instances = auto_dispose; pwr->e.iid = wr_iid; @@ -161,26 +163,26 @@ static void fwr (struct proxy_writer *wr) free (wr); } -static struct rhc *mkrhc (dds_reader *rd, nn_history_kind_t hk, int32_t hdepth, nn_destination_order_kind_t dok) +static struct dds_rhc *mkrhc (struct q_globals *gv, dds_reader *rd, dds_history_kind_t hk, int32_t hdepth, dds_destination_order_kind_t dok) { - struct rhc *rhc; - nn_xqos_t rqos; + struct dds_rhc *rhc; + dds_qos_t rqos; nn_xqos_init_empty (&rqos); rqos.present |= QP_HISTORY | QP_DESTINATION_ORDER; rqos.history.kind = hk; rqos.history.depth = hdepth; rqos.destination_order.kind = dok; - nn_xqos_mergein_missing (&rqos, &gv.default_xqos_rd); - thread_state_awake (lookup_thread_state ()); - rhc = dds_rhc_new (rd, mdtopic); + nn_xqos_mergein_missing (&rqos, &gv->default_xqos_rd, ~(uint64_t)0); + thread_state_awake_domain_ok (lookup_thread_state ()); + rhc = dds_rhc_default_new_xchecks (rd, gv, mdtopic, true); dds_rhc_set_qos(rhc, &rqos); thread_state_asleep (lookup_thread_state ()); return rhc; } -static void frhc (struct rhc *rhc) +static void frhc (struct dds_rhc *rhc) { - thread_state_awake (lookup_thread_state ()); + thread_state_awake_domain_ok (lookup_thread_state ()); dds_rhc_free (rhc); thread_state_asleep (lookup_thread_state ()); } @@ -281,14 +283,14 @@ static void print_seq (int n, const dds_sample_info_t *iseq, const RhcTypes_T *m } } -static void rdtkcond (struct rhc *rhc, dds_readcond *cond, const struct check *chk, bool print, int max, const char *opname, int (*op) (struct rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond), uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) +static void rdtkcond (struct dds_rhc *rhc, dds_readcond *cond, const struct check *chk, bool print, int max, const char *opname, int (*op) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond), uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) { int cnt; if (print) printf ("%s:\n", opname); - thread_state_awake (lookup_thread_state ()); + thread_state_awake_domain_ok (lookup_thread_state ()); cnt = op (rhc, true, rres_ptrs, rres_iseq, (max <= 0) ? (uint32_t) (sizeof (rres_iseq) / sizeof (rres_iseq[0])) : (uint32_t) max, cond ? NO_STATE_MASK_SET : (DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE), 0, cond); thread_state_asleep (lookup_thread_state ()); if (max > 0 && cnt > max) { @@ -379,12 +381,12 @@ static void rdtkcond (struct rhc *rhc, dds_readcond *cond, const struct check *c } } -static void rdall (struct rhc *rhc, const struct check *chk, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) +static void rdall (struct dds_rhc *rhc, const struct check *chk, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) { rdtkcond (rhc, NULL, chk, print, 0, "READ ALL", dds_rhc_read, states_seen); } -static void tkall (struct rhc *rhc, const struct check *chk, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) +static void tkall (struct dds_rhc *rhc, const struct check *chk, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) { rdtkcond (rhc, NULL, chk, print, 0, "TAKE ALL", dds_rhc_take, states_seen); } @@ -440,7 +442,7 @@ static void print_condmask (char *buf, size_t bufsz, const dds_readcond *cond) snprintf (buf + pos, bufsz - pos, "]"); } -static void rdcond (struct rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) +static void rdcond (struct dds_rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) { char buf[100]; int pos; @@ -449,7 +451,7 @@ static void rdcond (struct rhc *rhc, dds_readcond *cond, const struct check *chk rdtkcond (rhc, cond, chk, print, max, buf, dds_rhc_read, states_seen); } -static void tkcond (struct rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) +static void tkcond (struct dds_rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2]) { char buf[100]; int pos; @@ -467,10 +469,10 @@ static void wait_gc_cycle_impl (struct gcreq *gcreq) gcreq_free (gcreq); } -static void wait_gc_cycle (void) +static void wait_gc_cycle (struct gcreq_queue *gcreq_queue) { /* only single-threaded for now */ - struct gcreq *gcreq = gcreq_new (gv.gcreq_queue, wait_gc_cycle_impl); + struct gcreq *gcreq = gcreq_new (gcreq_queue, wait_gc_cycle_impl); #ifndef NDEBUG ddsrt_mutex_lock (&wait_gc_cycle_lock); assert (wait_gc_cycle_trig == 0); @@ -530,6 +532,17 @@ static dds_entity_t readcond_wrapper (dds_entity_t reader, uint32_t mask, dds_qu return dds_create_readcondition (reader, mask); } +static struct q_globals *get_gv (dds_entity_t e) +{ + struct q_globals *gv; + dds_entity *x; + if (dds_entity_pin (e, &x) < 0) + abort (); + gv = &x->m_domain->gv; + dds_entity_unpin (x); + return gv; +} + static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, dds_entity_t (*create_cond) (dds_entity_t reader, uint32_t mask, dds_querycondition_filter_fn filter), dds_querycondition_filter_fn filter0, dds_querycondition_filter_fn filter1, bool print) { dds_qos_t *qos = dds_create_qos (); @@ -539,17 +552,20 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, dds_entity_t rd[] = { dds_create_reader (pp, tp, qos, NULL), dds_create_reader (pp, tp, qos, NULL) }; const size_t nrd = sizeof (rd) / sizeof (rd[0]); dds_delete_qos (qos); - struct rhc *rhc[sizeof (rd) / sizeof (rd[0])]; + struct dds_rhc *rhc[sizeof (rd) / sizeof (rd[0])]; for (size_t i = 0; i < sizeof (rd) / sizeof (rd[0]); i++) { struct dds_entity *x; if (dds_entity_lock (rd[i], DDS_KIND_READER, &x) < 0) abort (); dds_reader *rdp = (dds_reader *) x; - rhc[i] = rdp->m_rd->rhc; + rhc[i] = rdp->m_rhc; dds_entity_unlock (x); } - struct proxy_writer *wr[] = { mkwr (0), mkwr (1), mkwr (1) }; + + const struct q_globals *gv = get_gv (pp); + struct ddsi_tkmap *tkmap = gv->m_tkmap; + struct proxy_writer *wr[] = { mkwr (gv, 0), mkwr (gv, 1), mkwr (gv, 1) }; static const uint32_t stab[] = { DDS_READ_SAMPLE_STATE, DDS_NOT_READ_SAMPLE_STATE, @@ -699,42 +715,42 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, case 0: { /* wr */ struct ddsi_serdata *s = mksample (keyval, 0); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } case 1: { /* wr disp */ struct ddsi_serdata *s = mksample (keyval, NN_STATUSINFO_DISPOSE); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } case 2: { /* disp */ struct ddsi_serdata *s = mkkeysample (keyval, NN_STATUSINFO_DISPOSE); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } case 3: { /* unreg */ struct ddsi_serdata *s = mkkeysample (keyval, NN_STATUSINFO_UNREGISTER); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } case 4: { /* disp unreg */ struct ddsi_serdata *s = mkkeysample (keyval, NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } case 5: { /* wr disp unreg */ struct ddsi_serdata *s = mksample (keyval, NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER); for (size_t k = 0; k < nrd; k++) - store (rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); + store (tkmap, rhc[k], wr[which], ddsi_serdata_ref (s), print && k == 0); ddsi_serdata_unref (s); break; } @@ -765,7 +781,7 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, break; } case 11: { - thread_state_awake (lookup_thread_state ()); + thread_state_awake_domain_ok (lookup_thread_state ()); struct proxy_writer_info wr_info; wr_info.auto_dispose = wr[which]->c.xqos->writer_data_lifecycle.autodispose_unregistered_instances; wr_info.guid = wr[which]->e.guid; @@ -779,7 +795,7 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, } if ((i % 200) == 0) - wait_gc_cycle (); + wait_gc_cycle (gv->gcreq_queue); } for (size_t oper = 0; oper < sizeof (opcount) / sizeof (opcount[0]); oper++) @@ -837,6 +853,7 @@ int main (int argc, char **argv) tref_dds = dds_time(); mainthread = lookup_thread_state (); + assert (ddsrt_atomic_ldvoidp (&mainthread->gv) != NULL); { struct dds_entity *x; if (dds_entity_lock(tp, DDS_KIND_TOPIC, &x) < 0) abort(); @@ -846,20 +863,22 @@ int main (int argc, char **argv) if (0 >= first) { + struct q_globals *gv = get_gv (pp); + struct ddsi_tkmap *tkmap = gv->m_tkmap; if (print) printf ("************* 0 *************\n"); - struct rhc *rhc = mkrhc (NULL, NN_KEEP_LAST_HISTORY_QOS, 1, NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS); - struct proxy_writer *wr0 = mkwr (1); + struct dds_rhc *rhc = mkrhc (gv, NULL, DDS_HISTORY_KEEP_LAST, 1, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); + struct proxy_writer *wr0 = mkwr (gv, 1); uint64_t iid0, iid1, iid_t; - iid0 = store (rhc, wr0, mksample (0, 0), print); - iid1 = store (rhc, wr0, mksample (1, NN_STATUSINFO_DISPOSE), print); + iid0 = store (tkmap, rhc, wr0, mksample (0, 0), print); + iid1 = store (tkmap, rhc, wr0, mksample (1, NN_STATUSINFO_DISPOSE), print); const struct check c0[] = { { "NNA", iid0, wr0->e.iid, 0,0, 1, 0,1 }, { "NND", iid1, wr0->e.iid, 0,0, 1, 1,2 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }; rdall (rhc, c0, print, states_seen); - iid_t = store (rhc, wr0, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); + iid_t = store (tkmap, rhc, wr0, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); assert (iid_t == iid0); (void)iid0; (void)iid_t; @@ -870,7 +889,7 @@ int main (int argc, char **argv) { 0, 0, 0, 0, 0, 0, 0, 0 } }; rdall (rhc, c1, print, states_seen); - thread_state_awake (lookup_thread_state ()); + thread_state_awake_domain_ok (lookup_thread_state ()); struct proxy_writer_info wr0_info; wr0_info.auto_dispose = wr0->c.xqos->writer_data_lifecycle.autodispose_unregistered_instances; wr0_info.guid = wr0->e.guid; @@ -892,15 +911,17 @@ int main (int argc, char **argv) if (1 >= first) { + struct q_globals *gv = get_gv (pp); + struct ddsi_tkmap *tkmap = gv->m_tkmap; if (print) printf ("************* 1 *************\n"); - struct rhc *rhc = mkrhc (NULL, NN_KEEP_LAST_HISTORY_QOS, 4, NN_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS); - struct proxy_writer *wr[] = { mkwr (0), mkwr (0), mkwr (0) }; + struct dds_rhc *rhc = mkrhc (gv, NULL, DDS_HISTORY_KEEP_LAST, 4, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); + struct proxy_writer *wr[] = { mkwr (gv, 0), mkwr (gv, 0), mkwr (gv, 0) }; uint64_t iid0, iid_t; int nregs = 3, isreg[] = { 1, 1, 1 }; - iid0 = store (rhc, wr[0], mksample (0, 0), print); - iid_t = store (rhc, wr[1], mksample (0, 0), print); assert (iid0 == iid_t); - iid_t = store (rhc, wr[2], mksample (0, 0), print); assert (iid0 == iid_t); + iid0 = store (tkmap, rhc, wr[0], mksample (0, 0), print); + iid_t = store (tkmap, rhc, wr[1], mksample (0, 0), print); assert (iid0 == iid_t); + iid_t = store (tkmap, rhc, wr[2], mksample (0, 0), print); assert (iid0 == iid_t); (void)iid0; tkall (rhc, NULL, print, states_seen); for (int i = 0; i < 3*3 * 3*3 * 3*3 * 3*3; i++) @@ -912,17 +933,17 @@ int main (int argc, char **argv) switch (oper) { case 0: - iid_t = store (rhc, wr[which], mksample (0, 0), print); + iid_t = store (tkmap, rhc, wr[which], mksample (0, 0), print); if (!isreg[which]) { nregs++; isreg[which] = 1; } break; case 1: - iid_t = store (rhc, wr[which], mkkeysample (0, NN_STATUSINFO_DISPOSE), print); + iid_t = store (tkmap, rhc, wr[which], mkkeysample (0, NN_STATUSINFO_DISPOSE), print); if (!isreg[which]) { nregs++; isreg[which] = 1; } break; case 2: if (nregs > 1 || !isreg[which]) { - iid_t = store (rhc, wr[which], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); + iid_t = store (tkmap, rhc, wr[which], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); if (isreg[which]) { isreg[which] = 0; nregs--; } } break; @@ -931,13 +952,13 @@ int main (int argc, char **argv) } } tkall (rhc, 0, print, states_seen); - wait_gc_cycle (); + wait_gc_cycle (gv->gcreq_queue); assert (nregs > 0); for (int i = 0; i < 3; i++) { if (isreg[i]) { - iid_t = store (rhc, wr[i], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); + iid_t = store (tkmap, rhc, wr[i], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); assert (iid_t == iid0); isreg[i] = 0; nregs--; @@ -945,11 +966,11 @@ int main (int argc, char **argv) } assert (nregs == 0); tkall (rhc, 0, print, states_seen); - wait_gc_cycle (); - iid_t = store (rhc, wr[0], mksample (0, 0), print); + wait_gc_cycle (gv->gcreq_queue); + iid_t = store (tkmap, rhc, wr[0], mksample (0, 0), print); assert (iid_t != iid0); iid0 = iid_t; - iid_t = store (rhc, wr[0], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); + iid_t = store (tkmap, rhc, wr[0], mkkeysample (0, NN_STATUSINFO_UNREGISTER), print); assert (iid_t == iid0); frhc (rhc); @@ -982,6 +1003,7 @@ int main (int argc, char **argv) for (size_t i = 0; i < sizeof (rres_iseq) / sizeof (rres_iseq[0]); i++) RhcTypes_T_free (&rres_mseq[i], DDS_FREE_CONTENTS); + ddsi_sertopic_unref (mdtopic); dds_delete(pp); return 0; } diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt index 2b5171a..492136d 100644 --- a/src/ddsrt/CMakeLists.txt +++ b/src/ddsrt/CMakeLists.txt @@ -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 "$" @@ -69,7 +112,9 @@ list(APPEND headers "${include_path}/dds/ddsrt/dynlib.h" "${include_path}/dds/ddsrt/strtod.h" "${include_path}/dds/ddsrt/strtol.h" - "${include_path}/dds/ddsrt/types.h") + "${include_path}/dds/ddsrt/types.h" + "${include_path}/dds/ddsrt/countargs.h" + "${include_path}/dds/ddsrt/static_assert.h") list(APPEND sources "${source_path}/io.c" @@ -79,10 +124,10 @@ list(APPEND sources "${source_path}/strtol.c") list(APPEND headers - "${source_path}/dds/ddsrt/avl.h" - "${source_path}/dds/ddsrt/fibheap.h" - "${source_path}/dds/ddsrt/hopscotch.h" - "${source_path}/dds/ddsrt/thread_pool.h") + "${include_path}/dds/ddsrt/avl.h" + "${include_path}/dds/ddsrt/fibheap.h" + "${include_path}/dds/ddsrt/hopscotch.h" + "${include_path}/dds/ddsrt/thread_pool.h") list(APPEND sources "${source_path}/avl.c" @@ -103,13 +148,13 @@ list(APPEND sources # network stack. In order to mix-and-match various compilers, architectures, # operating systems, etc input from the build system is required. foreach(feature atomics cdtors environ heap ifaddrs random rusage - sockets string sync threads time md5 process dynlib) + sockets string sync threads time md5 process netstat dynlib) if(EXISTS "${include_path}/dds/ddsrt/${feature}.h") list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h") - file(GLOB + file(GLOB_RECURSE files CONFIGURE_DEPENDS - "${include_path}/dds/ddsrt/${feature}/**.h") + "${include_path}/dds/ddsrt/${feature}/*.h") list(APPEND headers ${files}) # Do not add any sources if a feature is not offered by the target. The @@ -125,10 +170,9 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage # feature does not exist in cmake, the feature is expected to be # implemented for all targets. string(TOUPPER "${feature}" feature_uc) + set(HAVE_${feature_uc} TRUE) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${feature}.c") - check_runtime_feature(cmake/${feature}.c) - else() - set(HAVE_${feature_uc} TRUE) + check_runtime_feature("cmake/${feature}.c") endif() if(HAVE_${feature_uc}) @@ -138,24 +182,32 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage list(APPEND sources "${source_path}/${feature}.c") endif() set(system_exists FALSE) - foreach(system ${system_name} posix) + + # Allow custom implementations for a feature. e.g. lwip as opposed to + # windows or posix. + set(_system_name "${system_name}") + if(NOT HAVE_${feature_uc} MATCHES "[tT][rR][uU][eE]") + set(_system_name "${HAVE_${feature_uc}}") + endif() + + foreach(system ${_system_name} posix) # Headers that must remain private but are required by other runtime # source files must be located in src//dds/ddsrt. if(IS_DIRECTORY "${source_path}/${feature}/include") - file(GLOB + file(GLOB_RECURSE files CONFIGURE_DEPENDS - "${source_path}/${feature}/include/**.h") - list(APPEND sources ${files}) + "${source_path}/${feature}/include/*.h") + list(APPEND headers ${files}) target_include_directories( ddsrt INTERFACE "$") endif() if(IS_DIRECTORY "${source_path}/${feature}/${system}") - file(GLOB + file(GLOB_RECURSE files CONFIGURE_DEPENDS - "${source_path}/${feature}/${system}/**.c") + "${source_path}/${feature}/${system}/*.c") list(APPEND sources ${files}) set(system_exists TRUE) endif() @@ -172,12 +224,16 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage endif() endforeach() -target_sources(ddsrt INTERFACE ${sources}) +target_sources(ddsrt INTERFACE ${sources} ${headers}) -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) -find_package(Threads REQUIRED) -target_link_libraries(ddsrt INTERFACE Threads::Threads) -target_link_libraries(ddsrt INTERFACE ${CMAKE_DL_LIBS}) +set(HAVE_MULTI_PROCESS ${HAVE_MULTI_PROCESS} PARENT_SCOPE) + +if(NOT WITH_FREERTOS) + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + find_package(Threads REQUIRED) + target_link_libraries(ddsrt INTERFACE Threads::Threads) + target_link_libraries(ddsrt INTERFACE ${CMAKE_DL_LIBS}) +endif() if(WIN32) target_link_libraries(ddsrt INTERFACE wsock32 ws2_32 iphlpapi bcrypt) diff --git a/src/core/ddsc/src/dds__err.h b/src/ddsrt/cmake/ifaddrs.c similarity index 65% rename from src/core/ddsc/src/dds__err.h rename to src/ddsrt/cmake/ifaddrs.c index a54be27..aaa61f5 100644 --- a/src/core/ddsc/src/dds__err.h +++ b/src/ddsrt/cmake/ifaddrs.c @@ -9,20 +9,15 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef _DDS_ERR_H_ -#define _DDS_ERR_H_ +#include "dds/ddsrt/ifaddrs.h" -#include - -#include "dds/ddsrt/retcode.h" - -#if defined (__cplusplus) -extern "C" { +#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 -#define DDS_ERRNO(err) (assert(err > DDS_RETCODE_OK), -(err)) - -#if defined (__cplusplus) -} -#endif -#endif diff --git a/src/ddsrt/cmake/netstat.c b/src/ddsrt/cmake/netstat.c new file mode 100644 index 0000000..a64b512 --- /dev/null +++ b/src/ddsrt/cmake/netstat.c @@ -0,0 +1,18 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/netstat.h" + +#if DDSRT_HAVE_NETSTAT +# error "cmake_HAVE_NETSTAT=true" +#else +# error "cmake_HAVE_NETSTAT=false" +#endif diff --git a/src/ddsrt/cmake/process.c b/src/ddsrt/cmake/process.c new file mode 100644 index 0000000..84e13f0 --- /dev/null +++ b/src/ddsrt/cmake/process.c @@ -0,0 +1,18 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/process.h" + +#if DDSRT_HAVE_MULTI_PROCESS +# error "cmake_HAVE_MULTI_PROCESS=true" +#else +# error "cmake_HAVE_MULTI_PROCESS=false" +#endif diff --git a/src/ddsrt/cmake/rusage.c b/src/ddsrt/cmake/rusage.c new file mode 100644 index 0000000..c9c6154 --- /dev/null +++ b/src/ddsrt/cmake/rusage.c @@ -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 + diff --git a/src/ddsrt/include/dds/ddsrt/atomics.h b/src/ddsrt/include/dds/ddsrt/atomics.h index 5acbed4..294085e 100644 --- a/src/ddsrt/include/dds/ddsrt/atomics.h +++ b/src/ddsrt/include/dds/ddsrt/atomics.h @@ -59,6 +59,34 @@ typedef ddsrt_atomic_uintptr_t ddsrt_atomic_voidp_t; #error "Atomic operations are not supported" #endif +#if ! DDSRT_HAVE_ATOMIC64 +/* 64-bit atomics are not supported by all hardware, but it would be a shame not to use them when + they are available. That necessitates an alternative implementation when they are not, either in + the form of a different implementation where it is used, or as an emulation using a mutex in + ddsrt. It seems that the places where they'd be used end up adding a mutex, so an emulation in + ddsrt while being able to check whether it is supported by hardware is a sensible approach. */ +DDS_EXPORT uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x); +DDS_EXPORT void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x); +DDS_EXPORT uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x); +DDS_EXPORT void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x); +DDS_EXPORT uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x); +DDS_EXPORT void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT void ddsrt_atomic_and64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_and64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_and64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT void ddsrt_atomic_or64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_or64_ov (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT uint64_t ddsrt_atomic_or64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); +DDS_EXPORT int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des); +#endif + +void ddsrt_atomics_init (void); +void ddsrt_atomics_fini (void); + #if defined(__cplusplus) } #endif diff --git a/src/ddsrt/include/dds/ddsrt/atomics/arm.h b/src/ddsrt/include/dds/ddsrt/atomics/arm.h index 863e483..c035883 100644 --- a/src/ddsrt/include/dds/ddsrt/atomics/arm.h +++ b/src/ddsrt/include/dds/ddsrt/atomics/arm.h @@ -85,6 +85,9 @@ inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff inline void ddsrt_atomic_add32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { (void) ddsrt_atomic_add32_nv (x, v); } +inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return ddsrt_atomic_add32_nv (x, v) - v; +} inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { (void) ddsrt_atomic_addptr_nv (x, v); } @@ -115,6 +118,9 @@ inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v /* INC */ +inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) { + return ddsrt_atomic_add32_nv (x, 1) - 1; +} inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) { return ddsrt_atomic_add32_nv (x, 1); } @@ -130,6 +136,9 @@ inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) { /* DEC */ +inline uint32_t ddsrt_atomic_dec32_ov (volatile ddsrt_atomic_uint32_t *x) { + return ddsrt_atomic_sub32_nv (x, 1) + 1; +} inline uint32_t ddsrt_atomic_dec32_nv (volatile ddsrt_atomic_uint32_t *x) { return ddsrt_atomic_sub32_nv (x, 1); } @@ -206,6 +215,12 @@ inline void ddsrt_atomic_orptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) inline void ddsrt_atomic_fence (void) { __asm volatile ("dmb" : : : "memory"); } +inline void ddsrt_atomic_fence_ldld (void) { + ddsrt_atomic_fence (); +} +inline void ddsrt_atomic_fence_stst (void) { + ddsrt_atomic_fence (); +} inline void ddsrt_atomic_fence_acq (void) { ddsrt_atomic_fence (); } diff --git a/src/ddsrt/include/dds/ddsrt/atomics/gcc.h b/src/ddsrt/include/dds/ddsrt/atomics/gcc.h index 4da5f29..8b6cc98 100644 --- a/src/ddsrt/include/dds/ddsrt/atomics/gcc.h +++ b/src/ddsrt/include/dds/ddsrt/atomics/gcc.h @@ -13,6 +13,7 @@ #define DDSRT_ATOMICS_GCC_H #include "dds/ddsrt/misc.h" +#include "dds/ddsrt/attributes.h" #if defined (__cplusplus) extern "C" { @@ -25,19 +26,51 @@ extern "C" { /* LD, ST */ -inline uint32_t ddsrt_atomic_ld32(const volatile ddsrt_atomic_uint32_t *x) { return x->v; } +ddsrt_attribute_no_sanitize (("thread")) +inline uint32_t ddsrt_atomic_ld32(const volatile ddsrt_atomic_uint32_t *x) +{ + return x->v; +} #if DDSRT_HAVE_ATOMIC64 -inline uint64_t ddsrt_atomic_ld64(const volatile ddsrt_atomic_uint64_t *x) { return x->v; } +ddsrt_attribute_no_sanitize (("thread")) +inline uint64_t ddsrt_atomic_ld64(const volatile ddsrt_atomic_uint64_t *x) +{ + return x->v; +} #endif -inline uintptr_t ddsrt_atomic_ldptr(const volatile ddsrt_atomic_uintptr_t *x) { return x->v; } -inline void *ddsrt_atomic_ldvoidp(const volatile ddsrt_atomic_voidp_t *x) { return (void *) ddsrt_atomic_ldptr(x); } +ddsrt_attribute_no_sanitize (("thread")) +inline uintptr_t ddsrt_atomic_ldptr(const volatile ddsrt_atomic_uintptr_t *x) +{ + return x->v; +} +ddsrt_attribute_no_sanitize (("thread")) +inline void *ddsrt_atomic_ldvoidp(const volatile ddsrt_atomic_voidp_t *x) +{ + return (void *) ddsrt_atomic_ldptr(x); +} -inline void ddsrt_atomic_st32(volatile ddsrt_atomic_uint32_t *x, uint32_t v) { x->v = v; } +ddsrt_attribute_no_sanitize (("thread")) +inline void ddsrt_atomic_st32(volatile ddsrt_atomic_uint32_t *x, uint32_t v) +{ + x->v = v; +} #if DDSRT_HAVE_ATOMIC64 -inline void ddsrt_atomic_st64(volatile ddsrt_atomic_uint64_t *x, uint64_t v) { x->v = v; } +ddsrt_attribute_no_sanitize (("thread")) +inline void ddsrt_atomic_st64(volatile ddsrt_atomic_uint64_t *x, uint64_t v) +{ + x->v = v; +} #endif -inline void ddsrt_atomic_stptr(volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { x->v = v; } -inline void ddsrt_atomic_stvoidp(volatile ddsrt_atomic_voidp_t *x, void *v) { ddsrt_atomic_stptr(x, (uintptr_t)v); } +ddsrt_attribute_no_sanitize (("thread")) +inline void ddsrt_atomic_stptr(volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) +{ + x->v = v; +} +ddsrt_attribute_no_sanitize (("thread")) +inline void ddsrt_atomic_stvoidp(volatile ddsrt_atomic_voidp_t *x, void *v) +{ + ddsrt_atomic_stptr(x, (uintptr_t)v); +} /* INC */ @@ -52,6 +85,9 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) { inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) { __sync_fetch_and_add (&x->v, 1); } +inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) { + return __sync_fetch_and_add (&x->v, 1); +} inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) { return __sync_add_and_fetch (&x->v, 1); } @@ -116,6 +152,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { ddsrt_atomic_addptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v); } +inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return __sync_fetch_and_add (&x->v, v); +} inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { return __sync_add_and_fetch (&x->v, v); } @@ -147,6 +186,9 @@ inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { ddsrt_atomic_subptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v); } +inline uint32_t ddsrt_atomic_sub32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return __sync_fetch_and_sub (&x->v, v); +} inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { return __sync_sub_and_fetch (&x->v, v); } @@ -284,11 +326,24 @@ inline void ddsrt_atomic_fence_ldld (void) { __sync_synchronize (); #endif } +inline void ddsrt_atomic_fence_stst (void) { +#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64) + __sync_synchronize (); +#endif +} inline void ddsrt_atomic_fence_acq (void) { +#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64) ddsrt_atomic_fence (); +#else + asm volatile ("" ::: "memory"); +#endif } inline void ddsrt_atomic_fence_rel (void) { +#if !(defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64) ddsrt_atomic_fence (); +#else + asm volatile ("" ::: "memory"); +#endif } #if defined (__cplusplus) diff --git a/src/ddsrt/include/dds/ddsrt/atomics/msvc.h b/src/ddsrt/include/dds/ddsrt/atomics/msvc.h index e4418e1..6a16241 100644 --- a/src/ddsrt/include/dds/ddsrt/atomics/msvc.h +++ b/src/ddsrt/include/dds/ddsrt/atomics/msvc.h @@ -74,6 +74,9 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) { inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) { DDSRT_ATOMIC_PTROP (InterlockedIncrement) (&x->v); } +inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) { + return InterlockedIncrement (&x->v) - 1; +} inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) { return InterlockedIncrement (&x->v); } @@ -138,6 +141,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { ddsrt_atomic_addptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v); } +inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return InterlockedExchangeAdd (&x->v, v); +} inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { return InterlockedExchangeAdd (&x->v, v) + v; } @@ -157,46 +163,52 @@ inline void *ddsrt_atomic_addvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff inline void ddsrt_atomic_sub32 (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) InterlockedExchangeAdd (&x->v, -v); -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } #if DDSRT_HAVE_ATOMIC64 inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) InterlockedExchangeAdd64 (&x->v, -v); -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } #endif inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v); -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { ddsrt_atomic_subptr ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v); } +inline uint32_t ddsrt_atomic_sub32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + /* disable unary minus applied to unsigned type, result still unsigned */ + DDSRT_WARNING_MSVC_OFF(4146) + return InterlockedExchangeAdd (&x->v, -v); + DDSRT_WARNING_MSVC_ON(4146) +} inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) return InterlockedExchangeAdd (&x->v, -v) - v; -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } #if DDSRT_HAVE_ATOMIC64 inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) return InterlockedExchangeAdd64 (&x->v, -v) - v; -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } #endif inline uintptr_t ddsrt_atomic_subptr_nv (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v) { /* disable unary minus applied to unsigned type, result still unsigned */ -DDSRT_WARNING_MSVC_OFF(4146) + DDSRT_WARNING_MSVC_OFF(4146) return DDSRT_ATOMIC_PTROP (InterlockedExchangeAdd) (&x->v, -v) - v; -DDSRT_WARNING_MSVC_ON(4146) + DDSRT_WARNING_MSVC_ON(4146) } inline void *ddsrt_atomic_subvoidp_nv (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { return (void *) ddsrt_atomic_subptr_nv ((volatile ddsrt_atomic_uintptr_t *) x, (uintptr_t) v); @@ -280,16 +292,21 @@ inline void ddsrt_atomic_fence (void) { /* 28113: accessing a local variable tmp via an Interlocked function: This is an unusual usage which could be reconsidered. It is too heavyweight, true, but it does the trick. */ -DDSRT_WARNING_MSVC_OFF(28113) + DDSRT_WARNING_MSVC_OFF(28113) volatile LONG tmp = 0; InterlockedExchange (&tmp, 0); -DDSRT_WARNING_MSVC_ON(28113) + DDSRT_WARNING_MSVC_ON(28113) } inline void ddsrt_atomic_fence_ldld (void) { #if !(defined _M_IX86 || defined _M_X64) ddsrt_atomic_fence (); #endif } +inline void ddsrt_atomic_fence_stst (void) { +#if !(defined _M_IX86 || defined _M_X64) + ddsrt_atomic_fence (); +#endif +} inline void ddsrt_atomic_fence_acq (void) { ddsrt_atomic_fence (); } diff --git a/src/ddsrt/include/dds/ddsrt/atomics/sun.h b/src/ddsrt/include/dds/ddsrt/atomics/sun.h index 74a7469..c5f871b 100644 --- a/src/ddsrt/include/dds/ddsrt/atomics/sun.h +++ b/src/ddsrt/include/dds/ddsrt/atomics/sun.h @@ -40,6 +40,11 @@ inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) { inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x) { atomic_inc_ulong (&x->v); } +inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x) { + uint32_t oldval, newval; + do { oldval = x->v; newval = oldval + 1; } while (atomic_cas_32 (&x->v, oldval, newval) != oldval); + return oldval; +} inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x) { return atomic_inc_32_nv (&x->v); } @@ -100,6 +105,9 @@ inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { atomic_add_ptr (&x->v, v); } +inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return atomic_add_32_nv (&x->v, v) - v; +} inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { return atomic_add_32_nv (&x->v, v); } @@ -127,6 +135,9 @@ inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v) { atomic_add_ptr (&x->v, -v); } +inline uint32_t ddsrt_atomic_sub32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { + return atomic_add_32_nv (&x->v, -v) + v; +} inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v) { return atomic_add_32_nv (&x->v, -v); } @@ -234,7 +245,10 @@ inline void ddsrt_atomic_fence (void) { membar_enter (); } inline void ddsrt_atomic_fence_ldld (void) { - membar_enter (); + membar_consumer (); +} +inline void ddsrt_atomic_fence_stst (void) { + membar_producer (); } inline void ddsrt_atomic_fence_acq (void) { membar_enter (); diff --git a/src/ddsrt/include/dds/ddsrt/attributes.h b/src/ddsrt/include/dds/ddsrt/attributes.h index c91584d..08e1e0a 100644 --- a/src/ddsrt/include/dds/ddsrt/attributes.h +++ b/src/ddsrt/include/dds/ddsrt/attributes.h @@ -105,4 +105,22 @@ # define ddsrt_attribute_assume_aligned(params) #endif +#if ddsrt_has_attribute(packed) +# define ddsrt_attribute_packed __attribute__ ((__packed__)) +#else +# define ddsrt_attribute_packed +#endif + +#if ddsrt_has_attribute(no_sanitize) +# define ddsrt_attribute_no_sanitize(params) __attribute__ ((__no_sanitize__ params)) +#else +# define ddsrt_attribute_no_sanitize(params) +#endif + +#if defined(__has_feature) +# define ddsrt_has_feature_thread_sanitizer __has_feature(thread_sanitizer) +#else +# define ddsrt_has_feature_thread_sanitizer 0 +#endif + #endif /* DDSRT_ATTRIBUTES_H */ diff --git a/src/ddsrt/include/dds/ddsrt/countargs.h b/src/ddsrt/include/dds/ddsrt/countargs.h new file mode 100644 index 0000000..69e6773 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/countargs.h @@ -0,0 +1,20 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSRT_COUNTARGS_H +#define DDSRT_COUNTARGS_H + +#define DDSRT_COUNT_ARGS_MSVC_WORKAROUND(x) x +#define DDSRT_COUNT_ARGS(...) DDSRT_COUNT_ARGS1 (__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1,0) +#define DDSRT_COUNT_ARGS1(...) DDSRT_COUNT_ARGS_MSVC_WORKAROUND (DDSRT_COUNT_ARGS_ARGN (__VA_ARGS__)) +#define DDSRT_COUNT_ARGS_ARGN(a,b,c,d,e,f,g,h,i,j,n,...) n + +#endif diff --git a/src/ddsrt/include/dds/ddsrt/dynlib.h b/src/ddsrt/include/dds/ddsrt/dynlib.h index 1f9270e..554438b 100644 --- a/src/ddsrt/include/dds/ddsrt/dynlib.h +++ b/src/ddsrt/include/dds/ddsrt/dynlib.h @@ -47,7 +47,7 @@ typedef struct ddsrt_dynlib *ddsrt_dynlib_t; * @param[in] translate Automatic name translation on/off. * @param[out] handle Library handle that will be assigned after successfull operation. It is assigned to NULL if loading fails. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Library handle was successfully loaded. @@ -57,7 +57,7 @@ typedef struct ddsrt_dynlib *ddsrt_dynlib_t; * Loading failed. * Use ddsrt_dlerror() to diagnose the failure. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_dlopen( const char *name, bool translate, @@ -73,7 +73,7 @@ ddsrt_dlopen( * * @param[in] handle Library handle. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Library handle was successfully closed. @@ -81,7 +81,7 @@ ddsrt_dlopen( * Library closing failed. * Use ddsrt_dlerror() to diagnose the failure. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_dlclose( ddsrt_dynlib_t handle); @@ -95,7 +95,7 @@ ddsrt_dlclose( * @param[in] symbol Symbol name. * @param[out] address The memory address of the loaded symbol (void*). * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Symbol was found in the loaded library. @@ -104,7 +104,7 @@ ddsrt_dlclose( * Symbol was not found. * Use ddsrt_dlerror() to diagnose the failure. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_dlsym( ddsrt_dynlib_t handle, const char *symbol, @@ -124,14 +124,14 @@ ddsrt_dlsym( * function should be called immediately after calling ddsrt_dlopen or ddsrt_dlsym * function. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Most recent library related error returned. * @retval DDS_RETCODE_NOT_FOUND * No library related error found. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_dlerror( char *buf, size_t buflen); diff --git a/src/ddsrt/include/dds/ddsrt/endian.h b/src/ddsrt/include/dds/ddsrt/endian.h index a046b09..c1b831b 100644 --- a/src/ddsrt/include/dds/ddsrt/endian.h +++ b/src/ddsrt/include/dds/ddsrt/endian.h @@ -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 diff --git a/src/ddsrt/include/dds/ddsrt/environ.h b/src/ddsrt/include/dds/ddsrt/environ.h index 67a8c29..d5d895e 100644 --- a/src/ddsrt/include/dds/ddsrt/environ.h +++ b/src/ddsrt/include/dds/ddsrt/environ.h @@ -24,13 +24,9 @@ extern "C" { * @brief Get value for environment variable. * * @param[in] name Environment variable name. - * @param[in] buf Buffer to write value to. - * @param[in] sz Size of buffer. - * @param[out] reqsz Number of bytes written (excluding the terminating null - * byte), or would have been written would @buf have been - * sufficiently large enough. + * @param[out] value Alias to value of environment variable - must not be modified * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Environment variable written to @buf. @@ -43,7 +39,7 @@ extern "C" { * @retval DDS_RETCODE_ERROR * Unspecified error. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_getenv( const char *name, char **value) @@ -58,7 +54,7 @@ ddsrt_nonnull_all; * @param[in] name Environment variable name. * @param[in] value Value to set environment variable to. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Environment variable successfully set to @value. @@ -69,7 +65,7 @@ ddsrt_nonnull_all; * @retval DDS_RETCODE_ERROR * Unspecified system error. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_setenv( const char *name, const char *value) @@ -80,7 +76,7 @@ ddsrt_nonnull_all; * * @param[in] name Environment variable name. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Environment variable successfully unset. @@ -91,7 +87,7 @@ ddsrt_nonnull_all; * @retval DDS_RETCODE_ERROR * Unspecified system error. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_unsetenv( const char *name) ddsrt_nonnull_all; @@ -104,6 +100,10 @@ ddsrt_nonnull_all; * The result string should be freed with ddsrt_free(). * * @param[in] string String to expand. + * @param[in] domid Domain id that this is relevant to + * UINT32_MAX means none (see logging) + * also made available as + * ${CYCLONEDDS_DOMAIN_ID} * * @returns Allocated char*. * @@ -115,7 +115,8 @@ ddsrt_nonnull_all; */ DDS_EXPORT char* ddsrt_expand_envvars( - const char *string); + const char *string, + uint32_t domid); /** * @brief Expand environment variables within string. @@ -137,7 +138,8 @@ ddsrt_expand_envvars( */ DDS_EXPORT char* ddsrt_expand_envvars_sh( - const char *string); + const char *string, + uint32_t domid); #if defined(__cplusplus) diff --git a/src/ddsrt/include/dds/ddsrt/hopscotch.h b/src/ddsrt/include/dds/ddsrt/hopscotch.h index 24d9213..dbb4004 100644 --- a/src/ddsrt/include/dds/ddsrt/hopscotch.h +++ b/src/ddsrt/include/dds/ddsrt/hopscotch.h @@ -20,15 +20,6 @@ extern "C" { #endif -/* Concurrent version */ -struct ddsrt_chh; -struct ddsrt_chh_bucket; -struct ddsrt_chh_iter { - struct ddsrt_chh_bucket *bs; - uint32_t size; - uint32_t cursor; -}; - /* * The hopscotch hash table is dependent on a proper functioning hash. * If the hash function generates a lot of hash collisions, then it will @@ -39,29 +30,20 @@ struct ddsrt_chh_iter { * When proper distributed hash values are generated, then hopscotch * works nice and quickly. */ -typedef uint32_t (*ddsrt_hh_hash_fn) (const void *); +typedef uint32_t (*ddsrt_hh_hash_fn) (const void *a); /* * Hopscotch needs to be able to compare two elements. * Returns 0 when not equal. */ -typedef int (*ddsrt_hh_equals_fn) (const void *, const void *); +typedef int (*ddsrt_hh_equals_fn) (const void *a, const void *b); /* * Hopscotch is will resize its internal buckets list when needed. It will * call this garbage collection function with the old buckets list. The * caller has to delete the list when it deems it safe to do so. */ -typedef void (*ddsrt_hh_buckets_gc_fn) (void *); - -DDS_EXPORT struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets); -DDS_EXPORT void ddsrt_chh_free (struct ddsrt_chh * __restrict hh); -DDS_EXPORT void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template); -DDS_EXPORT int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data); -DDS_EXPORT int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template); -DDS_EXPORT void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */ -void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it); -void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it); +typedef void (*ddsrt_hh_buckets_gc_fn) (void *bs, void *arg); /* Sequential version */ struct ddsrt_hh; @@ -80,6 +62,31 @@ DDS_EXPORT void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void DDS_EXPORT void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter); /* may delete nodes */ DDS_EXPORT void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter); +/* Concurrent version */ +struct ddsrt_chh; +struct ddsrt_chh_bucket; + +#if ! ddsrt_has_feature_thread_sanitizer +struct ddsrt_chh_iter { + struct ddsrt_chh_bucket *bs; + uint32_t size; + uint32_t cursor; +}; +#else +struct ddsrt_chh_iter { + struct ddsrt_chh *chh; + struct ddsrt_hh_iter it; +}; +#endif + +DDS_EXPORT struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg); +DDS_EXPORT void ddsrt_chh_free (struct ddsrt_chh * __restrict hh); +DDS_EXPORT void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template); +DDS_EXPORT int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data); +DDS_EXPORT int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template); +DDS_EXPORT void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */ +DDS_EXPORT void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it); +DDS_EXPORT void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it); /* Sequential version, embedded data */ struct ddsrt_ehh; diff --git a/src/ddsrt/include/dds/ddsrt/ifaddrs.h b/src/ddsrt/include/dds/ddsrt/ifaddrs.h index b98d5b8..3eea634 100644 --- a/src/ddsrt/include/dds/ddsrt/ifaddrs.h +++ b/src/ddsrt/include/dds/ddsrt/ifaddrs.h @@ -18,11 +18,18 @@ extern "C" { #endif +enum ddsrt_iftype { + DDSRT_IFTYPE_UNKNOWN, + DDSRT_IFTYPE_WIRED, + DDSRT_IFTYPE_WIFI +}; + struct ddsrt_ifaddrs { struct ddsrt_ifaddrs *next; char *name; uint32_t index; uint32_t flags; + enum ddsrt_iftype type; struct sockaddr *addr; struct sockaddr *netmask; struct sockaddr *broadaddr; @@ -30,7 +37,7 @@ struct ddsrt_ifaddrs { typedef struct ddsrt_ifaddrs ddsrt_ifaddrs_t; -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_getifaddrs( ddsrt_ifaddrs_t **ifap, const int *afs); diff --git a/src/ddsrt/include/dds/ddsrt/log.h b/src/ddsrt/include/dds/ddsrt/log.h index 360f9c6..d3fbc2b 100644 --- a/src/ddsrt/include/dds/ddsrt/log.h +++ b/src/ddsrt/include/dds/ddsrt/log.h @@ -92,6 +92,8 @@ extern "C" { typedef struct { /** Log category the message falls into. */ uint32_t priority; + /** Log domain id, UINT32_MAX is global. */ + uint32_t domid; /** Filename where message was generated. */ const char *file; /** Line number in file where message was generated. */ @@ -102,10 +104,38 @@ typedef struct { const char *message; /** Size of log message. */ size_t size; + /** Default log message header length */ + size_t hdrsize; } dds_log_data_t; /** Function signature that log and trace callbacks must adhere too. */ -typedef void(*dds_log_write_fn_t)(void *, const dds_log_data_t *); +typedef void (*dds_log_write_fn_t) (void *, const dds_log_data_t *); + +/** Semi-opaque type for log/trace configuration. */ +struct ddsrt_log_cfg_common { + /** Mask for testing whether the xLOG macro should forward to the + function (and so incur the cost of constructing the parameters). + Messages in DDS_LOG_MASK are rare, so the overhead of calling + the function and then dropping the message is not an issue, unlike + for messages in DDS_TRACE_MASK. */ + uint32_t mask; + + /** The actual configured trace mask */ + uint32_t tracemask; + + /** Domain id for reporting; UINT32_MAX = no domain */ + uint32_t domid; +}; + +typedef struct ddsrt_log_cfg { + struct ddsrt_log_cfg_common c; + union { + dds_log_write_fn_t fnptr; + void *ptr; + uint32_t u32; + unsigned char pad[72]; + } u; +} ddsrt_log_cfg_t; DDS_EXPORT extern uint32_t *const dds_log_mask; @@ -186,14 +216,84 @@ dds_set_trace_sink( void *userdata); /** - * @brief Write a log or trace message. + * @brief Initialize a struct ddsrt_log_cfg for use with dds_log_cfg + * + * Callbacks registered to handle log messages will receive messages of type + * info, warning, error and fatal. Messages that fall into the trace category + * will never be delivered to the callback. + * + * Callbacks registered to handle trace messages will receive messages of type + * info, warning, error and fatal as well as all message types that fall into + * the trace category depending on the log mask. + * + * This operation is synchronous and only returns once the operation is + * registered with all threads. Meaning that neither callback or + * userdata will be referenced by the DDS stack on return. + * + * @param[out] cfg On return, initialised to make dds_log_cfg invoked + * with this config object behave as specified by the + * other parameters. + * @param[in] domid Numerical identifier in log/trace, UINT32_MAX is + * reserved for global logging. + * @param[in] tracemask Mask determining which traces should be written. + * @param[in] log_fp File for default sink. + * @param[in] trace_fp File for default sink. + */ +DDS_EXPORT void +dds_log_cfg_init( + struct ddsrt_log_cfg *cfg, + uint32_t domid, + uint32_t tracemask, + FILE *log_fp, + FILE *trace_fp); + +/** + * @brief Write a log or trace message for a specific logging configuraiton + * (categories, id, sinks). + * + * Direct use of #dds_log is discouraged. Use #DDS_CINFO, #DDS_CWARNING, + * #DDS_CERROR, #DDS_CTRACE or #DDS_CLOG instead. + */ +DDS_EXPORT void +dds_log_cfg( + const struct ddsrt_log_cfg *cfg, + uint32_t prio, + const char *file, + uint32_t line, + const char *func, + const char *fmt, + ...) + ddsrt_attribute_format((__printf__, 6, 7)); + +/** + * @brief Write a log or trace message to the global configuration but with + * specific domain (intended solely for use during domain start-up, while + * the domain-specific logging/tracing hasn't been set yet). + * + * Write a log or trace message to one (or both) of the currently active sinks. + * + * Direct use of #dds_log_id is discouraged. Use #DDS_ILOG instead. + */ +DDS_EXPORT void +dds_log_id( + uint32_t prio, + uint32_t domid, + const char *file, + uint32_t line, + const char *func, + const char *fmt, + ...) + ddsrt_attribute_format((__printf__, 6, 7)); + +/** + * @brief Write a log or trace message to the global log/trace. * * Write a log or trace message to one (or both) of the currently active sinks. * * Direct use of #dds_log is discouraged. Use #DDS_INFO, #DDS_WARNING, * #DDS_ERROR, #DDS_FATAL or #DDS_LOG instead. */ -DDS_EXPORT int +DDS_EXPORT void dds_log( uint32_t prio, const char *file, @@ -279,23 +379,70 @@ dds_log( */ #define DDS_LOG(cat, ...) \ ((dds_get_log_mask() & (cat)) ? \ - dds_log(cat, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0) + dds_log((cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0) -/** Write a log message of type #DDS_LC_INFO. */ +/** + * @brief Write a log message with a domain id override. + * + * Write a log or trace message to the currently active log and/or trace sinks + * if the log category is enabled. Whether or not the category is enabled is + * checked before any dds_log-related activities to save a couple of % CPU. + * + * Only messages that fall into one of the log categories are passed onto + * dds_log. While messages that fall into a trace category could have been + * passed just as easily, they are rejected so that tracing is kept entirely + * separate from logging, if only cosmetic. + */ +#define DDS_ILOG(cat, domid, ...) \ + ((dds_get_log_mask() & (cat)) ? \ + dds_log_id((cat), (domid), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0) + +/** + * @brief Write a log message using a specific config. + * + * Write a log or trace message to the currently active log and/or trace sinks + * if the log category is enabled. Whether or not the category is enabled is + * checked before any dds_log-related activities to save a couple of % CPU. + * + * Only messages that fall into one of the log categories are passed onto + * dds_log. While messages that fall into a trace category could have been + * passed just as easily, they are rejected so that tracing is kept entirely + * separate from logging, if only cosmetic. + */ +#define DDS_CLOG(cat, cfg, ...) \ + (((cfg)->c.mask & (cat)) ? \ + dds_log_cfg((cfg), (cat), __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) : 0) + +/** Write a log message of type #DDS_LC_INFO into global log. */ #define DDS_INFO(...) \ DDS_LOG(DDS_LC_INFO, __VA_ARGS__) -/** Write a log message of type #DDS_LC_WARNING. */ +/** Write a log message of type #DDS_LC_WARNING into global log. */ #define DDS_WARNING(...) \ DDS_LOG(DDS_LC_WARNING, __VA_ARGS__) -/** Write a log message of type #DDS_LC_ERROR. */ +/** Write a log message of type #DDS_LC_ERROR into global log. */ #define DDS_ERROR(...) \ DDS_LOG(DDS_LC_ERROR, __VA_ARGS__) -/** Write a log message of type #DDS_LC_ERROR and abort. */ +/** Write a log message of type #DDS_LC_ERROR into global log and abort. */ #define DDS_FATAL(...) \ dds_log(DDS_LC_FATAL, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) -/** Write a #DDS_LC_TRACE message. */ -#define DDS_TRACE(...) \ - DDS_LOG(DDS_LC_TRACE, __VA_ARGS__) + +/* MSVC mishandles __VA_ARGS__ while claiming to be conforming -- and even + if they have a defensible implement, they still differ from every other + compiler out there. An extra layer of macro expansion works around it. */ +#define DDS_CLOG_MSVC_WORKAROUND(x) x + +/** Write a log message of type #DDS_LC_INFO using specific logging config. */ +#define DDS_CINFO(...) \ + DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_INFO, __VA_ARGS__)) +/** Write a log message of type #DDS_LC_WARNING using specific logging config. */ +#define DDS_CWARNING(...) \ + DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_WARNING, __VA_ARGS__)) +/** Write a log message of type #DDS_LC_ERROR using specific logging config. */ +#define DDS_CERROR(...) \ + DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_ERROR, __VA_ARGS__)) +/** Write a #DDS_LC_TRACE message using specific logging config. */ +#define DDS_CTRACE(...) \ + DDS_CLOG_MSVC_WORKAROUND(DDS_CLOG(DDS_LC_TRACE, __VA_ARGS__)) #if defined (__cplusplus) } diff --git a/src/ddsrt/include/dds/ddsrt/misc.h b/src/ddsrt/include/dds/ddsrt/misc.h index 1d165b1..582a52d 100644 --- a/src/ddsrt/include/dds/ddsrt/misc.h +++ b/src/ddsrt/include/dds/ddsrt/misc.h @@ -18,29 +18,45 @@ extern "C" { #endif -#if defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 -# define DDSRT_GNUC_STR(s) #s -# define DDSRT_GNUC_JOINSTR(x,y) DDSRT_GNUC_STR(x ## y) -# define DDSRT_GNUC_DO_PRAGMA(x) _Pragma (#x) -# define DDSRT_GNUC_PRAGMA(x) DDSRT_GNUC_DO_PRAGMA(GCC diagnostic x) -# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 +#if defined(__clang__) || \ + defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 +# define DDSRT_STR(s) #s +# define DDSRT_JOINSTR(x,y) DDSRT_STR(x ## y) +# define DDSRT_DO_PRAGMA(x) _Pragma(#x) +# define DDSRT_PRAGMA(x) DDSRT_DO_PRAGMA(GCC diagnostic x) + +# if defined(__clang__) +# define DDSRT_WARNING_CLANG_OFF(x) \ + DDSRT_PRAGMA(push) \ + DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x)) +# define DDSRT_WARNING_CLANG_ON(x) \ + DDSRT_PRAGMA(pop) +# elif ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406 # define DDSRT_WARNING_GNUC_OFF(x) \ - DDSRT_GNUC_PRAGMA(push) \ - DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x)) + DDSRT_PRAGMA(push) \ + DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x)) # define DDSRT_WARNING_GNUC_ON(x) \ - DDSRT_GNUC_PRAGMA(pop) + DDSRT_PRAGMA(pop) # else # define DDSRT_WARNING_GNUC_OFF(x) \ - DDSRT_GNUC_PRAGMA(ignored DDSRT_GNUC_JOINSTR(-W,x)) + DDSRT_PRAGMA(ignored DDSRT_JOINSTR(-W,x)) # define DDSRT_WARNING_GNUC_ON(x) \ - DDSRT_GNUC_PRAGMA(warning DDSRT_GNUC_JOINSTR(-W,x)) + DDSRT_PRAGMA(warning DDSRT_JOINSTR(-W,x)) # endif -#else +#endif + +#if !defined(DDSRT_WARNING_CLANG_OFF) && \ + !defined(DDSRT_WARNING_CLANG_ON) +# define DDSRT_WARNING_CLANG_OFF(x) +# define DDSRT_WARNING_CLANG_ON(x) +#endif + +#if !defined(DDSRT_WARNING_GNUC_OFF) && \ + !defined(DDSRT_WARNING_GNUC_ON) # define DDSRT_WARNING_GNUC_OFF(x) # define DDSRT_WARNING_GNUC_ON(x) #endif - #if defined(_MSC_VER) # define DDSRT_WARNING_MSVC_OFF(x) \ __pragma (warning(push)) \ @@ -52,23 +68,6 @@ extern "C" { # define DDSRT_WARNING_MSVC_ON(x) #endif -/** - * @brief Calculate maximum value of an integer type - * - * A somewhat complex, but efficient way to calculate the maximum value of an - * integer type at compile time. - * - * For unsigned numerical types the first part up to XOR is enough. The second - * part is to make up for signed numerical types. - */ -#define DDSRT_MAX_INTEGER(T) \ - ((T)(((T)~0) ^ ((T)!((T)~0 > 0) << (CHAR_BIT * sizeof(T) - 1)))) -/** - * @brief Calculate minimum value of an integer type - */ -#define DDSRT_MIN_INTEGER(T) \ - ((-DDSRT_MAX_INTEGER(T)) - 1) - /** * @brief Macro to disable unused argument warnings */ diff --git a/src/ddsrt/include/dds/ddsrt/netstat.h b/src/ddsrt/include/dds/ddsrt/netstat.h new file mode 100644 index 0000000..49151d2 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/netstat.h @@ -0,0 +1,73 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSRT_NETSTAT_H +#define DDSRT_NETSTAT_H + +#include + +#include "dds/export.h" +#include "dds/ddsrt/retcode.h" + +#if defined (__linux) || defined (__APPLE__) || defined (_WIN32) +#define DDSRT_HAVE_NETSTAT (1) +#else +#define DDSRT_HAVE_NETSTAT (0) +#endif + +#if DDSRT_HAVE_NETSTAT + +#if defined(__cplusplus) +extern "C" { +#endif + +struct ddsrt_netstat { + uint64_t ipkt; + uint64_t opkt; + uint64_t ibytes; + uint64_t obytes; +}; + +/** + * @brief Platform dependent control structure for network statistics + */ +struct ddsrt_netstat_control; + +/** + * @brief Prepare for gathering network statistics for specified interface. + */ +DDS_EXPORT dds_return_t +ddsrt_netstat_new ( + struct ddsrt_netstat_control **control, + const char *device); + +/** + * @brief Release resources for gathering network statistics. + */ +DDS_EXPORT dds_return_t +ddsrt_netstat_free ( + struct ddsrt_netstat_control *control); + +/** + * @brief Get network statistics. + */ +DDS_EXPORT dds_return_t +ddsrt_netstat_get ( + struct ddsrt_netstat_control *control, + struct ddsrt_netstat *stats); + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_HAVE_NETSTAT */ + +#endif /* DDSRT_NETSTAT_H */ diff --git a/src/ddsrt/include/dds/ddsrt/process.h b/src/ddsrt/include/dds/ddsrt/process.h index 45e7099..2d59130 100644 --- a/src/ddsrt/include/dds/ddsrt/process.h +++ b/src/ddsrt/include/dds/ddsrt/process.h @@ -17,19 +17,30 @@ #include "dds/ddsrt/types.h" #include "dds/ddsrt/retcode.h" -#if defined(_WIN32) +#if DDSRT_WITH_FREERTOS +#include +#include +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 #if defined(_WRS_KERNEL) typedef RTP_ID ddsrt_pid_t; /* typedef struct wind_rtp *RTP_ID */ #define PRIdPID PRIuPTR +#define DDSRT_HAVE_MULTI_PROCESS 0 #else typedef pid_t ddsrt_pid_t; #define PRIdPID "d" +#define DDSRT_HAVE_MULTI_PROCESS 1 +#endif #endif -#endif /* _WIN32 */ #if defined (__cplusplus) @@ -44,6 +55,7 @@ extern "C" { DDS_EXPORT ddsrt_pid_t ddsrt_getpid(void); +#if DDSRT_HAVE_MULTI_PROCESS /** * @brief Create new process. @@ -60,7 +72,7 @@ ddsrt_getpid(void); * @param[in] argv Arguments array. * @param[out] pid ID of the created process. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Process successfully created. @@ -73,7 +85,7 @@ ddsrt_getpid(void); * @retval DDS_RETCODE_ERROR * Process could not be created. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_proc_create( const char *executable, char *const argv[], @@ -94,10 +106,10 @@ ddsrt_proc_create( * See ddsrt_proc_waitpids() for waiting on all child processes. * * @param[in] pid Process ID (PID) to get the exit code from. - * @param[in] timemout Time within the process is expected to finish. + * @param[in] timeout Time within the process is expected to finish. * @param[out] code The exit code of the process. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Process has terminated and its exit code has been captured. @@ -112,7 +124,7 @@ ddsrt_proc_create( * @retval DDS_RETCODE_ERROR * Getting the exit code failed for an unknown reason. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_proc_waitpid( ddsrt_pid_t pid, dds_duration_t timeout, @@ -133,11 +145,11 @@ ddsrt_proc_waitpid( * * See ddsrt_proc_waitpid() for waiting on a specific child process. * - * @param[in] timemout Time within a process is expected to finish. + * @param[in] timeout Time within a process is expected to finish. * @param[out] pid Process ID (PID) of the finished process. * @param[out] code The exit code of the process. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * A process has terminated. @@ -153,7 +165,7 @@ ddsrt_proc_waitpid( * @retval DDS_RETCODE_ERROR * Getting the exit code failed for an unknown reason. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_proc_waitpids( dds_duration_t timeout, ddsrt_pid_t *pid, @@ -164,7 +176,7 @@ ddsrt_proc_waitpids( * * @param[in] pid Process ID (PID) to check if it exists. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * The process exists. @@ -173,7 +185,7 @@ ddsrt_proc_waitpids( * @retval DDS_RETCODE_ERROR * Determining if a process exists or not, failed. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_proc_exists( ddsrt_pid_t pid); @@ -190,7 +202,7 @@ ddsrt_proc_exists( * * @param[in] pid Process ID (PID) of the process to terminate. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Kill attempt has been started. @@ -201,10 +213,11 @@ ddsrt_proc_exists( * @retval DDS_RETCODE_ERROR * Kill failed for an unknown reason. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_proc_kill( ddsrt_pid_t pid); +#endif /* DDSRT_HAVE_MULTI_PROCESS */ #if defined (__cplusplus) } diff --git a/src/ddsrt/include/dds/ddsrt/retcode.h b/src/ddsrt/include/dds/ddsrt/retcode.h index f57626d..20b106f 100644 --- a/src/ddsrt/include/dds/ddsrt/retcode.h +++ b/src/ddsrt/include/dds/ddsrt/retcode.h @@ -9,7 +9,7 @@ extern "C" { #endif -typedef int32_t dds_retcode_t; +typedef int32_t dds_return_t; /* State is unchanged following a function call returning an error @@ -29,25 +29,25 @@ typedef int32_t dds_retcode_t; * @{ */ #define DDS_RETCODE_OK 0 /**< Success */ -#define DDS_RETCODE_ERROR 1 /**< Non specific error */ -#define DDS_RETCODE_UNSUPPORTED 2 /**< Feature unsupported */ -#define DDS_RETCODE_BAD_PARAMETER 3 /**< Bad parameter value */ -#define DDS_RETCODE_PRECONDITION_NOT_MET 4 /**< Precondition for operation not met */ -#define DDS_RETCODE_OUT_OF_RESOURCES 5 /**< When an operation fails because of a lack of resources */ -#define DDS_RETCODE_NOT_ENABLED 6 /**< When a configurable feature is not enabled */ -#define DDS_RETCODE_IMMUTABLE_POLICY 7 /**< When an attempt is made to modify an immutable policy */ -#define DDS_RETCODE_INCONSISTENT_POLICY 8 /**< When a policy is used with inconsistent values */ -#define DDS_RETCODE_ALREADY_DELETED 9 /**< When an attempt is made to delete something more than once */ -#define DDS_RETCODE_TIMEOUT 10 /**< When a timeout has occurred */ -#define DDS_RETCODE_NO_DATA 11 /**< When expected data is not provided */ -#define DDS_RETCODE_ILLEGAL_OPERATION 12 /**< When a function is called when it should not be */ -#define DDS_RETCODE_NOT_ALLOWED_BY_SECURITY 13 /**< When credentials are not enough to use the function */ +#define DDS_RETCODE_ERROR -1 /**< Non specific error */ +#define DDS_RETCODE_UNSUPPORTED -2 /**< Feature unsupported */ +#define DDS_RETCODE_BAD_PARAMETER -3 /**< Bad parameter value */ +#define DDS_RETCODE_PRECONDITION_NOT_MET -4 /**< Precondition for operation not met */ +#define DDS_RETCODE_OUT_OF_RESOURCES -5 /**< When an operation fails because of a lack of resources */ +#define DDS_RETCODE_NOT_ENABLED -6 /**< When a configurable feature is not enabled */ +#define DDS_RETCODE_IMMUTABLE_POLICY -7 /**< When an attempt is made to modify an immutable policy */ +#define DDS_RETCODE_INCONSISTENT_POLICY -8 /**< When a policy is used with inconsistent values */ +#define DDS_RETCODE_ALREADY_DELETED -9 /**< When an attempt is made to delete something more than once */ +#define DDS_RETCODE_TIMEOUT -10 /**< When a timeout has occurred */ +#define DDS_RETCODE_NO_DATA -11 /**< When expected data is not provided */ +#define DDS_RETCODE_ILLEGAL_OPERATION -12 /**< When a function is called when it should not be */ +#define DDS_RETCODE_NOT_ALLOWED_BY_SECURITY -13 /**< When credentials are not enough to use the function */ /* Extended return codes are not in the DDS specification and are meant exclusively for internal use and must not be returned by the C API. */ -#define DDS_XRETCODE_BASE (50) -#define DDS_XRETCODE(x) (DDS_XRETCODE_BASE + (x)) +#define DDS_XRETCODE_BASE (-50) +#define DDS_XRETCODE(x) (DDS_XRETCODE_BASE - (x)) /** Requested resource is busy */ #define DDS_RETCODE_IN_PROGRESS DDS_XRETCODE(1) @@ -84,11 +84,11 @@ typedef int32_t dds_retcode_t; /** * @brief Takes the error value and outputs a string corresponding to it. * - * @param[in] err Error value to be converted to a string + * @param[in] ret Error value to be converted to a string * * @returns String corresponding to the error value */ -DDS_EXPORT const char *dds_strretcode(dds_retcode_t ret); +DDS_EXPORT const char *dds_strretcode(dds_return_t ret); #if defined (__cplusplus) } diff --git a/src/ddsrt/include/dds/ddsrt/rusage.h b/src/ddsrt/include/dds/ddsrt/rusage.h index 040ce2e..a8906ac 100644 --- a/src/ddsrt/include/dds/ddsrt/rusage.h +++ b/src/ddsrt/include/dds/ddsrt/rusage.h @@ -14,8 +14,23 @@ #include +#if DDSRT_WITH_FREERTOS +#include +# if configUSE_TRACE_FACILITY == 1 && \ + configGENERATE_RUN_TIME_STATS == 1 +# define DDSRT_HAVE_RUSAGE 1 +# else +# define DDSRT_HAVE_RUSAGE 0 +#endif +#elif defined (_WIN32) || defined (__linux) || defined (__APPLE__) +# define DDSRT_HAVE_RUSAGE 1 +#else +# define DDSRT_HAVE_RUSAGE 0 +#endif + #include "dds/ddsrt/time.h" #include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/threads.h" #if defined (__cplusplus) extern "C" { @@ -31,8 +46,10 @@ typedef struct { size_t nivcsw; /* Involuntary context switches. Not maintained on Windows. */ } ddsrt_rusage_t; -#define DDSRT_RUSAGE_SELF (0) -#define DDSRT_RUSAGE_THREAD (1) +enum ddsrt_getrusage_who { + DDSRT_RUSAGE_SELF, + DDSRT_RUSAGE_THREAD +}; /** * @brief Get resource usage for the current thread or process. @@ -40,7 +57,7 @@ typedef struct { * @param[in] who DDSRT_RUSAGE_SELF or DDSRT_RUSAGE_THREAD. * @param[in] usage Structure where resource usage is returned. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Resource usage successfully returned in @usage. @@ -49,7 +66,26 @@ typedef struct { * @retval DDS_RETCODE_ERROR * An unidentified error occurred. */ -DDS_EXPORT dds_retcode_t ddsrt_getrusage(int who, ddsrt_rusage_t *usage); +DDS_EXPORT dds_return_t ddsrt_getrusage(enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage); + +#if DDSRT_HAVE_THREAD_LIST +/** + * @brief Get resource usage for some thread. + * + * @param[in] tid id of the thread of to get the resource usage for + * @param[in] usage Structure where resource usage is returned. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Resource usage successfully returned in @usage. + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * There were not enough resources to get resource usage. + * @retval DDS_RETCODE_ERROR + * An unidentified error occurred. + */ +DDS_EXPORT dds_return_t ddsrt_getrusage_anythread (ddsrt_thread_list_id_t tid, ddsrt_rusage_t * __restrict usage); +#endif #if defined (__cplusplus) } diff --git a/src/ddsrt/include/dds/ddsrt/sockets.h b/src/ddsrt/include/dds/ddsrt/sockets.h index ec5efa3..0f55e2b 100644 --- a/src/ddsrt/include/dds/ddsrt/sockets.h +++ b/src/ddsrt/include/dds/ddsrt/sockets.h @@ -3,6 +3,10 @@ #include +#if !defined(DDSRT_WITH_DNS) +# define DDSRT_WITH_DNS 1 +#endif + #include "dds/export.h" #include "dds/ddsrt/types.h" #include "dds/ddsrt/attributes.h" @@ -28,53 +32,53 @@ extern const struct in6_addr ddsrt_in6addr_loopback; #define DDSRT_AF_TERM (-1) -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_gethostname( char *hostname, size_t buffersize); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_socket( ddsrt_socket_t *sockptr, int domain, int type, int protocol); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_close( ddsrt_socket_t sock); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_connect( ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_accept( ddsrt_socket_t sock, struct sockaddr *addr, socklen_t *addrlen, ddsrt_socket_t *connptr); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_listen( ddsrt_socket_t sock, int backlog); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_bind( ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_getsockname( ddsrt_socket_t sock, struct sockaddr *addr, socklen_t *addrlen); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_send( ddsrt_socket_t sock, const void *buf, @@ -82,14 +86,14 @@ ddsrt_send( int flags, ssize_t *sent); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_sendmsg( ddsrt_socket_t sock, const ddsrt_msghdr_t *msg, int flags, ssize_t *sent); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_recv( ddsrt_socket_t sock, void *buf, @@ -97,14 +101,14 @@ ddsrt_recv( int flags, ssize_t *rcvd); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_recvmsg( ddsrt_socket_t sock, ddsrt_msghdr_t *msg, int flags, ssize_t *rcvd); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_getsockopt( ddsrt_socket_t sock, int32_t level, /* SOL_SOCKET */ @@ -112,7 +116,7 @@ ddsrt_getsockopt( void *optval, socklen_t *optlen); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_setsockopt( ddsrt_socket_t sock, int32_t level, /* SOL_SOCKET */ @@ -126,7 +130,7 @@ ddsrt_setsockopt( * @param[in] sock Socket to set I/O mode for. * @param[in] nonblock true for nonblocking, or false for blocking I/O. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * I/O mode successfully set to (non)blocking. @@ -137,7 +141,7 @@ ddsrt_setsockopt( * @retval DDS_RETCODE_ERROR * An unknown error error occurred. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_setsocknonblocking( ddsrt_socket_t sock, bool nonblock); @@ -224,11 +228,11 @@ ddsrt_sockaddr_insamesubnet( const struct sockaddr *mask) ddsrt_nonnull_all; -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_sockaddrfromstr( int af, const char *str, void *sa); -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_sockaddrtostr( const void *sa, char *buf, size_t size); @@ -243,9 +247,9 @@ typedef struct { * * @param[in] name Host name to resolve. * @param[in] af Address family, either AF_INET, AF_INET6 or AF_UNSPEC. - * @param[out] hent Structure of type ddsrt_hostent_t. + * @param[out] hentp Structure of type ddsrt_hostent_t. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Host name successfully resolved to address(es). @@ -258,7 +262,7 @@ typedef struct { * @retval DDS_RETCODE_TRY_AGAIN * Nonauthoratitative host not found. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_gethostbyname( const char *name, int af, diff --git a/src/ddsrt/include/dds/ddsrt/sockets/posix.h b/src/ddsrt/include/dds/ddsrt/sockets/posix.h index a9697af..21cc327 100644 --- a/src/ddsrt/include/dds/ddsrt/sockets/posix.h +++ b/src/ddsrt/include/dds/ddsrt/sockets/posix.h @@ -12,12 +12,17 @@ #ifndef DDSRT_SOCKETS_POSIX_H #define DDSRT_SOCKETS_POSIX_H +#if DDSRT_WITH_LWIP +#include +#include +#else +#include #include #include #include #include #include -#include +#endif #if defined(__cplusplus) extern "C" { @@ -27,21 +32,51 @@ typedef int ddsrt_socket_t; #define DDSRT_INVALID_SOCKET (-1) #define PRIdSOCK "d" -#define DDSRT_HAVE_IPV6 1 -#define DDSRT_HAVE_DNS 1 -#define DDSRT_HAVE_SSM 1 +#if LWIP_SOCKET +# if LWIP_IPV6 +# define DDSRT_HAVE_IPV6 1 +# endif +# if LWIP_DNS && LWIP_SOCKET +# define DDSRT_HAVE_DNS DDSRT_WITH_DNS +# define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS +# endif +# define DDSRT_HAVE_SSM 0 +# define DDSRT_HAVE_INET_NTOP 1 +# define DDSRT_HAVE_INET_PTON 1 + +# define IFF_UP 0x1 +# define IFF_BROADCAST 0x2 +# define IFF_LOOPBACK 0x8 +# define IFF_POINTOPOINT 0x10 +# define IFF_MULTICAST 0x1000 +#elif __SunOS_5_6 +# define DDSRT_HAVE_IPV6 0 +# define DDSRT_HAVE_DNS DDSRT_WITH_DNS +# define DDSRT_HAVE_GETADDRINFO 0 +# define DDSRT_HAVE_SSM 0 +# define DDSRT_HAVE_INET_NTOP 0 +# define DDSRT_HAVE_INET_PTON 0 +#else /* LWIP_SOCKET */ +# define DDSRT_HAVE_IPV6 1 +# define DDSRT_HAVE_DNS DDSRT_WITH_DNS +# define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS +# define DDSRT_HAVE_SSM 1 +# define DDSRT_HAVE_INET_NTOP 1 +# define DDSRT_HAVE_INET_PTON 1 +#endif /* LWIP_SOCKET */ typedef struct iovec ddsrt_iovec_t; typedef size_t ddsrt_iov_len_t; -#if defined(__linux) +#if defined(__linux) && !LWIP_SOCKET typedef size_t ddsrt_msg_iovlen_t; #else /* POSIX says int (which macOS, FreeBSD, Solaris do) */ typedef int ddsrt_msg_iovlen_t; #endif typedef struct msghdr ddsrt_msghdr_t; -#if defined(__sun) && !defined(_XPG4_2) +#if (defined(__sun) && !defined(_XPG4_2)) || \ + (defined(LWIP_SOCKET)) # define DDSRT_MSGHDR_FLAGS 0 #else # define DDSRT_MSGHDR_FLAGS 1 diff --git a/src/ddsrt/include/dds/ddsrt/sockets/windows.h b/src/ddsrt/include/dds/ddsrt/sockets/windows.h index 277dfe7..b557a21 100644 --- a/src/ddsrt/include/dds/ddsrt/sockets/windows.h +++ b/src/ddsrt/include/dds/ddsrt/sockets/windows.h @@ -12,8 +12,11 @@ typedef SOCKET ddsrt_socket_t; #define DDSRT_INVALID_SOCKET (INVALID_SOCKET) #define PRIdSOCK PRIuPTR -#define DDSRT_HAVE_IPV6 1 -#define DDSRT_HAVE_DNS 1 +#define DDSRT_HAVE_IPV6 1 +#define DDSRT_HAVE_DNS DDSRT_WITH_DNS +#define DDSRT_HAVE_GETADDRINFO DDSRT_WITH_DNS +#define DDSRT_HAVE_INET_NTOP 1 +#define DDSRT_HAVE_INET_PTON 1 #if defined(NTDDI_VERSION) && \ defined(_WIN32_WINNT_WS03) && \ diff --git a/src/core/ddsi/include/dds/ddsi/q_static_assert.h b/src/ddsrt/include/dds/ddsrt/static_assert.h similarity index 58% rename from src/core/ddsi/include/dds/ddsi/q_static_assert.h rename to src/ddsrt/include/dds/ddsrt/static_assert.h index 078ed62..f21d44f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_static_assert.h +++ b/src/ddsrt/include/dds/ddsrt/static_assert.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2019 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,29 +9,34 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef Q_STATIC_ASSERT_H -#define Q_STATIC_ASSERT_H +#ifndef DDSRT_STATIC_ASSERT_H +#define DDSRT_STATIC_ASSERT_H /* There are many tricks to use a constant expression to yield an illegal type or expression at compile time, such as zero-sized arrays and duplicate case or enum labels. So this is but one of the many tricks. */ +#define DDSRT_STATIC_ASSERT2(line, pred) \ + struct static_assert_##line { \ + char cond[(pred) ? 1 : -1]; \ + } +#define DDSRT_STATIC_ASSERT1(line, pred) \ + DDSRT_STATIC_ASSERT2 (line, pred) +#define DDSRT_STATIC_ASSERT(pred) \ + DDSRT_STATIC_ASSERT1 (__LINE__, pred) + #ifndef _MSC_VER - -#define Q_STATIC_ASSERT_CODE(pred) do { switch(0) { case 0: case pred: ; } } while (0) - +#define DDSRT_STATIC_ASSERT_CODE(pred) do { switch(0) { case 0: case (pred): ; } } while (0) #else - /* Temporarily disabling warning C6326: Potential comparison of a constant with another constant. */ -#define Q_STATIC_ASSERT_CODE(pred) do { \ +#define DDSRT_STATIC_ASSERT_CODE(pred) do { \ __pragma (warning (push)) \ __pragma (warning (disable : 6326)) \ - switch(0) { case 0: case pred: ; } \ + switch(0) { case 0: case (pred): ; } \ __pragma (warning (pop)) \ } while (0) - #endif -#endif /* Q_STATIC_ASSERT_H */ +#endif diff --git a/src/ddsrt/include/dds/ddsrt/string.h b/src/ddsrt/include/dds/ddsrt/string.h index 1d8f184..7fca58c 100644 --- a/src/ddsrt/include/dds/ddsrt/string.h +++ b/src/ddsrt/include/dds/ddsrt/string.h @@ -12,7 +12,6 @@ #ifndef DDSRT_STRING_H #define DDSRT_STRING_H -#include #include "dds/export.h" #include "dds/ddsrt/attributes.h" #include "dds/ddsrt/retcode.h" @@ -53,21 +52,6 @@ ddsrt_strncasecmp( size_t n) ddsrt_nonnull((1,2)); -/** - * @brief Split string into tokens. - * - * @param[in] str String to split into tokens. - * @param[in] delim Characters that delimit a token. - * @param[inout] saveptr Pointer to a char * used internally. - * - * @returns The next token or NULL if there are no more tokens. - */ -DDS_EXPORT char * -ddsrt_strtok_r( - char *str, - const char *delim, - char **saveptr); - /** * @brief Extract token from string. * @@ -75,7 +59,7 @@ ddsrt_strtok_r( * @delim. The delimiter is overwritten with a null byte, terminating the * token and @stringp is updated to point past the delimiter. * - * @param[inout] stringp String to extract token from. + * @param[in,out] stringp String to extract token from. * @param[in] delim Characters that delimit a token. * * @returns The original value of @stringp. @@ -154,7 +138,7 @@ ddsrt_nonnull((1,2)); * string is truncated if there is not enough space. The resulting string * guaranteed to be null terminated if there is space. * - * @param[inout] dest Destination buffer. + * @param[in,out] dest Destination buffer. * @param[in] src Null terminated string to append to dest. * @param[in] size Number of bytes available in dest. * @@ -170,8 +154,6 @@ ddsrt_strlcat( size_t size) ddsrt_nonnull((1,2)); - - /** * @brief Get description for specified system error number. * @@ -179,7 +161,7 @@ ddsrt_nonnull((1,2)); * @param[in] buf Buffer where description is copied to. * @param[in] buflen Number of bytes available in @buf. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Description for @errnum was successfully copied to @buf. @@ -188,7 +170,7 @@ ddsrt_nonnull((1,2)); * @retval DDS_RETCODE_NOT_ENOUGH_SPACE * Buffer was not large enough to hold the description. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_strerror_r( int errnum, char *buf, diff --git a/src/ddsrt/include/dds/ddsrt/strtod.h b/src/ddsrt/include/dds/ddsrt/strtod.h index f8bb511..4db08e7 100644 --- a/src/ddsrt/include/dds/ddsrt/strtod.h +++ b/src/ddsrt/include/dds/ddsrt/strtod.h @@ -34,9 +34,9 @@ extern "C" { * character is stored. * @param[out] dblptr A double where the result is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_strtod(const char *nptr, char **endptr, double *dblptr); /** @@ -47,9 +47,9 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr); * character is stored. * @param[out] fltptr A float where the floating-point number is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_strtof(const char *nptr, char **endptr, float *fltptr); /** diff --git a/src/ddsrt/include/dds/ddsrt/strtol.h b/src/ddsrt/include/dds/ddsrt/strtol.h index a862c06..c4cb059 100644 --- a/src/ddsrt/include/dds/ddsrt/strtol.h +++ b/src/ddsrt/include/dds/ddsrt/strtol.h @@ -37,7 +37,7 @@ extern "C" { * determine from @str. * @param[out] llng A long long integer where the number is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * String successfully converted to an integer. @@ -46,7 +46,7 @@ extern "C" { * @retval DDS_RETCODE_OUT_OF_RANGE * String converted to an integer, but was out of range. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_strtoll( const char *str, char **endptr, @@ -69,7 +69,7 @@ ddsrt_strtoll( * determine from @str. * @param[out] ullng A long long integer where the number is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * String successfully converted to an integer. @@ -78,7 +78,7 @@ ddsrt_strtoll( * @retval DDS_RETCODE_OUT_OF_RANGE * String converted to an integer, but was out of range. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_strtoull( const char *str, char **endptr, @@ -91,7 +91,7 @@ ddsrt_strtoull( * @param[in] str String to convert into a long long integer. * @param[in] llng A long long integer where the number is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * String successfully converted to an integer. @@ -100,7 +100,7 @@ ddsrt_strtoull( * @retval DDS_RETCODE_OUT_OF_RANGE * String converted to an integer, but was out of range. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_atoll( const char *str, long long *llng); @@ -111,7 +111,7 @@ ddsrt_atoll( * @param[in] str String to conver into an unsigned long long integer. * @param[out] ullng An unsigned long long integer where the number is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * String successfully converted to an integer. @@ -120,7 +120,7 @@ ddsrt_atoll( * @retval DDS_RETCODE_OUT_OF_RANGE * String converted to an integer, but was out of range. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_atoull( const char *str, unsigned long long *ullng); diff --git a/src/ddsrt/include/dds/ddsrt/sync.h b/src/ddsrt/include/dds/ddsrt/sync.h index 8228aab..a9e62e3 100644 --- a/src/ddsrt/include/dds/ddsrt/sync.h +++ b/src/ddsrt/include/dds/ddsrt/sync.h @@ -18,8 +18,12 @@ #include "dds/ddsrt/retcode.h" #include "dds/ddsrt/attributes.h" -#if _WIN32 +#if DDSRT_WITH_FREERTOS +#include "dds/ddsrt/sync/freertos.h" +#elif _WIN32 #include "dds/ddsrt/sync/windows.h" +#elif __SunOS_5_6 +#include "dds/ddsrt/sync/solaris2.6.h" #else #include "dds/ddsrt/sync/posix.h" #endif diff --git a/src/ddsrt/include/dds/ddsrt/sync/freertos.h b/src/ddsrt/include/dds/ddsrt/sync/freertos.h new file mode 100644 index 0000000..4d05578 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/sync/freertos.h @@ -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 +#include +#include +#include + +#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 */ diff --git a/src/ddsrt/include/dds/ddsrt/sync/solaris2.6.h b/src/ddsrt/include/dds/ddsrt/sync/solaris2.6.h new file mode 100644 index 0000000..34b1956 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/sync/solaris2.6.h @@ -0,0 +1,44 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSRT_POSIX_SYNC_H +#define DDSRT_POSIX_SYNC_H + +#include +#include +#if HAVE_LKST +#include "lkst.h" +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +typedef struct { + pthread_cond_t cond; +} ddsrt_cond_t; + +typedef struct { + pthread_mutex_t mutex; +} ddsrt_mutex_t; + +typedef struct { + pthread_mutex_t rwlock; +} ddsrt_rwlock_t; + +typedef pthread_once_t ddsrt_once_t; +#define DDSRT_ONCE_INIT PTHREAD_ONCE_INIT + +#if defined (__cplusplus) +} +#endif + +#endif /* DDSRT_POSIX_SYNC_H */ diff --git a/src/ddsrt/include/dds/ddsrt/thread_pool.h b/src/ddsrt/include/dds/ddsrt/thread_pool.h index f03fe46..4bcdc77 100644 --- a/src/ddsrt/include/dds/ddsrt/thread_pool.h +++ b/src/ddsrt/include/dds/ddsrt/thread_pool.h @@ -55,7 +55,7 @@ DDS_EXPORT void ddsrt_thread_pool_purge (ddsrt_thread_pool pool); Note that if the pool queue has reached it's maximum DDS_RETCODE_TRY_AGAIN is returned. */ -DDS_EXPORT dds_retcode_t ddsrt_thread_pool_submit +DDS_EXPORT dds_return_t ddsrt_thread_pool_submit ( ddsrt_thread_pool pool, /* Thread pool instance */ void (*fn) (void *arg), /* Function to be invoked by thread from pool */ diff --git a/src/ddsrt/include/dds/ddsrt/threads.h b/src/ddsrt/include/dds/ddsrt/threads.h index 7497002..e258218 100644 --- a/src/ddsrt/include/dds/ddsrt/threads.h +++ b/src/ddsrt/include/dds/ddsrt/threads.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" @@ -119,14 +121,14 @@ ddsrt_nonnull_all; * @param[in] start_routine Function to execute in created thread. * @param[in] arg Argument passed to @start_routine. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Thread successfully created. * @retval DDS_RETCODE_ERROR * Thread could not be created. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_thread_create( ddsrt_thread_t *thread, const char *name, @@ -170,14 +172,14 @@ ddsrt_thread_equal(ddsrt_thread_t t1, ddsrt_thread_t t2); * @param[in] thread Id of thread to wait for. * @param[out] thread_result Location where thread result is stored. * - * @returns A dds_retcode_t indicating success or failure. + * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK * Target thread terminated. * @retval DDS_RETCODE_ERROR * An error occurred while waiting for the thread to terminate. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_thread_join( ddsrt_thread_t thread, uint32_t *thread_result); @@ -206,9 +208,58 @@ ddsrt_thread_getname( * * @param[in] name Name for current thread. */ +#if DDSRT_HAVE_THREAD_SETNAME DDS_EXPORT void ddsrt_thread_setname( const char *__restrict name); +#endif + +#if DDSRT_HAVE_THREAD_LIST +/** + * @brief Get a list of threads in the calling process + * + * @param[out] tids Array of size elements to be filled with thread + * identifiers, may be NULL if size is 0 + * @param[in] size The size of the tids array; 0 is allowed + * + * @returns A dds_return_t indicating the number of threads in the process + * or an error code on failure. + * + * @retval > 0 + * Number of threads in the process, may be larger than size + * tids[0 .. (return - 1)] are valid + * @retval DDS_RETCODE_ERROR + * Something went wrong, contents of tids is undefined + * @retval DDS_RETCODE_UNSUPPORTED + * Not supported on the platform + */ +DDS_EXPORT dds_return_t ddsrt_thread_list (ddsrt_thread_list_id_t * __restrict tids, size_t size); + +/** + * @brief Get the name of the specified thread (in the calling process) + * + * @param[in] tid Thread identifier for which the name is sought + * @param[out] name Filled with the thread name (or a synthesized one) + * on successful return; name is silently truncated + * if the actual name is longer than name can hold; + * always 0-terminated if size > 0 + * @param[in] size Number of bytes of name that may be assigned, size + * is 0 is allowed, though somewhat useless + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Possibly truncated name is returned as a null-terminated + * string in name (provided size > 0). + * @retval DDS_RETCODE_NOT_FOUND + * Thread not found; the contents of name is unchanged + * @retval DDS_RETCODE_ERROR + * Unspecified failure, the contents of name is undefined + * @retval DDS_RETCODE_UNSUPPORTED + * Not supported on the platform + */ +DDS_EXPORT dds_return_t ddsrt_thread_getname_anythread (ddsrt_thread_list_id_t tid, char *__restrict name, size_t size); +#endif /** * @brief Push cleanup handler onto the cleanup stack @@ -220,7 +271,7 @@ ddsrt_thread_setname( * @param[in] routine Cleanup handler to push onto the thread cleanup stack. * @param[in] arg Argument that will be passed to the cleanup handler. */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_thread_cleanup_push( void (*routine)(void*), void *arg); @@ -231,7 +282,7 @@ ddsrt_thread_cleanup_push( * Remove routine at the top of the calling thread's cleanup stack and * optionally invoke it (if execute is non-zero). */ -DDS_EXPORT dds_retcode_t +DDS_EXPORT dds_return_t ddsrt_thread_cleanup_pop( int execute); diff --git a/src/ddsrt/include/dds/ddsrt/threads/freertos.h b/src/ddsrt/include/dds/ddsrt/threads/freertos.h new file mode 100644 index 0000000..50b517f --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/threads/freertos.h @@ -0,0 +1,36 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSRT_THREADS_FREERTOS_H +#define DDSRT_THREADS_FREERTOS_H + +#include +#include + +#define DDSRT_HAVE_THREAD_SETNAME (0) +#define DDSRT_HAVE_THREAD_LIST (0) + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef struct { + TaskHandle_t task; +} ddsrt_thread_t; + +typedef UBaseType_t ddsrt_tid_t; +#define PRIdTID "lu" + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_THREADS_FREERTOS_H */ diff --git a/src/ddsrt/include/dds/ddsrt/threads/posix.h b/src/ddsrt/include/dds/ddsrt/threads/posix.h index 63d193d..9324c73 100644 --- a/src/ddsrt/include/dds/ddsrt/threads/posix.h +++ b/src/ddsrt/include/dds/ddsrt/threads/posix.h @@ -14,6 +14,17 @@ #include +#if defined(__VXWORKS__) +#define DDSRT_HAVE_THREAD_SETNAME (0) +#else +#define DDSRT_HAVE_THREAD_SETNAME (1) +#endif +#if defined (__linux) || defined (__APPLE__) +#define DDSRT_HAVE_THREAD_LIST (1) +#else +#define DDSRT_HAVE_THREAD_LIST (0) +#endif + #if defined (__cplusplus) extern "C" { #endif @@ -21,6 +32,7 @@ extern "C" { #if defined(__linux) typedef long int ddsrt_tid_t; #define PRIdTID "ld" +typedef long int ddsrt_thread_list_id_t; /* __linux */ #elif defined(__FreeBSD__) && (__FreeBSD_version >= 900031) /* FreeBSD >= 9.0 */ @@ -32,6 +44,8 @@ typedef int ddsrt_tid_t; /* macOS X >= 10.6 */ typedef uint64_t ddsrt_tid_t; #define PRIdTID PRIu64 +/* ddsrt_thread_list_id_t is actually a mach_port_t */ +typedef uint32_t ddsrt_thread_list_id_t; /* __APPLE__ */ #elif defined(__VXWORKS__) /* TODO: Verify taskIdSelf is the right function to use on VxWorks */ @@ -43,7 +57,7 @@ typedef TASK_ID ddsrt_tid_t; # endif /* __VXWORKS__ */ #else -typedef uintmax_t ddsrt_tid_t; +typedef uintptr_t ddsrt_tid_t; #define PRIdTID PRIuPTR #endif diff --git a/src/ddsrt/include/dds/ddsrt/threads/windows.h b/src/ddsrt/include/dds/ddsrt/threads/windows.h index e7eda64..1fdce54 100644 --- a/src/ddsrt/include/dds/ddsrt/threads/windows.h +++ b/src/ddsrt/include/dds/ddsrt/threads/windows.h @@ -14,6 +14,9 @@ #include "dds/ddsrt/types.h" +#define DDSRT_HAVE_THREAD_SETNAME (1) +#define DDSRT_HAVE_THREAD_LIST (1) + #if defined (__cplusplus) extern "C" { #endif @@ -26,6 +29,8 @@ typedef struct { typedef DWORD ddsrt_tid_t; #define PRIdTID "u" +typedef HANDLE ddsrt_thread_list_id_t; + #if defined (__cplusplus) } #endif diff --git a/src/ddsrt/include/dds/ddsrt/time.h b/src/ddsrt/include/dds/ddsrt/time.h index 37fcfa3..a474fb4 100644 --- a/src/ddsrt/include/dds/ddsrt/time.h +++ b/src/ddsrt/include/dds/ddsrt/time.h @@ -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 */ diff --git a/src/ddsrt/include/dds/ddsrt/time/freertos.h b/src/ddsrt/include/dds/ddsrt/time/freertos.h new file mode 100644 index 0000000..09525ee --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/time/freertos.h @@ -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 +#include + +#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 */ diff --git a/src/ddsrt/include/dds/ddsrt/types/posix.h b/src/ddsrt/include/dds/ddsrt/types/posix.h index 6088737..1344dc1 100644 --- a/src/ddsrt/include/dds/ddsrt/types/posix.h +++ b/src/ddsrt/include/dds/ddsrt/types/posix.h @@ -14,6 +14,10 @@ #include #include +#if defined(__IAR_SYSTEMS_ICC__) +typedef long int ssize_t; +#else #include +#endif #endif /* DDSRT_TYPES_POSIX_H */ diff --git a/src/ddsrt/include/dds/ddsrt/xmlparser.h b/src/ddsrt/include/dds/ddsrt/xmlparser.h index e33815b..93bd92d 100644 --- a/src/ddsrt/include/dds/ddsrt/xmlparser.h +++ b/src/ddsrt/include/dds/ddsrt/xmlparser.h @@ -20,10 +20,10 @@ extern "C" { #endif - typedef int (*ddsrt_xmlp_proc_elem_open_t) (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name); - typedef int (*ddsrt_xmlp_proc_attr_t) (void *varg, uintptr_t eleminfo, const char *name, const char *value); - typedef int (*ddsrt_xmlp_proc_elem_data_t) (void *varg, uintptr_t eleminfo, const char *data); - typedef int (*ddsrt_xmlp_proc_elem_close_t) (void *varg, uintptr_t eleminfo); + typedef int (*ddsrt_xmlp_proc_elem_open_t) (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line); + typedef int (*ddsrt_xmlp_proc_attr_t) (void *varg, uintptr_t eleminfo, const char *name, const char *value, int line); + typedef int (*ddsrt_xmlp_proc_elem_data_t) (void *varg, uintptr_t eleminfo, const char *data, int line); + typedef int (*ddsrt_xmlp_proc_elem_close_t) (void *varg, uintptr_t eleminfo, int line); typedef void (*ddsrt_xmlp_error) (void *varg, const char *msg, int line); struct ddsrt_xmlp_callbacks { @@ -36,9 +36,9 @@ extern "C" { struct ddsrt_xmlp_state; -#define DDSRT_XMLP_REQUIRE_EOF 1u /* set by default; if not set, junk may follow top-level closing tag */ -#define DDSRT_XMLP_ANONYMOUS_CLOSE_TAG 2u /* clear by default; if set allow closing an element with instead of */ - +#define DDSRT_XMLP_REQUIRE_EOF 1u /* set by default; if not set, junk may follow top-level closing tag */ +#define DDSRT_XMLP_ANONYMOUS_CLOSE_TAG 2u /* clear by default; if set allow closing an element with instead of */ +#define DDSRT_XMLP_MISSING_CLOSE_AS_EOF 4u /* clear by default; if set, treat missing close tag as EOF */ DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_file (FILE *fp, void *varg, const struct ddsrt_xmlp_callbacks *cb); DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, const struct ddsrt_xmlp_callbacks *cb); DDS_EXPORT void ddsrt_xmlp_set_options (struct ddsrt_xmlp_state *st, unsigned options); @@ -46,8 +46,6 @@ extern "C" { DDS_EXPORT void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st); DDS_EXPORT int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st); - DDS_EXPORT int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n); - #if defined (__cplusplus) } #endif diff --git a/src/ddsrt/src/atomics.c b/src/ddsrt/src/atomics.c index bc87a7b..829be41 100644 --- a/src/ddsrt/src/atomics.c +++ b/src/ddsrt/src/atomics.c @@ -30,6 +30,7 @@ extern inline void ddsrt_atomic_inc32 (volatile ddsrt_atomic_uint32_t *x); extern inline void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x); #endif extern inline void ddsrt_atomic_incptr (volatile ddsrt_atomic_uintptr_t *x); +extern inline uint32_t ddsrt_atomic_inc32_ov (volatile ddsrt_atomic_uint32_t *x); extern inline uint32_t ddsrt_atomic_inc32_nv (volatile ddsrt_atomic_uint32_t *x); #if DDSRT_HAVE_ATOMIC64 extern inline uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x); @@ -58,6 +59,7 @@ extern inline void ddsrt_atomic_add64 (volatile ddsrt_atomic_uint64_t *x, uint64 #endif extern inline void ddsrt_atomic_addptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v); extern inline void ddsrt_atomic_addvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v); +extern inline uint32_t ddsrt_atomic_add32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v); extern inline uint32_t ddsrt_atomic_add32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v); #if DDSRT_HAVE_ATOMIC64 extern inline uint64_t ddsrt_atomic_add64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); @@ -71,6 +73,7 @@ extern inline void ddsrt_atomic_sub64 (volatile ddsrt_atomic_uint64_t *x, uint64 #endif extern inline void ddsrt_atomic_subptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t v); extern inline void ddsrt_atomic_subvoidp (volatile ddsrt_atomic_voidp_t *x, ptrdiff_t v); +extern inline uint32_t ddsrt_atomic_sub32_ov (volatile ddsrt_atomic_uint32_t *x, uint32_t v); extern inline uint32_t ddsrt_atomic_sub32_nv (volatile ddsrt_atomic_uint32_t *x, uint32_t v); #if DDSRT_HAVE_ATOMIC64 extern inline uint64_t ddsrt_atomic_sub64_nv (volatile ddsrt_atomic_uint64_t *x, uint64_t v); @@ -122,6 +125,7 @@ extern inline int ddsrt_atomic_casvoidp2 (volatile ddsrt_atomic_uintptr2_t *x, u /* FENCES */ extern inline void ddsrt_atomic_fence (void); extern inline void ddsrt_atomic_fence_ldld (void); +extern inline void ddsrt_atomic_fence_stst (void); extern inline void ddsrt_atomic_fence_acq (void); extern inline void ddsrt_atomic_fence_rel (void); @@ -161,3 +165,182 @@ void ddsrt_atomic_lifo_pushmany (ddsrt_atomic_lifo_t *head, void *first, void *l } while (!ddsrt_atomic_casvoidp2 (&head->aba_head, a0, b0, a0+1, (uintptr_t)first)); } #endif + +/* On platforms that don't provide 64-bit atomic operations, emulate them by hashing + the variable's address to a small set of mutexes. + + This also defines the GCC builtins on SPARCv8 for 32-bit operations. It would be + more appropriate to simply define the ddsrt_atomic_... functions properly in that + case and avoid squatting in the __sync_... namespace, but SPARCv8 support really + is just for fun and it doesn't seem worth the bother right now */ + +#if DDSRT_HAVE_ATOMIC64 + +void ddsrt_atomics_init (void) { } +void ddsrt_atomics_fini (void) { } + +#else + +#include "dds/ddsrt/sync.h" + +/* SPARCv8 depends on these mutexes already for one-shot initialisation of the ddsrt + code. Using PTHREAD_MUTEX_INITIALIZER guarantees they are properly initialized. + Once a platform shows up that defines that macro where we don't used pthread mutexes + something else will have to be done. */ +#define N_MUTEXES_LG2 4 +#define N_MUTEXES (1 << N_MUTEXES_LG2) +#ifndef PTHREAD_MUTEX_INITIALIZER +static ddsrt_mutex_t mutexes[N_MUTEXES]; + +void ddsrt_atomics_init (void) +{ + for (int i = 0; i < N_MUTEXES; i++) + ddsrt_mutex_init (&mutexes[i]); +} + +void ddsrt_atomics_fini (void) +{ + for (int i = 0; i < N_MUTEXES; i++) + ddsrt_mutex_destroy (&mutexes[i]); +} +#else +static ddsrt_mutex_t mutexes[N_MUTEXES] = { + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER } +}; +void ddsrt_atomics_init (void) { } +void ddsrt_atomics_fini (void) { } +#endif + +static uint32_t atomic64_lock_index (const volatile ddsrt_atomic_uint64_t *x) +{ + const uint32_t u = (uint16_t) ((uintptr_t) x >> 3); + const uint32_t v = u * 0xb4817365; + return v >> (32 - N_MUTEXES_LG2); +} + +int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_t exp, uint64_t des) +{ + const uint32_t idx = atomic64_lock_index (x); + ddsrt_mutex_lock (&mutexes[idx]); + if (x->v == exp) + { + x->v = des; + ddsrt_mutex_unlock (&mutexes[idx]); + return true; + } + else + { + ddsrt_mutex_unlock (&mutexes[idx]); + return false; + } +} + +#define DDSRT_FAKE_ATOMIC64(name, oper, ret) \ + uint64_t ddsrt_atomic_##name##64_##ret (volatile ddsrt_atomic_uint64_t *x, uint64_t v) \ + { \ + const uint64_t idx = atomic64_lock_index (x); \ + ddsrt_mutex_lock (&mutexes[idx]); \ + const uint64_t ov = x->v; \ + const uint64_t nv = ov oper v; \ + x->v = nv; \ + ddsrt_mutex_unlock (&mutexes[idx]); \ + return ret; \ + } +#define DDSRT_FAKE_ATOMIC64_TRIPLET(name, oper) \ + DDSRT_FAKE_ATOMIC64(name, oper, nv) \ + DDSRT_FAKE_ATOMIC64(name, oper, ov) \ + void ddsrt_atomic_##name##64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) { \ + (void) ddsrt_atomic_##name##64_ov (x, v); \ + } + +uint64_t ddsrt_atomic_ld64 (const volatile ddsrt_atomic_uint64_t *x) +{ + const uint32_t idx = atomic64_lock_index (x); + ddsrt_mutex_lock (&mutexes[idx]); + const uint64_t v = x->v; + ddsrt_mutex_unlock (&mutexes[idx]); + return v; +} + +void ddsrt_atomic_st64 (volatile ddsrt_atomic_uint64_t *x, uint64_t v) +{ + const uint32_t idx = atomic64_lock_index (x); + ddsrt_mutex_lock (&mutexes[idx]); + x->v = v; + ddsrt_mutex_unlock (&mutexes[idx]); +} + +DDSRT_FAKE_ATOMIC64_TRIPLET(add, +) +DDSRT_FAKE_ATOMIC64_TRIPLET(sub, -) +DDSRT_FAKE_ATOMIC64_TRIPLET(or, |) +DDSRT_FAKE_ATOMIC64_TRIPLET(and, &) + +void ddsrt_atomic_inc64 (volatile ddsrt_atomic_uint64_t *x) { + ddsrt_atomic_add64 (x, 1); +} +uint64_t ddsrt_atomic_inc64_nv (volatile ddsrt_atomic_uint64_t *x) { + return ddsrt_atomic_add64_nv (x, 1); +} +void ddsrt_atomic_dec64 (volatile ddsrt_atomic_uint64_t *x) { + ddsrt_atomic_sub64 (x, 1); +} +uint64_t ddsrt_atomic_dec64_nv (volatile ddsrt_atomic_uint64_t *x) { + return ddsrt_atomic_sub64_nv (x, 1); +} + +#undef DDSRT_FAKE_ATOMIC64_TRIPLET +#undef DDSRT_FAKE_ATOMIC64 + +/* SPARCv8 doesn't support any atomic operations beyond a simple atomic exchange. GCC happily + compiles the __sync_* functions into library calls, and implementing them as such will do + the trick. The rarity of SPARCv8 machines (EOL'd 2 decades ago) */ +#ifdef __sparc_v8__ +#define DDSRT_FAKE_SYNC(name, size, oper, ret) \ + unsigned __sync_##name##_##size (volatile unsigned *x, unsigned v) \ + { \ + const uint32_t idx = atomic64_lock_index ((const volatile ddsrt_atomic_uint64_t *) x); \ + ddsrt_mutex_lock (&mutexes[idx]); \ + const uint32_t ov = *x; \ + const uint32_t nv = ov oper v; \ + *x = nv; \ + ddsrt_mutex_unlock (&mutexes[idx]); \ + return ret; \ + } +#define DDSRT_FAKE_SYNC_PAIR(name, size, oper) \ + DDSRT_FAKE_SYNC(name##_and_fetch, size, oper, nv) \ + DDSRT_FAKE_SYNC(fetch_and_##name, size, oper, ov) + +DDSRT_FAKE_SYNC_PAIR (add, 4, +) +DDSRT_FAKE_SYNC_PAIR (sub, 4, -) +DDSRT_FAKE_SYNC_PAIR (or, 4, |) +DDSRT_FAKE_SYNC_PAIR (and, 4, &) + +bool __sync_bool_compare_and_swap_4 (volatile unsigned *x, unsigned exp, unsigned des) +{ + const uint32_t idx = atomic64_lock_index ((const volatile ddsrt_atomic_uint64_t *) x); + ddsrt_mutex_lock (&mutexes[idx]); + if (*x == exp) + { + *x = des; + ddsrt_mutex_unlock (&mutexes[idx]); + return true; + } + else + { + ddsrt_mutex_unlock (&mutexes[idx]); + return false; + } +} + +#undef DDSRT_FAKE_SYNC_PAIR +#undef DDSRT_FAKE_SYNC +#endif /* SPARCv8 hack */ + +#endif /* DDSRT_HAVE_ATOMIC64 */ diff --git a/src/ddsrt/src/cdtors.c b/src/ddsrt/src/cdtors.c index 3888c87..e184098 100644 --- a/src/ddsrt/src/cdtors.c +++ b/src/ddsrt/src/cdtors.c @@ -43,6 +43,7 @@ retry: ddsrt_time_init(); #endif ddsrt_random_init(); + ddsrt_atomics_init(); ddsrt_atomic_or32(&init_status, INIT_STATUS_OK); } else { while (v > 1 && !(v & INIT_STATUS_OK)) { @@ -68,6 +69,7 @@ void ddsrt_fini (void) { ddsrt_mutex_destroy(&init_mutex); ddsrt_random_fini(); + ddsrt_atomics_fini(); #if _WIN32 ddsrt_winsock_fini(); ddsrt_time_fini(); @@ -139,6 +141,9 @@ ddsrt_cdtor( #pragma data_seg() #endif #else /* _WIN32 */ +void __attribute__((constructor)) ddsrt_ctor(void); +void __attribute__((destructor)) ddsrt_dtor(void); + void __attribute__((constructor)) ddsrt_ctor(void) { ddsrt_init(); diff --git a/src/ddsrt/src/dynlib/posix/dynlib.c b/src/ddsrt/src/dynlib/posix/dynlib.c index cb538d8..ec97397 100644 --- a/src/ddsrt/src/dynlib/posix/dynlib.c +++ b/src/ddsrt/src/dynlib/posix/dynlib.c @@ -17,9 +17,9 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/io.h" -dds_retcode_t ddsrt_dlopen(const char *name, bool translate, +dds_return_t ddsrt_dlopen(const char *name, bool translate, ddsrt_dynlib_t *handle) { - dds_retcode_t retcode = DDS_RETCODE_OK; + dds_return_t retcode = DDS_RETCODE_OK; assert( handle ); *handle = NULL; @@ -53,16 +53,16 @@ dds_retcode_t ddsrt_dlopen(const char *name, bool translate, return retcode; } -dds_retcode_t ddsrt_dlclose(ddsrt_dynlib_t handle) { +dds_return_t ddsrt_dlclose(ddsrt_dynlib_t handle) { assert ( handle ); return (dlclose(handle) == 0) ? DDS_RETCODE_OK : DDS_RETCODE_ERROR; } -dds_retcode_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol, +dds_return_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol, void **address) { - dds_retcode_t retcode = DDS_RETCODE_OK; + dds_return_t retcode = DDS_RETCODE_OK; assert( handle ); assert( address ); @@ -76,10 +76,10 @@ dds_retcode_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol, return retcode; } -dds_retcode_t ddsrt_dlerror(char *buf, size_t buflen) { +dds_return_t ddsrt_dlerror(char *buf, size_t buflen) { const char *err; - dds_retcode_t retcode = DDS_RETCODE_OK; + dds_return_t retcode = DDS_RETCODE_OK; assert (buf ); diff --git a/src/ddsrt/src/environ/posix/environ.c b/src/ddsrt/src/environ/posix/environ.c index b05769c..1f8b84f 100644 --- a/src/ddsrt/src/environ/posix/environ.c +++ b/src/ddsrt/src/environ/posix/environ.c @@ -23,7 +23,7 @@ isenvvar(const char *name) return (*name == '\0' || strchr(name, '=') != NULL) == 0; } -dds_retcode_t +dds_return_t ddsrt_getenv(const char *name, char **value) { char *env; @@ -40,7 +40,7 @@ ddsrt_getenv(const char *name, char **value) return DDS_RETCODE_NOT_FOUND; } -dds_retcode_t +dds_return_t ddsrt_setenv(const char *name, const char *value) { assert(name != NULL); @@ -65,7 +65,7 @@ ddsrt_setenv(const char *name, const char *value) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_unsetenv(const char *name) { assert(name != NULL); diff --git a/src/ddsrt/src/environ/solaris2.6/environ.c b/src/ddsrt/src/environ/solaris2.6/environ.c new file mode 100644 index 0000000..83f0d8f --- /dev/null +++ b/src/ddsrt/src/environ/solaris2.6/environ.c @@ -0,0 +1,100 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/retcode.h" + +extern char **environ; + +static int +isenvvar(const char *name) +{ + return (*name == '\0' || strchr(name, '=') != NULL) == 0; +} + +dds_return_t +ddsrt_getenv(const char *name, char **value) +{ + char *env; + + assert(name != NULL); + assert(value != NULL); + + if (!isenvvar(name)) + return DDS_RETCODE_BAD_PARAMETER; + if ((env = getenv(name)) != NULL) { + *value = env; + return DDS_RETCODE_OK; + } + return DDS_RETCODE_NOT_FOUND; +} + +dds_return_t +ddsrt_setenv(const char *name, const char *value) +{ + /* Not MT-Safe -- but it is only used in a tests to set + CYCLONEDDS_URI, so for Solaris 2.6 support it is not worth the + bother to do a better job. Same for a bit of leakage. */ + assert(name != NULL); + assert(value != NULL); + + if (strlen(value) == 0) + return ddsrt_unsetenv(name); + if (!isenvvar(name)) + return DDS_RETCODE_BAD_PARAMETER; + + const size_t namelen = strlen (name); + const size_t entrysize = namelen + 1 + strlen (value) + 1; + char *entry = malloc (entrysize); + snprintf (entry, entrysize, "%s=%s", name, value); + size_t n = 0; + while (environ[n] != NULL) + { + if (strncmp (environ[n], name, namelen) == 0 && environ[n][namelen] == '=') + { + environ[n] = entry; + return DDS_RETCODE_OK; + } + n++; + } + environ = realloc (environ, (n + 2) * sizeof (*environ)); + environ[n] = entry; + environ[n+1] = NULL; + return DDS_RETCODE_OK; +} + +dds_return_t +ddsrt_unsetenv(const char *name) +{ + /* Same considerations as setenv. */ + assert(name != NULL); + + if (!isenvvar(name)) + return DDS_RETCODE_BAD_PARAMETER; + + const size_t namelen = strlen (name); + size_t n = 0, idx = SIZE_MAX; + while (environ[n] != NULL) + { + if (idx > n && strncmp (environ[n], name, namelen) == 0 && environ[n][namelen] == '=') + idx = n; + n++; + } + if (idx < n) + memmove (&environ[idx], &environ[idx + 1], (n - idx) * sizeof (*environ)); + return DDS_RETCODE_OK; +} diff --git a/src/ddsrt/src/environ/windows/environ.c b/src/ddsrt/src/environ/windows/environ.c index 076aea1..a5b2f90 100644 --- a/src/ddsrt/src/environ/windows/environ.c +++ b/src/ddsrt/src/environ/windows/environ.c @@ -25,7 +25,7 @@ isenvvar(const char *name) } DDSRT_WARNING_MSVC_OFF(4996) -dds_retcode_t +dds_return_t ddsrt_getenv(const char *name, char **value) { char *env; @@ -43,7 +43,7 @@ ddsrt_getenv(const char *name, char **value) } DDSRT_WARNING_MSVC_ON(4996) -dds_retcode_t +dds_return_t ddsrt_setenv(const char *name, const char *value) { assert(name != NULL); @@ -65,7 +65,7 @@ ddsrt_setenv(const char *name, const char *value) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_unsetenv(const char *name) { assert(name != NULL); diff --git a/src/ddsrt/src/expand_envvars.c b/src/ddsrt/src/expand_envvars.c index dbaa33a..bd988c7 100644 --- a/src/ddsrt/src/expand_envvars.c +++ b/src/ddsrt/src/expand_envvars.c @@ -19,8 +19,9 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/process.h" -typedef char * (*expand_fn)(const char *src0); +typedef char * (*expand_fn)(const char *src0, uint32_t domid); static void expand_append (char **dst, size_t *sz, size_t *pos, char c) { @@ -32,34 +33,46 @@ static void expand_append (char **dst, size_t *sz, size_t *pos, char c) (*pos)++; } -static char *expand_env (const char *name, char op, const char *alt, expand_fn expand) +static char *expand_env (const char *name, char op, const char *alt, expand_fn expand, uint32_t domid) { + char idstr[20]; char *env = NULL; - (void)ddsrt_getenv (name, &env); + dds_return_t ret; + + if ((ret = ddsrt_getenv (name, &env)) == DDS_RETCODE_OK) { + /* ok */ + } else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) { + snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ()); + env = idstr; + } else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0 && domid != UINT32_MAX) { + snprintf (idstr, sizeof (idstr), "%"PRIu32, domid); + env = idstr; + } + switch (op) { case 0: return ddsrt_strdup (env ? env : ""); case '-': - return env && *env ? ddsrt_strdup (env) : expand (alt); + return env && *env ? ddsrt_strdup (env) : expand (alt, domid); case '?': if (env && *env) { return ddsrt_strdup (env); } else { - char *altx = expand (alt); - DDS_ERROR("%s: %s\n", name, altx); + char *altx = expand (alt, domid); + DDS_ILOG (DDS_LC_ERROR, domid, "%s: %s\n", name, altx); ddsrt_free (altx); return NULL; } case '+': - return env && *env ? expand (alt) : ddsrt_strdup (""); + return env && *env ? expand (alt, domid) : ddsrt_strdup (""); default: abort (); return NULL; } } -static char *expand_envbrace (const char **src, expand_fn expand) +static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid) { const char *start = *src + 1; char *name, *x; @@ -76,7 +89,7 @@ static char *expand_envbrace (const char **src, expand_fn expand) name[*src - start] = 0; if (**src == '}') { (*src)++; - x = expand_env (name, 0, NULL, expand); + x = expand_env (name, 0, NULL, expand, domid); ddsrt_free (name); return x; } else { @@ -120,7 +133,7 @@ static char *expand_envbrace (const char **src, expand_fn expand) memcpy (alt, altstart, (size_t) (*src - altstart)); alt[*src - altstart] = 0; (*src)++; - x = expand_env (name, op, alt, expand); + x = expand_env (name, op, alt, expand, domid); ddsrt_free (alt); ddsrt_free (name); return x; @@ -130,7 +143,7 @@ err: return NULL; } -static char *expand_envsimple (const char **src, expand_fn expand) +static char *expand_envsimple (const char **src, expand_fn expand, uint32_t domid) { const char *start = *src; char *name, *x; @@ -141,22 +154,22 @@ static char *expand_envsimple (const char **src, expand_fn expand) name = ddsrt_malloc ((size_t) (*src - start) + 1); memcpy (name, start, (size_t) (*src - start)); name[*src - start] = 0; - x = expand_env (name, 0, NULL, expand); + x = expand_env (name, 0, NULL, expand, domid); ddsrt_free (name); return x; } -static char *expand_envchar (const char **src, expand_fn expand) +static char *expand_envchar (const char **src, expand_fn expand, uint32_t domid) { char name[2]; assert (**src); name[0] = **src; name[1] = 0; (*src)++; - return expand_env (name, 0, NULL, expand); + return expand_env (name, 0, NULL, expand, domid); } -char *ddsrt_expand_envvars_sh (const char *src0) +char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid) { /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */ const char *src = src0; @@ -179,11 +192,11 @@ char *ddsrt_expand_envvars_sh (const char *src0) ddsrt_free(dst); return NULL; } else if (*src == '{') { - x = expand_envbrace (&src, &ddsrt_expand_envvars_sh); + x = expand_envbrace (&src, &ddsrt_expand_envvars_sh, domid); } else if (isalnum ((unsigned char) *src) || *src == '_') { - x = expand_envsimple (&src, &ddsrt_expand_envvars_sh); + x = expand_envsimple (&src, &ddsrt_expand_envvars_sh, domid); } else { - x = expand_envchar (&src, &ddsrt_expand_envvars_sh); + x = expand_envchar (&src, &ddsrt_expand_envvars_sh, domid); } if (x == NULL) { ddsrt_free(dst); @@ -202,7 +215,7 @@ char *ddsrt_expand_envvars_sh (const char *src0) return dst; } -char *ddsrt_expand_envvars (const char *src0) +char *ddsrt_expand_envvars (const char *src0, uint32_t domid) { /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */ const char *src = src0; @@ -212,7 +225,7 @@ char *ddsrt_expand_envvars (const char *src0) if (*src == '$' && *(src + 1) == '{') { char *x, *xp; src++; - x = expand_envbrace (&src, &ddsrt_expand_envvars); + x = expand_envbrace (&src, &ddsrt_expand_envvars, domid); if (x == NULL) { ddsrt_free(dst); return NULL; diff --git a/src/ddsrt/src/fibheap.c b/src/ddsrt/src/fibheap.c index 2e3bcf8..e9b122b 100644 --- a/src/ddsrt/src/fibheap.c +++ b/src/ddsrt/src/fibheap.c @@ -207,7 +207,7 @@ void *ddsrt_fibheap_extract_min (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap keys anyway to find the minimum */ { ddsrt_fibheap_node_t *mark, *cursor, *newmin; - unsigned i; + uint32_t i; for (i = 0; roots[i] == NULL; i++) { assert (i+1 < min_degree_noninit); } diff --git a/src/ddsrt/src/heap/freertos/heap.c b/src/ddsrt/src/heap/freertos/heap.c new file mode 100644 index 0000000..01782c4 --- /dev/null +++ b/src/ddsrt/src/heap/freertos/heap.c @@ -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 + +#if defined(configSUPPORT_DYNAMIC_ALLOCATION) && \ + (configSUPPORT_DYNAMIC_ALLOCATION == 0) +# error Dynamic memory allocation is not supported +#endif + +#include +#include +#include +#include + +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); + } +} diff --git a/src/ddsrt/src/hopscotch.c b/src/ddsrt/src/hopscotch.c index eef7efb..b6869b1 100644 --- a/src/ddsrt/src/hopscotch.c +++ b/src/ddsrt/src/hopscotch.c @@ -12,6 +12,7 @@ #include #include +#include "dds/ddsrt/attributes.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" @@ -22,8 +23,255 @@ #define NOT_A_BUCKET (~(uint32_t)0) +/************* SEQUENTIAL VERSION ***************/ + +struct ddsrt_hh_bucket { + uint32_t hopinfo; + void *data; +}; + +struct ddsrt_hh { + uint32_t size; /* power of 2 */ + struct ddsrt_hh_bucket *buckets; + ddsrt_hh_hash_fn hash; + ddsrt_hh_equals_fn equals; +}; + +static void ddsrt_hh_init (struct ddsrt_hh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals) +{ + uint32_t size; + uint32_t i; + /* degenerate case to minimize memory use */ + if (init_size == 1) { + size = 1; + } else { + size = HH_HOP_RANGE; + while (size < init_size) { + size *= 2; + } + } + rt->hash = hash; + rt->equals = equals; + rt->size = size; + rt->buckets = ddsrt_malloc (size * sizeof (*rt->buckets)); + for (i = 0; i < size; i++) { + rt->buckets[i].hopinfo = 0; + rt->buckets[i].data = NULL; + } +} + +static void ddsrt_hh_fini (struct ddsrt_hh *rt) +{ + ddsrt_free (rt->buckets); +} + +struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals) +{ + struct ddsrt_hh *hh = ddsrt_malloc (sizeof (*hh)); + ddsrt_hh_init (hh, init_size, hash, equals); + return hh; +} + +void ddsrt_hh_free (struct ddsrt_hh * __restrict hh) +{ + ddsrt_hh_fini (hh); + ddsrt_free (hh); +} + +static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t bucket, const void *template) +{ + const uint32_t idxmask = rt->size - 1; + uint32_t hopinfo = rt->buckets[bucket].hopinfo; + uint32_t idx; + for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) { + const uint32_t bidx = (bucket + idx) & idxmask; + void *data = rt->buckets[bidx].data; + if (data && rt->equals (data, template)) + return data; + } + return NULL; +} + +void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template) +{ + const uint32_t hash = rt->hash (template); + const uint32_t idxmask = rt->size - 1; + const uint32_t bucket = hash & idxmask; + return ddsrt_hh_lookup_internal (rt, bucket, template); +} + +static uint32_t ddsrt_hh_find_closer_free_bucket (struct ddsrt_hh *rt, uint32_t free_bucket, uint32_t *free_distance) +{ + const uint32_t idxmask = rt->size - 1; + uint32_t move_bucket, free_dist; + move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask; + for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) { + uint32_t move_free_distance = NOT_A_BUCKET; + uint32_t mask = 1; + uint32_t i; + for (i = 0; i < free_dist; i++, mask <<= 1) { + if (mask & rt->buckets[move_bucket].hopinfo) { + move_free_distance = i; + break; + } + } + if (move_free_distance != NOT_A_BUCKET) { + uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask; + rt->buckets[move_bucket].hopinfo |= 1u << free_dist; + rt->buckets[free_bucket].data = rt->buckets[new_free_bucket].data; + rt->buckets[new_free_bucket].data = NULL; + rt->buckets[move_bucket].hopinfo &= ~(1u << move_free_distance); + *free_distance -= free_dist - move_free_distance; + return new_free_bucket; + } + move_bucket = (move_bucket + 1) & idxmask; + } + return NOT_A_BUCKET; +} + +static void ddsrt_hh_resize (struct ddsrt_hh *rt) +{ + if (rt->size == 1) { + assert (rt->size == 1); + assert (rt->buckets[0].hopinfo == 1); + assert (rt->buckets[0].data != NULL); + + rt->size = HH_HOP_RANGE; + const uint32_t hash = rt->hash (rt->buckets[0].data); + const uint32_t idxmask = rt->size - 1; + const uint32_t start_bucket = hash & idxmask; + + struct ddsrt_hh_bucket *newbs = ddsrt_malloc (rt->size * sizeof (*newbs)); + for (uint32_t i = 0; i < rt->size; i++) { + newbs[i].hopinfo = 0; + newbs[i].data = NULL; + } + newbs[start_bucket] = rt->buckets[0]; + ddsrt_free (rt->buckets); + rt->buckets = newbs; + } else { + struct ddsrt_hh_bucket *bs1; + uint32_t i, idxmask0, idxmask1; + + bs1 = ddsrt_malloc (2 * rt->size * sizeof (*rt->buckets)); + + for (i = 0; i < 2 * rt->size; i++) { + bs1[i].hopinfo = 0; + bs1[i].data = NULL; + } + idxmask0 = rt->size - 1; + idxmask1 = 2 * rt->size - 1; + for (i = 0; i < rt->size; i++) { + void *data = rt->buckets[i].data; + if (data) { + const uint32_t hash = rt->hash (data); + const uint32_t old_start_bucket = hash & idxmask0; + const uint32_t new_start_bucket = hash & idxmask1; + const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket); + const uint32_t newb = (new_start_bucket + dist) & idxmask1; + assert (dist < HH_HOP_RANGE); + bs1[new_start_bucket].hopinfo |= 1u << dist; + bs1[newb].data = data; + } + } + + ddsrt_free (rt->buckets); + rt->size *= 2; + rt->buckets = bs1; + } +} + +int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data) +{ + const uint32_t hash = rt->hash (data); + const uint32_t idxmask = rt->size - 1; + const uint32_t start_bucket = hash & idxmask; + uint32_t free_distance, free_bucket; + + if (ddsrt_hh_lookup_internal (rt, start_bucket, data)) { + return 0; + } + + free_bucket = start_bucket; + for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) { + if (rt->buckets[free_bucket].data == NULL) + break; + free_bucket = (free_bucket + 1) & idxmask; + } + if (free_distance < HH_ADD_RANGE) { + do { + if (free_distance < HH_HOP_RANGE) { + assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask)); + rt->buckets[start_bucket].hopinfo |= 1u << free_distance; + rt->buckets[free_bucket].data = (void *) data; + return 1; + } + free_bucket = ddsrt_hh_find_closer_free_bucket (rt, free_bucket, &free_distance); + assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask); + } while (free_bucket != NOT_A_BUCKET); + } + + ddsrt_hh_resize (rt); + return ddsrt_hh_add (rt, data); +} + +int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template) +{ + const uint32_t hash = rt->hash (template); + const uint32_t idxmask = rt->size - 1; + const uint32_t bucket = hash & idxmask; + uint32_t hopinfo; + uint32_t idx; + hopinfo = rt->buckets[bucket].hopinfo; + for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) { + if (hopinfo & 1) { + const uint32_t bidx = (bucket + idx) & idxmask; + void *data = rt->buckets[bidx].data; + if (data && rt->equals (data, template)) { + rt->buckets[bidx].data = NULL; + rt->buckets[bucket].hopinfo &= ~(1u << idx); + return 1; + } + } + } + return 0; +} + +void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg) +{ + uint32_t i; + for (i = 0; i < rt->size; i++) { + void *data = rt->buckets[i].data; + if (data) { + f (data, f_arg); + } + } +} + +void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter) +{ + iter->hh = rt; + iter->cursor = 0; + return ddsrt_hh_iter_next (iter); +} + +void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter) +{ + struct ddsrt_hh *rt = iter->hh; + while (iter->cursor < rt->size) { + void *data = rt->buckets[iter->cursor].data; + iter->cursor++; + if (data) { + return data; + } + } + return NULL; +} + /********** CONCURRENT VERSION ************/ +#if ! ddsrt_has_feature_thread_sanitizer + #define N_BACKING_LOCKS 32 #define N_RESIZE_LOCKS 8 @@ -51,6 +299,7 @@ struct ddsrt_chh { ddsrt_hh_equals_fn equals; ddsrt_rwlock_t resize_locks[N_RESIZE_LOCKS]; ddsrt_hh_buckets_gc_fn gc_buckets; + void *gc_buckets_arg; }; #define CHH_MAX_TRIES 4 @@ -61,7 +310,7 @@ static int ddsrt_chh_data_valid_p (void *data) return data != NULL && data != CHH_BUSY; } -static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets) +static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg) { uint32_t size; uint32_t i; @@ -74,6 +323,7 @@ static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_ha rt->hash = hash; rt->equals = equals; rt->gc_buckets = gc_buckets; + rt->gc_buckets_arg = gc_buckets_arg; buckets = ddsrt_malloc (offsetof (struct ddsrt_chh_bucket_array, bs) + size * sizeof (*buckets->bs)); ddsrt_atomic_stvoidp (&rt->buckets, buckets); @@ -111,10 +361,10 @@ static void ddsrt_chh_fini (struct ddsrt_chh *rt) } } -struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets) +struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets, void *gc_buckets_arg) { struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh)); - if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets) < 0) { + if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets, gc_buckets_arg) < 0) { ddsrt_free (hh); return NULL; } else { @@ -228,7 +478,7 @@ static void *ddsrt_chh_lookup_internal (struct ddsrt_chh_bucket_array const * co #define ddsrt_atomic_rmw32_nonatomic(var_, tmp_, expr_) do { \ ddsrt_atomic_uint32_t *var__ = (var_); \ - uint32_t tmp_ = ddsrt_atomic_ld32 (var__); \ + uint32_t tmp_ = ddsrt_atomic_ld32 (var__); \ ddsrt_atomic_st32 (var__, (expr_)); \ } while (0) @@ -324,7 +574,7 @@ static void ddsrt_chh_resize (struct ddsrt_chh *rt) ddsrt_atomic_fence (); ddsrt_atomic_stvoidp (&rt->buckets, bsary1); - rt->gc_buckets (bsary0); + rt->gc_buckets (bsary0, rt->gc_buckets_arg); } int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data) @@ -467,224 +717,78 @@ void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_i return ddsrt_chh_iter_next (it); } -/************* SEQUENTIAL VERSION ***************/ +#else -struct ddsrt_hh_bucket { - uint32_t hopinfo; - void *data; +struct ddsrt_chh { + ddsrt_mutex_t lock; + struct ddsrt_hh rt; }; -struct ddsrt_hh { - uint32_t size; /* power of 2 */ - struct ddsrt_hh_bucket *buckets; - ddsrt_hh_hash_fn hash; - ddsrt_hh_equals_fn equals; -}; - -static void ddsrt_hh_init (struct ddsrt_hh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals) +struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc) { - uint32_t size = HH_HOP_RANGE; - uint32_t i; - while (size < init_size) { - size *= 2; - } - rt->hash = hash; - rt->equals = equals; - rt->size = size; - rt->buckets = ddsrt_malloc (size * sizeof (*rt->buckets)); - for (i = 0; i < size; i++) { - rt->buckets[i].hopinfo = 0; - rt->buckets[i].data = NULL; - } + struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh)); + (void) gc; + ddsrt_mutex_init (&hh->lock); + ddsrt_hh_init (&hh->rt, init_size, hash, equals); + return hh; } -static void ddsrt_hh_fini (struct ddsrt_hh *rt) +void ddsrt_chh_free (struct ddsrt_chh * __restrict hh) { - ddsrt_free (rt->buckets); + ddsrt_hh_fini (&hh->rt); + ddsrt_mutex_destroy (&hh->lock); + ddsrt_free (hh); } -struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals) +void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict hh, const void * __restrict template) { - struct ddsrt_hh *hh = ddsrt_malloc (sizeof (*hh)); - ddsrt_hh_init (hh, init_size, hash, equals); - return hh; + ddsrt_mutex_lock (&hh->lock); + void *x = ddsrt_hh_lookup (&hh->rt, template); + ddsrt_mutex_unlock (&hh->lock); + return x; } -void ddsrt_hh_free (struct ddsrt_hh * __restrict hh) +int ddsrt_chh_add (struct ddsrt_chh * __restrict hh, const void * __restrict data) { - ddsrt_hh_fini (hh); - ddsrt_free (hh); + ddsrt_mutex_lock (&hh->lock); + int x = ddsrt_hh_add (&hh->rt, data); + ddsrt_mutex_unlock (&hh->lock); + return x; } -static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t bucket, const void *template) +int ddsrt_chh_remove (struct ddsrt_chh * __restrict hh, const void * __restrict template) { - const uint32_t idxmask = rt->size - 1; - uint32_t hopinfo = rt->buckets[bucket].hopinfo; - uint32_t idx; - for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) { - const uint32_t bidx = (bucket + idx) & idxmask; - void *data = rt->buckets[bidx].data; - if (data && rt->equals (data, template)) - return data; - } - return NULL; + ddsrt_mutex_lock (&hh->lock); + int x = ddsrt_hh_remove (&hh->rt, template); + ddsrt_mutex_unlock (&hh->lock); + return x; } -void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template) +void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict hh, void (*f) (void *a, void *f_arg), void *f_arg) { - const uint32_t hash = rt->hash (template); - const uint32_t idxmask = rt->size - 1; - const uint32_t bucket = hash & idxmask; - return ddsrt_hh_lookup_internal (rt, bucket, template); + ddsrt_mutex_lock (&hh->lock); + ddsrt_hh_enum (&hh->rt, f, f_arg); + ddsrt_mutex_unlock (&hh->lock); } -static uint32_t ddsrt_hh_find_closer_free_bucket (struct ddsrt_hh *rt, uint32_t free_bucket, uint32_t *free_distance) +void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict hh, struct ddsrt_chh_iter *it) { - const uint32_t idxmask = rt->size - 1; - uint32_t move_bucket, free_dist; - move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask; - for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) { - uint32_t move_free_distance = NOT_A_BUCKET; - uint32_t mask = 1; - uint32_t i; - for (i = 0; i < free_dist; i++, mask <<= 1) { - if (mask & rt->buckets[move_bucket].hopinfo) { - move_free_distance = i; - break; - } - } - if (move_free_distance != NOT_A_BUCKET) { - uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask; - rt->buckets[move_bucket].hopinfo |= 1u << free_dist; - rt->buckets[free_bucket].data = rt->buckets[new_free_bucket].data; - rt->buckets[new_free_bucket].data = NULL; - rt->buckets[move_bucket].hopinfo &= ~(1u << move_free_distance); - *free_distance -= free_dist - move_free_distance; - return new_free_bucket; - } - move_bucket = (move_bucket + 1) & idxmask; - } - return NOT_A_BUCKET; + ddsrt_mutex_lock (&hh->lock); + it->chh = hh; + void *x = ddsrt_hh_iter_first (&hh->rt, &it->it); + ddsrt_mutex_unlock (&hh->lock); + return x; } -static void ddsrt_hh_resize (struct ddsrt_hh *rt) +void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it) { - struct ddsrt_hh_bucket *bs1; - uint32_t i, idxmask0, idxmask1; - - bs1 = ddsrt_malloc (2 * rt->size * sizeof (*rt->buckets)); - - for (i = 0; i < 2 * rt->size; i++) { - bs1[i].hopinfo = 0; - bs1[i].data = NULL; - } - idxmask0 = rt->size - 1; - idxmask1 = 2 * rt->size - 1; - for (i = 0; i < rt->size; i++) { - void *data = rt->buckets[i].data; - if (data) { - const uint32_t hash = rt->hash (data); - const uint32_t old_start_bucket = hash & idxmask0; - const uint32_t new_start_bucket = hash & idxmask1; - const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket); - const uint32_t newb = (new_start_bucket + dist) & idxmask1; - assert (dist < HH_HOP_RANGE); - bs1[new_start_bucket].hopinfo |= 1u << dist; - bs1[newb].data = data; - } - } - - ddsrt_free (rt->buckets); - rt->size *= 2; - rt->buckets = bs1; + ddsrt_mutex_lock (&it->chh->lock); + void *x = ddsrt_hh_iter_next (&it->it); + ddsrt_mutex_unlock (&it->chh->lock); + return x; } -int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data) -{ - const uint32_t hash = rt->hash (data); - const uint32_t idxmask = rt->size - 1; - const uint32_t start_bucket = hash & idxmask; - uint32_t free_distance, free_bucket; - - if (ddsrt_hh_lookup_internal (rt, start_bucket, data)) { - return 0; - } - - free_bucket = start_bucket; - for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) { - if (rt->buckets[free_bucket].data == NULL) - break; - free_bucket = (free_bucket + 1) & idxmask; - } - if (free_distance < HH_ADD_RANGE) { - do { - if (free_distance < HH_HOP_RANGE) { - assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask)); - rt->buckets[start_bucket].hopinfo |= 1u << free_distance; - rt->buckets[free_bucket].data = (void *) data; - return 1; - } - free_bucket = ddsrt_hh_find_closer_free_bucket (rt, free_bucket, &free_distance); - assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask); - } while (free_bucket != NOT_A_BUCKET); - } - - ddsrt_hh_resize (rt); - return ddsrt_hh_add (rt, data); -} - -int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template) -{ - const uint32_t hash = rt->hash (template); - const uint32_t idxmask = rt->size - 1; - const uint32_t bucket = hash & idxmask; - uint32_t hopinfo; - uint32_t idx; - hopinfo = rt->buckets[bucket].hopinfo; - for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) { - if (hopinfo & 1) { - const uint32_t bidx = (bucket + idx) & idxmask; - void *data = rt->buckets[bidx].data; - if (data && rt->equals (data, template)) { - rt->buckets[bidx].data = NULL; - rt->buckets[bucket].hopinfo &= ~(1u << idx); - return 1; - } - } - } - return 0; -} - -void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg) -{ - uint32_t i; - for (i = 0; i < rt->size; i++) { - void *data = rt->buckets[i].data; - if (data) { - f (data, f_arg); - } - } -} - -void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter) -{ - iter->hh = rt; - iter->cursor = 0; - return ddsrt_hh_iter_next (iter); -} - -void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter) -{ - struct ddsrt_hh *rt = iter->hh; - while (iter->cursor < rt->size) { - void *data = rt->buckets[iter->cursor].data; - iter->cursor++; - if (data) { - return data; - } - } - return NULL; -} +#endif /************* SEQUENTIAL VERSION WITH EMBEDDED DATA ***************/ diff --git a/src/ddsrt/src/ifaddrs/lwip/ifaddrs.c b/src/ddsrt/src/ifaddrs/lwip/ifaddrs.c new file mode 100644 index 0000000..68b4401 --- /dev/null +++ b/src/ddsrt/src/ifaddrs/lwip/ifaddrs.c @@ -0,0 +1,208 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include /* netif_list */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/ifaddrs.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/string.h" + +extern const int *const os_supp_afs; + +static uint32_t +getflags( + const struct netif *netif, + const ip_addr_t *addr) +{ + uint32_t flags = 0; + + if (netif->flags & NETIF_FLAG_UP) { + flags |= IFF_UP; + } + if (netif->flags & NETIF_FLAG_BROADCAST) { + flags |= IFF_BROADCAST; + } + if (netif->flags & NETIF_FLAG_IGMP) { + flags |= IFF_MULTICAST; + } + if (ip_addr_isloopback(addr)) { + flags |= IFF_LOOPBACK; + } + + return flags; +} + +static void +sockaddr_from_ip_addr( + struct sockaddr *sockaddr, + const ip_addr_t *addr) +{ + if (IP_IS_V4(addr)) { + memset(sockaddr, 0, sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)sockaddr)->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)sockaddr)->sin_family = AF_INET; + inet_addr_from_ip4addr(&((struct sockaddr_in *)sockaddr)->sin_addr, addr); +#if DDSRT_HAVE_IPV6 + } else { + assert(IP_IS_V6(addr)); + memset(sockaddr, 0, sizeof(struct sockaddr_in6)); + ((struct sockaddr_in6 *)sockaddr)->sin6_len = sizeof(struct sockaddr_in6); + ((struct sockaddr_in6 *)sockaddr)->sin6_family = AF_INET6; + inet6_addr_from_ip6addr(&((struct sockaddr_in6 *)sockaddr)->sin6_addr, addr); +#endif + } +} + +static dds_return_t +copyaddr( + ddsrt_ifaddrs_t **ifap, + const struct netif *netif, + const ip_addr_t *addr) +{ + dds_return_t rc = DDS_RETCODE_OK; + ddsrt_ifaddrs_t *ifa; + struct sockaddr_storage sa; + + assert(ifap != NULL); + assert(netif != NULL); + assert(addr != NULL); + + sockaddr_from_ip_addr((struct sockaddr *)&sa, addr); + + /* Network interface name is of the form "et0", where the first two letters + are the "name" field and the digit is the num field of the netif + structure as described in lwip/netif.h */ + + if ((ifa = ddsrt_calloc_s(1, sizeof(*ifa))) == NULL || + (ifa->addr = ddsrt_memdup(&sa, sa.s2_len)) == NULL || + (ddsrt_asprintf(&ifa->name, "%s%d", netif->name, netif->num) == -1)) + { + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + ifa->flags = getflags(netif, addr); + ifa->index = netif->num; + ifa->type = DDSRT_IFTYPE_UNKNOWN; + + if (IP_IS_V4(addr)) { + static const size_t sz = sizeof(struct sockaddr_in); + if ((ifa->netmask = ddsrt_calloc_s(1, sz)) == NULL || + (ifa->broadaddr = ddsrt_calloc_s(1, sz)) == NULL) + { + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + ip_addr_t broadaddr = IPADDR4_INIT( + ip_2_ip4(&netif->ip_addr)->addr | + ip_2_ip4(&netif->netmask)->addr); + + sockaddr_from_ip_addr((struct sockaddr*)ifa->netmask, &netif->netmask); + sockaddr_from_ip_addr((struct sockaddr*)ifa->broadaddr, &broadaddr); + } + } + } + + if (rc == DDS_RETCODE_OK) { + *ifap = ifa; + } else { + ddsrt_freeifaddrs(ifa); + } + + return rc; +} + +dds_return_t +ddsrt_getifaddrs( + ddsrt_ifaddrs_t **ifap, + const int *afs) +{ + dds_return_t rc = DDS_RETCODE_OK; + int use_ip4, use_ip6; + struct netif *netif; + ddsrt_ifaddrs_t *ifa, *next_ifa, *root_ifa; + + assert(ifap != NULL); + + if (afs == NULL) { + afs = os_supp_afs; + } + + use_ip4 = use_ip6 = 0; + for (int i = 0; afs[i] != DDSRT_AF_TERM; i++) { + if (afs[i] == AF_INET) { + use_ip4 = 1; + } else if (afs[i] == AF_INET6) { + use_ip6 = 1; + } + } + + ifa = next_ifa = root_ifa = NULL; + + for (netif = netif_list; + netif != NULL && rc == DDS_RETCODE_OK; + netif = netif->next) + { + if (use_ip4 && IP_IS_V4(&netif->ip_addr)) { + rc = copyaddr(&next_ifa, netif, &netif->ip_addr); + if (rc == DDS_RETCODE_OK) { + if (ifa == NULL) { + ifa = root_ifa = next_ifa; + } else { + ifa->next = next_ifa; + ifa = next_ifa; + } + } + } + +#if DDSRT_HAVE_IPV6 + if (use_ip6) { + int pref = 1; +again: + /* List preferred IPv6 address first. */ + for (int i = 0; + i < LWIP_IPV6_NUM_ADDRESSES && rc == DDS_RETCODE_OK; + i++) + { + if ((ip6_addr_ispreferred(netif->ip_addr_state[i]) && pref) || + (ip6_addr_isvalid(netif->ip_addr_state[i]) && !pref)) + { + rc = copyaddr(&next_ifa, netif, &netif->ip_addr[i]); + if (rc == DDS_RETCODE_OK) { + if (ifa == NULL) { + ifa = root_ifa = next_ifa; + } else { + ifa->next = next_ifa; + ifa = next_ifa; + } + } + } + } + + if (rc == DDS_RETCODE_OK && pref) { + pref = 0; + goto again; + } + } +#endif + } + + if (rc == DDS_RETCODE_OK) { + *ifap = ifa; + } else { + ddsrt_freeifaddrs(root_ifa); + } + + return rc; +} diff --git a/src/ddsrt/src/ifaddrs/posix/ifaddrs.c b/src/ddsrt/src/ifaddrs/posix/ifaddrs.c index 88606b1..8bf8f52 100644 --- a/src/ddsrt/src/ifaddrs/posix/ifaddrs.c +++ b/src/ddsrt/src/ifaddrs/posix/ifaddrs.c @@ -21,10 +21,115 @@ extern const int *const os_supp_afs; -static dds_retcode_t -copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa) +#if defined __linux +#include + +static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa) { - dds_retcode_t err = DDS_RETCODE_OK; + FILE *fp; + char ifnam[IFNAMSIZ + 1]; /* not sure whether IFNAMSIZ includes a terminating 0, can't be bothered */ + int c; + size_t np; + enum ddsrt_iftype type = DDSRT_IFTYPE_UNKNOWN; + if ((fp = fopen ("/proc/net/wireless", "r")) == NULL) + return type; + /* expected format: + :Inter-| sta-| Quality | Discarded packets | Missed | WE + : face | tus | link level noise | nwid crypt frag retry misc | beacon | 22 + : wlan0: 0000 67. -43. -256 0 0 0 0 0 0 + (where : denotes the start of the line) + + SKIP_HEADER_1 skips up to and including the first newline; then SKIP_TO_EOL skips + up to and including the second newline, so the first line that gets interpreted is + the third. + */ + enum { SKIP_HEADER_1, SKIP_WHITE, READ_NAME, SKIP_TO_EOL } state = SKIP_HEADER_1; + np = 0; + while (type != DDSRT_IFTYPE_WIFI && (c = fgetc (fp)) != EOF) { + switch (state) { + case SKIP_HEADER_1: + if (c == '\n') { + state = SKIP_TO_EOL; + } + break; + case SKIP_WHITE: + if (c != ' ' && c != '\t') { + ifnam[np++] = (char) c; + state = READ_NAME; + } + break; + case READ_NAME: + if (c == ':') { + ifnam[np] = 0; + if (strcmp (ifnam, sys_ifa->ifa_name) == 0) + type = DDSRT_IFTYPE_WIFI; + state = SKIP_TO_EOL; + np = 0; + } else if (np < sizeof (ifnam) - 1) { + ifnam[np++] = (char) c; + } + break; + case SKIP_TO_EOL: + if (c == '\n') { + state = SKIP_WHITE; + } + break; + } + } + fclose (fp); + return type; +} +#elif defined __APPLE__ /* probably works for all BSDs */ +#include +#include +#include +#include + +static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa) +{ + int sock; + if ((sock = socket (sys_ifa->ifa_addr->sa_family, SOCK_DGRAM, 0)) == -1) + return DDSRT_IFTYPE_UNKNOWN; + + struct ifmediareq ifmr; + enum ddsrt_iftype type; + memset (&ifmr, 0, sizeof (ifmr)); + ddsrt_strlcpy (ifmr.ifm_name, sys_ifa->ifa_name, sizeof (ifmr.ifm_name)); + if (ioctl (sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) + { + type = DDSRT_IFTYPE_UNKNOWN; + } + else + { + switch (IFM_TYPE (ifmr.ifm_active)) + { + case IFM_ETHER: + case IFM_TOKEN: + case IFM_FDDI: + type = DDSRT_IFTYPE_WIRED; + break; + case IFM_IEEE80211: + type = DDSRT_IFTYPE_WIFI; + break; + default: + type = DDSRT_IFTYPE_UNKNOWN; + break; + } + } + close (sock); + return type; +} +#else +static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa) +{ + return DDSRT_IFTYPE_UNKNOWN; +} +#endif + +static dds_return_t +copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa, enum ddsrt_iftype type) +{ + dds_return_t err = DDS_RETCODE_OK; ddsrt_ifaddrs_t *ifa; size_t sz; @@ -37,6 +142,7 @@ copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa) err = DDS_RETCODE_OUT_OF_RESOURCES; } else { ifa->index = if_nametoindex(sys_ifa->ifa_name); + ifa->type = type; ifa->flags = sys_ifa->ifa_flags; if ((ifa->name = ddsrt_strdup(sys_ifa->ifa_name)) == NULL || (ifa->addr = ddsrt_memdup(sys_ifa->ifa_addr, sz)) == NULL || @@ -64,12 +170,12 @@ copyaddr(ddsrt_ifaddrs_t **ifap, const struct ifaddrs *sys_ifa) return err; } -dds_retcode_t +dds_return_t ddsrt_getifaddrs( ddsrt_ifaddrs_t **ifap, const int *afs) { - dds_retcode_t err = DDS_RETCODE_OK; + dds_return_t err = DDS_RETCODE_OK; int use; ddsrt_ifaddrs_t *ifa, *ifa_root, *ifa_next; struct ifaddrs *sys_ifa, *sys_ifa_root; @@ -109,7 +215,8 @@ ddsrt_getifaddrs( } if (use) { - err = copyaddr(&ifa_next, sys_ifa); + enum ddsrt_iftype type = guess_iftype (sys_ifa); + err = copyaddr(&ifa_next, sys_ifa, type); if (err == DDS_RETCODE_OK) { if (ifa == NULL) { ifa = ifa_root = ifa_next; diff --git a/src/ddsrt/src/ifaddrs/solaris2.6/ifaddrs.c b/src/ddsrt/src/ifaddrs/solaris2.6/ifaddrs.c new file mode 100644 index 0000000..11e2231 --- /dev/null +++ b/src/ddsrt/src/ifaddrs/solaris2.6/ifaddrs.c @@ -0,0 +1,84 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "dds/ddsrt/ifaddrs.h" +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/string.h" + +extern const int *const os_supp_afs; + +#include +#include +#include +#include + +dds_return_t +ddsrt_getifaddrs( + ddsrt_ifaddrs_t **ret_ifap, + const int *afs) +{ + int sock; + char *buf; + int32_t n; + struct ifconf ifc; + struct ifreq *ifr; + + /* get interfaces */ + buf = ddsrt_malloc (8192); + memset (&ifc, 0, sizeof (ifc)); + ifc.ifc_len = 8192; + ifc.ifc_buf = buf; + sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) + { + perror ("ioctl (SIOCGIFCONF)"); + exit (77); + } + + ddsrt_ifaddrs_t **ifap, *ifa_root; + ifap = &ifa_root; ifa_root = NULL; + ifr = ifc.ifc_req; + for (n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++) + { + ddsrt_ifaddrs_t *ifa; + if (ifr->ifr_name[0] == '\0') + continue; /* Forget about anonymous network devices */ + + if (ifr->ifr_addr.sa_family != AF_INET) { + printf ("%s: not INET\n", ifr->ifr_name); + continue; + } + + ifa = ddsrt_malloc (sizeof (*ifa)); + memset (ifa, 0, sizeof (*ifa)); + ifa->index = (int) (ifr - ifc.ifc_req); + ifa->flags = IFF_UP | ((strcmp(ifr->ifr_name, "lo0")==0) ? IFF_LOOPBACK : IFF_MULTICAST); + ifa->name = strdup (ifr->ifr_name); + ifa->addr = ddsrt_memdup (&ifr->ifr_addr, sizeof (struct sockaddr_in)); + ifa->netmask = ddsrt_memdup (&ifr->ifr_addr, sizeof (struct sockaddr_in)); + ((struct sockaddr_in *) ifa->netmask)->sin_addr.s_addr = htonl (0xffffff00); + ifa->broadaddr = NULL; + ifa->next = NULL; + *ifap = ifa; + ifap = &ifa->next; + } + + ddsrt_free (buf); + close (sock); + *ret_ifap = ifa_root; + return DDS_RETCODE_OK; +} diff --git a/src/ddsrt/src/ifaddrs/windows/ifaddrs.c b/src/ddsrt/src/ifaddrs/windows/ifaddrs.c index 1bd41da..7c5045c 100644 --- a/src/ddsrt/src/ifaddrs/windows/ifaddrs.c +++ b/src/ddsrt/src/ifaddrs/windows/ifaddrs.c @@ -23,10 +23,10 @@ extern const int *const os_supp_afs; -static dds_retcode_t +static dds_return_t getifaces(PIP_ADAPTER_ADDRESSES *ptr) { - dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE; + dds_return_t err = DDS_RETCODE_NOT_ENOUGH_SPACE; PIP_ADAPTER_ADDRESSES buf = NULL; ULONG bufsz = 0; /* Size is determined on first iteration. */ ULONG ret; @@ -72,10 +72,10 @@ getifaces(PIP_ADAPTER_ADDRESSES *ptr) return err; } -static dds_retcode_t +static dds_return_t getaddrtable(PMIB_IPADDRTABLE *ptr) { - dds_retcode_t err = DDS_RETCODE_NOT_ENOUGH_SPACE; + dds_return_t err = DDS_RETCODE_NOT_ENOUGH_SPACE; PMIB_IPADDRTABLE buf = NULL; ULONG bufsz = 0; DWORD ret; @@ -152,6 +152,21 @@ getflags(const PIP_ADAPTER_ADDRESSES iface) return flags; } +static enum ddsrt_iftype +guess_iftype (const PIP_ADAPTER_ADDRESSES iface) +{ + switch (iface->IfType) { + case IF_TYPE_IEEE80211: + return DDSRT_IFTYPE_WIFI; + case IF_TYPE_ETHERNET_CSMACD: + case IF_TYPE_IEEE1394: + case IF_TYPE_ISO88025_TOKENRING: + return DDSRT_IFTYPE_WIRED; + default: + return DDSRT_IFTYPE_UNKNOWN; + } +} + static int copyaddr( ddsrt_ifaddrs_t **ifap, @@ -159,7 +174,7 @@ copyaddr( const PMIB_IPADDRTABLE addrtable, const PIP_ADAPTER_UNICAST_ADDRESS addr) { - dds_retcode_t err = DDS_RETCODE_OK; + dds_return_t err = DDS_RETCODE_OK; ddsrt_ifaddrs_t *ifa; struct sockaddr *sa; size_t sz; @@ -175,6 +190,7 @@ copyaddr( err = DDS_RETCODE_OUT_OF_RESOURCES; } else { ifa->flags = getflags(iface); + ifa->type = guess_iftype(iface); ifa->addr = ddsrt_memdup(sa, sz); (void)ddsrt_asprintf(&ifa->name, "%wS", iface->FriendlyName); if (ifa->addr == NULL || ifa->name == NULL) { @@ -220,7 +236,7 @@ copyaddr( return err; } -dds_retcode_t +dds_return_t ddsrt_getifaddrs( ddsrt_ifaddrs_t **ifap, const int *afs) diff --git a/src/ddsrt/src/log.c b/src/ddsrt/src/log.c index 558f56e..b7aef78 100644 --- a/src/ddsrt/src/log.c +++ b/src/ddsrt/src/log.c @@ -18,10 +18,12 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" +#include "dds/ddsrt/static_assert.h" +#define MAX_ID_LEN (10) #define MAX_TIMESTAMP_LEN (10 + 1 + 6) #define MAX_TID_LEN (10) -#define HDR_LEN (MAX_TIMESTAMP_LEN + 1 + MAX_TID_LEN + 2) +#define HDR_LEN (MAX_TIMESTAMP_LEN + 2 + MAX_ID_LEN + 2 + MAX_TID_LEN + 2) #define BUF_OFFSET HDR_LEN @@ -31,7 +33,7 @@ typedef struct { } log_buffer_t; typedef struct { - dds_log_write_fn_t funcs[2]; + dds_log_write_fn_t func; void *ptr; FILE *out; } log_sink_t; @@ -41,50 +43,58 @@ static ddsrt_thread_local log_buffer_t log_buffer; static ddsrt_once_t lock_inited = DDSRT_ONCE_INIT; static ddsrt_rwlock_t lock; -static uint32_t log_mask = DDS_LC_ERROR | DDS_LC_WARNING; +struct ddsrt_log_cfg_impl { + struct ddsrt_log_cfg_common c; + FILE *sink_fps[2]; +}; -static void default_sink(void *ptr, const dds_log_data_t *data) -{ - fwrite(data->message - HDR_LEN, 1, HDR_LEN + data->size + 1, (FILE *)ptr); - fflush((FILE *)ptr); -} +DDSRT_STATIC_ASSERT (sizeof (struct ddsrt_log_cfg_impl) <= sizeof (struct ddsrt_log_cfg)); -static void nop_sink(void *ptr, const dds_log_data_t *data) +static void default_sink (void *ptr, const dds_log_data_t *data) { - (void)ptr; - (void)data; - return; + if (ptr) + { + fwrite (data->message - data->hdrsize, 1, data->hdrsize + data->size + 1, (FILE *) ptr); + fflush ((FILE *) ptr); + } } #define LOG (0) #define TRACE (1) -#define USE (0) -#define SET (1) -static log_sink_t sinks[] = { - /* Log */ - { .funcs = { default_sink, default_sink }, .ptr = NULL, .out = NULL }, - /* Trace */ - { .funcs = { nop_sink, default_sink }, .ptr = NULL, .out = NULL } +static struct ddsrt_log_cfg_impl logconfig = { + .c = { + .mask = DDS_LC_ERROR | DDS_LC_WARNING, + .tracemask = 0, + .domid = UINT32_MAX + }, + .sink_fps = { + [LOG] = NULL, + [TRACE] = NULL + } }; -uint32_t *const dds_log_mask = &log_mask; +static log_sink_t sinks[2] = { + [LOG] = { .func = default_sink, .ptr = NULL, .out = NULL }, + [TRACE] = { .func = default_sink, .ptr = NULL, .out = NULL } +}; -#define RDLOCK (1) -#define WRLOCK (2) +uint32_t * const dds_log_mask = &logconfig.c.mask; -static void init_lock(void) +static void init_lock (void) { - ddsrt_rwlock_init(&lock); + ddsrt_rwlock_init (&lock); sinks[LOG].ptr = sinks[TRACE].ptr = stderr; sinks[LOG].out = sinks[TRACE].out = stderr; + logconfig.sink_fps[LOG] = sinks[LOG].ptr; + logconfig.sink_fps[TRACE] = sinks[TRACE].ptr; } -static void lock_sink(int type) -{ - assert(type == RDLOCK || type == WRLOCK); - ddsrt_once(&lock_inited, &init_lock); +enum lock_type { RDLOCK, WRLOCK }; +static void lock_sink (enum lock_type type) +{ + ddsrt_once (&lock_inited, &init_lock); if (type == RDLOCK) { ddsrt_rwlock_read(&lock); } else { @@ -92,154 +102,134 @@ static void lock_sink(int type) } } -static void unlock_sink(void) +static void unlock_sink (void) { - ddsrt_rwlock_unlock(&lock); + ddsrt_rwlock_unlock (&lock); } -static void set_active_log_sinks(void) +static void set_log_sink (log_sink_t *sink, dds_log_write_fn_t func, void *ptr) { - if (dds_get_log_mask() & DDS_LOG_MASK) { - sinks[LOG].funcs[USE] = sinks[LOG].funcs[SET]; - } else { - sinks[LOG].funcs[USE] = nop_sink; - } - if (dds_get_log_mask() & DDS_TRACE_MASK) { - sinks[TRACE].funcs[USE] = sinks[TRACE].funcs[SET]; - } else { - sinks[TRACE].funcs[USE] = nop_sink; - } - if (sinks[LOG].funcs[USE] == sinks[TRACE].funcs[USE] && - sinks[LOG].ptr == sinks[TRACE].ptr) - { - sinks[LOG].funcs[USE] = nop_sink; - } -} - -static void -set_log_sink( - log_sink_t *sink, - dds_log_write_fn_t func, - void *ptr) -{ - assert(sink != NULL); + assert (sink != NULL); + assert (sink == &sinks[0] || sink == &sinks[1]); /* No life cycle management is done for log sinks, the caller is responsible for that. Ensure this operation is deterministic and that on return, no thread in the DDS stack still uses the deprecated sink. */ - lock_sink(WRLOCK); - - if (func == 0) { - sink->funcs[SET] = default_sink; - sink->ptr = sink->out; - } else { - sink->funcs[SET] = func; - sink->ptr = ptr; - } - - set_active_log_sinks(); - unlock_sink(); + lock_sink (WRLOCK); + sink->func = (func != 0) ? func : default_sink; + sink->ptr = ptr; + unlock_sink (); } /* dds_set_log_file must be considered private. */ -void dds_set_log_file(FILE *file) +void dds_set_log_file (FILE *file) { - lock_sink(WRLOCK); - sinks[LOG].out = (file == NULL ? stderr : file); - if (sinks[LOG].funcs[SET] == default_sink) { - sinks[LOG].ptr = sinks[LOG].out; - } - set_active_log_sinks(); - unlock_sink(); + lock_sink (WRLOCK); + logconfig.sink_fps[LOG] = (file == NULL ? stderr : file); + unlock_sink (); } -void dds_set_trace_file(FILE *file) +void dds_set_trace_file (FILE *file) { - lock_sink(WRLOCK); - sinks[TRACE].out = (file == NULL ? stderr : file); - if (sinks[TRACE].funcs[SET] == default_sink) { - sinks[TRACE].ptr = sinks[TRACE].out; - } - set_active_log_sinks(); - unlock_sink(); + lock_sink (WRLOCK); + logconfig.sink_fps[TRACE] = (file == NULL ? stderr : file); + unlock_sink (); } -void dds_set_log_sink( - dds_log_write_fn_t callback, - void *userdata) +void dds_set_log_sink (dds_log_write_fn_t callback, void *userdata) { - set_log_sink(&sinks[LOG], callback, userdata); + set_log_sink (&sinks[LOG], callback, userdata); } -void dds_set_trace_sink( - dds_log_write_fn_t callback, - void *userdata) +void dds_set_trace_sink (dds_log_write_fn_t callback, void *userdata) { - set_log_sink(&sinks[TRACE], callback, userdata); + set_log_sink (&sinks[TRACE], callback, userdata); } -extern inline uint32_t -dds_get_log_mask(void); +extern inline uint32_t dds_get_log_mask (void); -void -dds_set_log_mask(uint32_t cats) +void dds_set_log_mask (uint32_t cats) { - lock_sink(WRLOCK); - *dds_log_mask = (cats & (DDS_LOG_MASK | DDS_TRACE_MASK)); - set_active_log_sinks(); - unlock_sink(); + lock_sink (WRLOCK); + logconfig.c.tracemask = cats & DDS_TRACE_MASK; + logconfig.c.mask = (cats & (DDS_LOG_MASK | DDS_TRACE_MASK)) | DDS_LC_FATAL; + unlock_sink (); } -static void print_header(char *str) +void dds_log_cfg_init (struct ddsrt_log_cfg *cfg, uint32_t domid, uint32_t tracemask, FILE *log_fp, FILE *trace_fp) { - int cnt; + struct ddsrt_log_cfg_impl *cfgimpl = (struct ddsrt_log_cfg_impl *) cfg; + assert (domid != UINT32_MAX); /* because that's reserved for global use */ + memset (cfgimpl, 0, sizeof (*cfgimpl)); + cfgimpl->c.mask = tracemask | DDS_LOG_MASK; + cfgimpl->c.tracemask = tracemask; + cfgimpl->c.domid = domid; + cfgimpl->sink_fps[LOG] = log_fp; + cfgimpl->sink_fps[TRACE] = trace_fp; +} + +static size_t print_header (char *str, uint32_t id) +{ + int cnt, off; char *tid, buf[MAX_TID_LEN+1] = { 0 }; - static const char fmt[] = "%10u.%06d/%*.*s:"; + static const char fmt_no_id[] = "%10u.%06d [] %*.*s:"; + static const char fmt_with_id[] = "%10u.%06d [%"PRIu32"] %*.*s:"; dds_time_t time; unsigned sec; int usec; - (void)ddsrt_thread_getname(buf, sizeof(buf)); + (void) ddsrt_thread_getname (buf, sizeof (buf)); tid = (buf[0] == '\0' ? "(anon)" : buf); - time = dds_time(); - sec = (unsigned)(time / DDS_NSECS_IN_SEC); - usec = (int)((time % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC); + time = dds_time (); + sec = (unsigned) (time / DDS_NSECS_IN_SEC); + usec = (int) ((time % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC); - cnt = snprintf( - str, HDR_LEN, fmt, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid); - assert(cnt == (HDR_LEN - 1)); - str[cnt] = ' '; /* Replace snprintf null byte by space. */ + if (id == UINT32_MAX) + { + off = MAX_ID_LEN; + cnt = snprintf (str + off, HDR_LEN, fmt_no_id, sec, usec, MAX_TID_LEN, MAX_TID_LEN, tid); + } + else + { + /* low domain ids tend to be most used from what I have seen */ + off = 9; + if (id >= 10) + for (uint32_t thres = 10; off > 0 && id >= thres; off--, thres *= 10); + cnt = snprintf (str + off, HDR_LEN, fmt_with_id, sec, usec, id, MAX_TID_LEN, MAX_TID_LEN, tid); + } + assert (off + cnt == (HDR_LEN - 1)); + str[off + cnt] = ' '; /* Replace snprintf null byte by space. */ + return (size_t) cnt; } -static void vlog( - uint32_t cat, - const char *file, - uint32_t line, - const char *func, - const char *fmt, - va_list ap) +static void vlog1 (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t domid, const char *file, uint32_t line, const char *func, const char *fmt, va_list ap) { int n, trunc = 0; size_t nrem; log_buffer_t *lb; dds_log_data_t data; + /* id can be used to override the id in logconfig, so that the global + logging configuration can be used for reporting errors while inlcuding + a domain id. This simply verifies that the id override is only ever + used with the global one. */ + assert (domid == cfg->c.domid || cfg == &logconfig); + if (*fmt == 0) { return; } - lock_sink(RDLOCK); lb = &log_buffer; /* Thread-local buffer is always initialized with all zeroes. The pos member must always be greater or equal to BUF_OFFSET. */ if (lb->pos < BUF_OFFSET) { - lb->pos = BUF_OFFSET; - lb->buf[lb->pos] = 0; + lb->pos = BUF_OFFSET; + lb->buf[lb->pos] = 0; } nrem = sizeof (lb->buf) - lb->pos; if (nrem > 0) { - n = vsnprintf(lb->buf + lb->pos, nrem, fmt, ap); + n = vsnprintf (lb->buf + lb->pos, nrem, fmt, ap); if (n >= 0 && (size_t) n < nrem) { lb->pos += (size_t) n; } else { @@ -249,54 +239,89 @@ static void vlog( if (trunc) { static const char msg[] = "(trunc)\n"; const size_t msglen = sizeof (msg) - 1; - assert(lb->pos <= sizeof (lb->buf)); - assert(lb->pos >= msglen); - memcpy(lb->buf + lb->pos - msglen, msg, msglen); + assert (lb->pos <= sizeof (lb->buf)); + assert (lb->pos >= msglen); + memcpy (lb->buf + lb->pos - msglen, msg, msglen); } } - if (fmt[strlen (fmt) - 1] == '\n') { - print_header(lb->buf); + if (fmt[strlen (fmt) - 1] == '\n' && lb->pos > BUF_OFFSET + 1) { + assert (lb->pos > BUF_OFFSET); + size_t hdrsize = print_header (lb->buf, domid); data.priority = cat; data.file = file; data.function = func; data.line = line; data.message = lb->buf + BUF_OFFSET; - data.size = strlen(data.message) - 1; + data.size = lb->pos - BUF_OFFSET - 1; + data.hdrsize = hdrsize; - for (size_t i = (cat & DDS_LOG_MASK) ? LOG : TRACE; - i < sizeof(sinks) / sizeof(sinks[0]); - i++) + dds_log_write_fn_t f = 0; + void *f_arg = NULL; + if (cat & DDS_LOG_MASK) { - sinks[i].funcs[USE](sinks[i].ptr, &data); + f = sinks[LOG].func; + f_arg = (f == default_sink) ? cfg->sink_fps[LOG] : sinks[LOG].ptr; + assert (f != 0); + f (f_arg, &data); + } + /* if tracing is enabled, then print to trace if it matches the + trace flags or if it got written to the log + (mask == (tracemask | DDS_LOG_MASK)) */ + if (cfg->c.tracemask && (cat & cfg->c.mask)) + { + dds_log_write_fn_t const g = sinks[TRACE].func; + void * const g_arg = (g == default_sink) ? cfg->sink_fps[TRACE] : sinks[TRACE].ptr; + assert (g != 0); + if (g != f || g_arg != f_arg) + g (g_arg, &data); } lb->pos = BUF_OFFSET; lb->buf[lb->pos] = 0; } - - unlock_sink(); } -int -dds_log( - uint32_t cat, - const char *file, - uint32_t line, - const char *func, - const char *fmt, - ...) +static void vlog (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t domid, const char *file, uint32_t line, const char *func, const char *fmt, va_list ap) { - if ((dds_get_log_mask() & cat) || (cat & DDS_LC_FATAL)) { - va_list ap; - va_start(ap, fmt); - vlog(cat, file, line, func, fmt, ap); - va_end(ap); - } - if (cat & DDS_LC_FATAL) { + lock_sink (RDLOCK); + vlog1 (cfg, cat, domid, file, line, func, fmt, ap); + unlock_sink (); + if (cat & DDS_LC_FATAL) abort(); - } - - return 0; +} + +void dds_log_cfg (const struct ddsrt_log_cfg *cfg, uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...) +{ + const struct ddsrt_log_cfg_impl *cfgimpl = (const struct ddsrt_log_cfg_impl *) cfg; + /* cfgimpl->c.mask is too weak a test because it has all DDS_LOG_MASK bits set, + rather than just the ones in dds_get_log_mask() (so as not to cache the latter + and have to keep them synchronized */ + if ((cfgimpl->c.mask & cat) && ((dds_get_log_mask () | cfgimpl->c.tracemask) & cat)) { + va_list ap; + va_start (ap, fmt); + vlog (cfgimpl, cat, cfgimpl->c.domid, file, line, func, fmt, ap); + va_end (ap); + } +} + +void dds_log_id (uint32_t cat, uint32_t id, const char *file, uint32_t line, const char *func, const char *fmt, ...) +{ + if (dds_get_log_mask () & cat) { + va_list ap; + va_start (ap, fmt); + vlog (&logconfig, cat, id, file, line, func, fmt, ap); + va_end (ap); + } +} + +void dds_log (uint32_t cat, const char *file, uint32_t line, const char *func, const char *fmt, ...) +{ + if (dds_get_log_mask () & cat) { + va_list ap; + va_start (ap, fmt); + vlog (&logconfig, cat, UINT32_MAX, file, line, func, fmt, ap); + va_end (ap); + } } diff --git a/src/ddsrt/src/netstat/darwin/netstat.c b/src/ddsrt/src/netstat/darwin/netstat.c new file mode 100644 index 0000000..7ffd7c8 --- /dev/null +++ b/src/ddsrt/src/netstat/darwin/netstat.c @@ -0,0 +1,130 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct ddsrt_netstat_control { + char *name; + int cached_row; +}; + +static dds_return_t ddsrt_netstat_get_int (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats) +{ + int name[6]; + size_t len; + int count; + struct ifmibdata ifmd; + + if (control->cached_row > 0) + { + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = control->cached_row; + name[5] = IFDATA_GENERAL; + len = sizeof (ifmd); + if (sysctl (name, 6, &ifmd, &len, NULL, 0) != 0) + control->cached_row = 0; + else if (strcmp (ifmd.ifmd_name, control->name) != 0) + control->cached_row = 0; + } + + if (control->cached_row == 0) + { + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_SYSTEM; + name[4] = IFMIB_IFCOUNT; + len = sizeof (count); + if (sysctl (name, 5, &count, &len, NULL, 0) != 0) + goto error; + for (int row = 1; row <= count; row++) + { + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = row; + name[5] = IFDATA_GENERAL; + len = sizeof (ifmd); + if (sysctl (name, 6, &ifmd, &len, NULL, 0) != 0) + { + if (errno != ENOENT) + goto error; + } + else if (strcmp (control->name, ifmd.ifmd_name) == 0) + { + control->cached_row = row; + break; + } + } + } + + if (control->cached_row == 0) + return DDS_RETCODE_NOT_FOUND; + else + { + stats->ipkt = ifmd.ifmd_data.ifi_ipackets; + stats->opkt = ifmd.ifmd_data.ifi_opackets; + stats->ibytes = ifmd.ifmd_data.ifi_ibytes; + stats->obytes = ifmd.ifmd_data.ifi_obytes; + return DDS_RETCODE_OK; + } + + error: + control->cached_row = -1; + return DDS_RETCODE_ERROR; +} + +dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device) +{ + struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c)); + struct ddsrt_netstat dummy; + c->name = ddsrt_strdup (device); + c->cached_row = 0; + if (ddsrt_netstat_get_int (c, &dummy) != DDS_RETCODE_OK) + { + ddsrt_free (c->name); + ddsrt_free (c); + *control = NULL; + return DDS_RETCODE_ERROR; + } + else + { + *control = c; + return DDS_RETCODE_OK; + } +} + +dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control) +{ + ddsrt_free (control->name); + ddsrt_free (control); + return DDS_RETCODE_OK; +} + +dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats) +{ + if (control->cached_row < 0) + return DDS_RETCODE_ERROR; + else + return ddsrt_netstat_get_int (control, stats); +} diff --git a/src/ddsrt/src/netstat/linux/netstat.c b/src/ddsrt/src/netstat/linux/netstat.c new file mode 100644 index 0000000..b0c2c81 --- /dev/null +++ b/src/ddsrt/src/netstat/linux/netstat.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include + +#include +#include +#include + +struct ddsrt_netstat_control { + char *name; +}; + +dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats) +{ + FILE *fp; + char save[256]; + int c; + size_t np; + int field = 0; + if ((fp = fopen ("/proc/net/dev", "r")) == NULL) + return DDS_RETCODE_ERROR; + /* expected format: 2 header lines, then on each line, white space/interface + name/colon and then numbers. Received bytes is 1st data field, transmitted + bytes is 9th. + + SKIP_HEADER_1 skips up to and including the first newline; then SKIP_TO_EOL + skips up to and including the second newline, so the first line that gets + interpreted is the third. + */ + dds_return_t res = DDS_RETCODE_NOT_FOUND; + enum { SKIP_HEADER_1, SKIP_WHITE, READ_NAME, SKIP_TO_EOL, READ_SEP, READ_INT } state = SKIP_HEADER_1; + np = 0; + while (res == DDS_RETCODE_NOT_FOUND && (c = fgetc (fp)) != EOF) { + switch (state) { + case SKIP_HEADER_1: + if (c == '\n') { + state = SKIP_TO_EOL; + } + break; + case SKIP_WHITE: + if (c != ' ' && c != '\t') { + save[np++] = (char) c; + state = READ_NAME; + } + break; + case READ_NAME: + if (c == ':') { + save[np] = 0; + np = 0; + if (strcmp (save, control->name) != 0) + state = SKIP_TO_EOL; + else + state = READ_SEP; + } else if (np < sizeof (save) - 1) { + save[np++] = (char) c; + } + break; + case SKIP_TO_EOL: + if (c == '\n') { + state = SKIP_WHITE; + } + break; + case READ_SEP: + if (c == '\n') + { + /* unexpected end of line */ + res = DDS_RETCODE_ERROR; + } + else if (c >= '0' && c <= '9') + { + field++; + save[np++] = (char) c; + state = READ_INT; + } + break; + case READ_INT: + if (c >= '0' && c <= '9') + { + if (np == sizeof (save) - 1) + { + res = DDS_RETCODE_ERROR; + break; + } + save[np++] = (char) c; + } + else + { + save[np] = 0; + np = 0; + if (field == 1 || field == 2 || field == 9 || field == 10) + { + int pos; + uint64_t val; + if (sscanf (save, "%"SCNu64"%n", &val, &pos) != 1 || save[pos] != 0) + res = DDS_RETCODE_ERROR; + else + { + switch (field) + { + case 1: stats->ibytes = val; break; + case 2: stats->ipkt = val; break; + case 9: stats->obytes = val; break; + case 10: stats->opkt = val; res = DDS_RETCODE_OK; break; + } + } + } + if (c == '\n' && res != DDS_RETCODE_OK) + { + /* newline before all expected fields have been read */ + res = DDS_RETCODE_ERROR; + } + state = READ_SEP; + } + break; + } + } + fclose (fp); + return res; +} + +dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device) +{ + struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c)); + struct ddsrt_netstat dummy; + c->name = ddsrt_strdup (device); + if (ddsrt_netstat_get (c, &dummy) != DDS_RETCODE_OK) + { + ddsrt_free (c->name); + ddsrt_free (c); + *control = NULL; + return DDS_RETCODE_ERROR; + } + else + { + *control = c; + return DDS_RETCODE_OK; + } +} + +dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control) +{ + ddsrt_free (control->name); + ddsrt_free (control); + return DDS_RETCODE_OK; +} diff --git a/src/ddsrt/src/netstat/windows/netstat.c b/src/ddsrt/src/netstat/windows/netstat.c new file mode 100644 index 0000000..678662c --- /dev/null +++ b/src/ddsrt/src/netstat/windows/netstat.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include + +#include +#include +#include + +struct ddsrt_netstat_control { + wchar_t *name; + bool errored; + bool have_index; + NET_IFINDEX index; +}; + +static void copy_data (struct ddsrt_netstat *dst, const MIB_IF_ROW2 *src) +{ + dst->ipkt = src->InUcastPkts + src->InNUcastPkts; + dst->opkt = src->OutUcastPkts + src->OutNUcastPkts; + dst->ibytes = src->InOctets; + dst->obytes = src->OutOctets; +} + +static bool is_desired_interface (const struct ddsrt_netstat_control *control, const MIB_IF_ROW2 *info) +{ + return wcscmp (control->name, info->Description) == 0 || wcscmp (control->name, info->Alias) == 0; +} + +static dds_return_t ddsrt_netstat_get_int (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats) +{ + if (control->errored) + return DDS_RETCODE_ERROR; + + if (control->have_index) + { + MIB_IF_ROW2 info; + memset (&info, 0, sizeof (info)); + info.InterfaceIndex = control->index; + if (GetIfEntry2 (&info) != NO_ERROR || !is_desired_interface (control, &info)) + control->have_index = false; + else + { + copy_data (stats, &info); + return DDS_RETCODE_OK; + } + } + + MIB_IF_TABLE2 *table; + if (GetIfTable2 (&table) != NO_ERROR) + goto error; + control->have_index = false; + for (ULONG row = 0; row < table->NumEntries; row++) + { + if (is_desired_interface (control, &table->Table[row])) + { + control->index = table->Table[row].InterfaceIndex; + control->have_index = true; + copy_data (stats, &table->Table[row]); + break; + } + } + FreeMibTable (table); + return control->have_index ? DDS_RETCODE_OK : DDS_RETCODE_NOT_FOUND; + + error: + control->errored = true; + return DDS_RETCODE_ERROR; +} + +dds_return_t ddsrt_netstat_new (struct ddsrt_netstat_control **control, const char *device) +{ + struct ddsrt_netstat_control *c = ddsrt_malloc (sizeof (*c)); + struct ddsrt_netstat dummy; + size_t name_size = strlen (device) + 1; + c->name = ddsrt_malloc (name_size * sizeof (*c->name)); + size_t cnt = 0; + mbstowcs_s (&cnt, c->name, name_size, device, _TRUNCATE); + c->have_index = false; + c->errored = false; + c->index = 0; + if (ddsrt_netstat_get_int (c, &dummy) != DDS_RETCODE_OK) + { + ddsrt_free (c->name); + ddsrt_free (c); + *control = NULL; + return DDS_RETCODE_ERROR; + } + else + { + *control = c; + return DDS_RETCODE_OK; + } +} + +dds_return_t ddsrt_netstat_free (struct ddsrt_netstat_control *control) +{ + ddsrt_free (control->name); + ddsrt_free (control); + return DDS_RETCODE_OK; +} + +dds_return_t ddsrt_netstat_get (struct ddsrt_netstat_control *control, struct ddsrt_netstat *stats) +{ + return ddsrt_netstat_get_int (control, stats); +} diff --git a/src/ddsrt/src/process/freertos/process.c b/src/ddsrt/src/process/freertos/process.c new file mode 100644 index 0000000..b299888 --- /dev/null +++ b/src/ddsrt/src/process/freertos/process.c @@ -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 +#include + +ddsrt_pid_t +ddsrt_getpid(void) +{ + return xTaskGetCurrentTaskHandle(); +} + diff --git a/src/ddsrt/src/process/posix/process.c b/src/ddsrt/src/process/posix/process.c index d42877f..f8de0fc 100644 --- a/src/ddsrt/src/process/posix/process.c +++ b/src/ddsrt/src/process/posix/process.c @@ -72,7 +72,7 @@ static void no_op(int sig) } -static dds_retcode_t +static dds_return_t waitpids( ddsrt_pid_t request_pid, dds_duration_t timeout, @@ -81,7 +81,7 @@ waitpids( { struct sigaction sigactold; struct sigaction sigact; - dds_retcode_t rv; + dds_return_t rv; int options = 0; int ret; int s; @@ -148,13 +148,13 @@ waitpids( -dds_retcode_t +dds_return_t ddsrt_proc_create( const char *executable, char *const argv[], ddsrt_pid_t *pid) { - dds_retcode_t rv; + dds_return_t rv; char **exec_argv; int exec_fds[2]; int exec_err; @@ -253,7 +253,7 @@ fail_pipe: -dds_retcode_t +dds_return_t ddsrt_proc_waitpid( ddsrt_pid_t pid, dds_duration_t timeout, @@ -267,7 +267,7 @@ ddsrt_proc_waitpid( -dds_retcode_t +dds_return_t ddsrt_proc_waitpids( dds_duration_t timeout, ddsrt_pid_t *pid, @@ -278,7 +278,7 @@ ddsrt_proc_waitpids( -dds_retcode_t +dds_return_t ddsrt_proc_exists( ddsrt_pid_t pid) { @@ -294,7 +294,7 @@ ddsrt_proc_exists( -dds_retcode_t +dds_return_t ddsrt_proc_kill( ddsrt_pid_t pid) { diff --git a/src/ddsrt/src/process/windows/process.c b/src/ddsrt/src/process/windows/process.c index 91cebec..65c5125 100644 --- a/src/ddsrt/src/process/windows/process.c +++ b/src/ddsrt/src/process/windows/process.c @@ -29,24 +29,24 @@ ddsrt_getpid(void) -static HANDLE pid_to_phdl (ddsrt_pid_t pid); -static dds_retcode_t process_get_exit_code(HANDLE phdl, int32_t *code); -static dds_retcode_t process_kill (HANDLE phdl); -static char* commandline (const char *exe, char *const argv_in[]); -static BOOL child_add (HANDLE phdl); -static void child_remove (HANDLE phdl); -static DWORD child_list (HANDLE *list, DWORD max); -static HANDLE child_handle (ddsrt_pid_t pid); +static HANDLE pid_to_phdl (ddsrt_pid_t pid); +static dds_return_t process_get_exit_code(HANDLE phdl, int32_t *code); +static dds_return_t process_kill (HANDLE phdl); +static char* commandline (const char *exe, char *const argv_in[]); +static BOOL child_add (HANDLE phdl); +static void child_remove (HANDLE phdl); +static DWORD child_list (HANDLE *list, DWORD max); +static HANDLE child_handle (ddsrt_pid_t pid); -dds_retcode_t +dds_return_t ddsrt_proc_create( const char *executable, char *const argv[], ddsrt_pid_t *pid) { - dds_retcode_t rv = DDS_RETCODE_ERROR; + dds_return_t rv = DDS_RETCODE_ERROR; PROCESS_INFORMATION process_info; STARTUPINFO si; char *cmd; @@ -111,13 +111,13 @@ ddsrt_proc_create( -dds_retcode_t +dds_return_t ddsrt_proc_waitpid( ddsrt_pid_t pid, dds_duration_t timeout, int32_t *code) { - dds_retcode_t rv = DDS_RETCODE_OK; + dds_return_t rv = DDS_RETCODE_OK; HANDLE phdl; DWORD ret; @@ -155,13 +155,13 @@ ddsrt_proc_waitpid( -dds_retcode_t +dds_return_t ddsrt_proc_waitpids( dds_duration_t timeout, ddsrt_pid_t *pid, int32_t *code) { - dds_retcode_t rv = DDS_RETCODE_OK; + dds_return_t rv = DDS_RETCODE_OK; HANDLE hdls[MAXIMUM_WAIT_OBJECTS]; HANDLE phdl; DWORD cnt; @@ -208,11 +208,11 @@ ddsrt_proc_waitpids( -dds_retcode_t +dds_return_t ddsrt_proc_exists( ddsrt_pid_t pid) { - dds_retcode_t rv = DDS_RETCODE_NOT_FOUND; + dds_return_t rv = DDS_RETCODE_NOT_FOUND; HANDLE phdl; phdl = pid_to_phdl(pid); @@ -235,11 +235,11 @@ ddsrt_proc_exists( -dds_retcode_t +dds_return_t ddsrt_proc_kill( ddsrt_pid_t pid) { - dds_retcode_t rv = DDS_RETCODE_BAD_PARAMETER; + dds_return_t rv = DDS_RETCODE_BAD_PARAMETER; HANDLE phdl; phdl = pid_to_phdl(pid); @@ -262,12 +262,12 @@ pid_to_phdl(ddsrt_pid_t pid) -static dds_retcode_t +static dds_return_t process_get_exit_code( HANDLE phdl, int32_t *code) { - dds_retcode_t rv = DDS_RETCODE_ERROR; + dds_return_t rv = DDS_RETCODE_ERROR; DWORD tr; assert(phdl != 0); @@ -289,7 +289,7 @@ process_get_exit_code( /* Forcefully kill the given process. */ -static dds_retcode_t +static dds_return_t process_kill(HANDLE phdl) { assert(phdl != 0); diff --git a/src/ddsrt/src/random.c b/src/ddsrt/src/random.c index 7f2943a..b5b2ac6 100644 --- a/src/ddsrt/src/random.c +++ b/src/ddsrt/src/random.c @@ -61,6 +61,7 @@ #include "dds/ddsrt/sync.h" #include "dds/ddsrt/time.h" #include "dds/ddsrt/process.h" +#include "dds/ddsrt/static_assert.h" #define N DDSRT_MT19937_N #define M 397 @@ -186,9 +187,7 @@ void ddsrt_random_init (void) if (!ddsrt_prng_makeseed (&seed)) { /* Poor man's initialisation */ - struct lengthof_seed_large_enough { - char ok[sizeof (seed.key) / sizeof (seed.key[0]) >= 3 ? 1 : -1]; - }; + DDSRT_STATIC_ASSERT (sizeof (seed.key) / sizeof (seed.key[0]) >= 3); memset (&seed, 0, sizeof (seed)); dds_time_t now = dds_time (); seed.key[0] = (uint32_t) ddsrt_getpid (); diff --git a/src/ddsrt/src/retcode.c b/src/ddsrt/src/retcode.c index 6484f23..930a327 100644 --- a/src/ddsrt/src/retcode.c +++ b/src/ddsrt/src/retcode.c @@ -11,8 +11,7 @@ */ #include "dds/ddsrt/retcode.h" -static const char *retcodes[] = -{ +static const char *retcodes[] = { "Success", "Error", "Unsupported", @@ -42,19 +41,20 @@ static const char *xretcodes[] = { "Not found" }; -const char * -dds_strretcode (dds_retcode_t rc) +const char *dds_strretcode (dds_return_t rc) { - if (rc >= 0 && - rc < (dds_retcode_t)(sizeof(retcodes) / sizeof(retcodes[0]))) - { + const dds_return_t nretcodes = (dds_return_t) (sizeof (retcodes) / sizeof (retcodes[0])); + const dds_return_t nxretcodes = (dds_return_t) (sizeof (xretcodes) / sizeof (xretcodes[0])); + /* Retcodes used to be positive, but return values from the API would be a negative + and so there are/were/may be places outside the core library where dds_strretcode + is called with a -N for N a API return value, so ... play it safe and use the + magnitude */ + if (rc < 0) + rc = -rc; + if (rc >= 0 && rc < nretcodes) return retcodes[rc]; - } else if (rc >= (DDS_XRETCODE_BASE) && - rc < (dds_retcode_t)(DDS_XRETCODE_BASE + (sizeof(xretcodes) / sizeof(xretcodes[0])))) - { + else if (rc >= DDS_XRETCODE_BASE && rc < DDS_XRETCODE_BASE + nxretcodes) return xretcodes[rc - DDS_XRETCODE_BASE]; - } - - return "Unknown return code"; + else + return "Unknown return code"; } - diff --git a/src/ddsrt/src/rusage/freertos/rusage.c b/src/ddsrt/src/rusage/freertos/rusage.c new file mode 100644 index 0000000..7dd2784 --- /dev/null +++ b/src/ddsrt/src/rusage/freertos/rusage.c @@ -0,0 +1,106 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/rusage.h" + +/* Task CPU time statistics require a high resolution timer. FreeRTOS + recommends a time base between 10 and 100 times faster than the tick + interrupt (https://www.freertos.org/rtos-run-time-stats.html), but does not + define a macro or function to retrieve the base. */ + +/* Require time base to be defined for conversion to nanoseconds. */ + +#define DDSRT_NSECS_IN_RUSAGE_TIME_BASE (1) /* FIXME: Make configurable! */ + +#if !defined(DDSRT_NSECS_IN_RUSAGE_TIME_BASE) +#error "Time base for run time stats is not defined" +#endif + +static dds_return_t +rusage_self(ddsrt_rusage_t *usage) +{ + dds_return_t rc = DDS_RETCODE_OK; + dds_duration_t nsecs; + UBaseType_t cnt, len; + TaskStatus_t *states = NULL, *ptr; + size_t size; + + do { + len = uxTaskGetNumberOfTasks(); + size = len * sizeof(*states); + if ((ptr = ddsrt_realloc_s(states, size)) == NULL) { + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + states = ptr; + /* uxTaskGetSystemState returns 0 if the TaskStatus_t buffer is not + sufficiently large enough. */ + cnt = uxTaskGetSystemState(states, len, NULL); + } + } while (rc == DDS_RETCODE_OK && cnt == 0); + + if (rc == DDS_RETCODE_OK) { + memset(usage, 0, sizeof(*usage)); + + for (len = cnt, cnt = 0; cnt < len; cnt++) { + nsecs = states[cnt].ulRunTimeCounter * DDSRT_NSECS_IN_RUSAGE_TIME_BASE; + usage->stime += nsecs; /* FIXME: Protect against possible overflow! */ + } + } + + ddsrt_free(states); + + return rc; +} + +static dds_return_t +rusage_thread(ddsrt_rusage_t *usage) +{ + TaskStatus_t states; + + memset(usage, 0, sizeof(*usage)); + memset(&states, 0, sizeof(states)); + vTaskGetInfo(xTaskGetCurrentTaskHandle(), &states, pdFALSE, eInvalid); + usage->stime = states.ulRunTimeCounter * DDSRT_NSECS_IN_RUSAGE_TIME_BASE; + + return DDS_RETCODE_OK; +} + +#if ! DDSRT_HAVE_THREAD_LIST +static +#endif +dds_return_t +ddsrt_getrusage_anythread(ddsrt_thread_list_id_t tid, ddsrt_rusage_t *__restrict usage) +{ + assert(usage != NULL); + return rusage_thread(tid, usage); +} + +dds_return_t +ddsrt_getrusage(enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage) +{ + dds_return_t rc; + + assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD); + assert(usage != NULL); + + if (who == DDSRT_RUSAGE_THREAD) { + rc = rusage_thread_anythread(xTaskGetCurrentTaskHandle(), usage); + } else { + rc = rusage_self(usage); + } + + return rc; +} diff --git a/src/ddsrt/src/rusage/posix/rusage.c b/src/ddsrt/src/rusage/posix/rusage.c index 878bd1d..d8806e3 100644 --- a/src/ddsrt/src/rusage/posix/rusage.c +++ b/src/ddsrt/src/rusage/posix/rusage.c @@ -15,87 +15,212 @@ #include #include -#if defined(__APPLE__) +#include "dds/ddsrt/rusage.h" + +#if defined __linux +#include +#include + +dds_return_t +ddsrt_getrusage_anythread ( + ddsrt_thread_list_id_t tid, + ddsrt_rusage_t * __restrict usage) +{ + /* Linux' man pages happily state that the second field is the process/task name + in parentheses, and that %s is the correct scanf conversion. As it turns out + the process name itself can contain spaces and parentheses ... so %s is not a + good choice for the general case. The others are spec'd as a character or a + number, which suggests the correct procedure is to have the 2nd field start at + the first ( and end at the last ) ... + + RSS is per-process, so no point in populating that one + field 14, 15: utime, stime (field 1 is first) + + Voluntary and involuntary context switches can be found in .../status, but + not in stat; and .../status does not give the time. Crazy. */ + const double hz = (double) sysconf (_SC_CLK_TCK); + char file[100]; + FILE *fp; + int pos; + pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/stat", (unsigned long) tid); + if (pos < 0 || pos >= (int) sizeof (file)) + return DDS_RETCODE_ERROR; + if ((fp = fopen (file, "r")) == NULL) + return DDS_RETCODE_NOT_FOUND; + /* max 2 64-bit ints plus some whitespace; need 1 extra for detecting something + went wrong and we ended up gobbling up garbage; 64 will do */ + char save[64]; + size_t savepos = 0; + int prevc, c; + int field = 1; + for (prevc = 0; (c = fgetc (fp)) != EOF; prevc = c) + { + if (field == 1) + { + if (c == '(') + field = 2; + } + else if (field >= 2) + { + /* each close paren resets the field counter to 3 (the first is common, + further ones are rare and occur only if the thread name contains a + closing parenthesis), as well as the save space for fields 14 & 15 + that we care about. */ + if (c == ')') + { + field = 2; + savepos = 0; + } + else + { + /* next field on transition of whitespace to non-whitespace */ + if (c != ' ' && prevc == ' ') + field++; + /* save fields 14 & 15 while continuing scanning to EOF on the off-chance + that 14&15 initially appear to be in what ultimately turns out to be + task name */ + if (field == 14 || field == 15) + { + if (savepos < sizeof (save) - 1) + save[savepos++] = (char) c; + } + } + } + } + fclose (fp); + assert (savepos < sizeof (save)); + save[savepos] = 0; + if (savepos == sizeof (save) - 1) + return DDS_RETCODE_ERROR; + /* it's really integer, but the conversion from an unknown HZ value is much + less tricky in floating-point */ + double user, sys; + if (sscanf (save, "%lf %lf%n", &user, &sys, &pos) != 2 || (save[pos] != 0 && save[pos] != ' ')) + return DDS_RETCODE_ERROR; + usage->utime = (dds_time_t) (1e9 * user / hz); + usage->stime = (dds_time_t) (1e9 * sys / hz); + usage->idrss = 0; + usage->maxrss = 0; + usage->nvcsw = 0; + usage->nivcsw = 0; + + pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/status", (unsigned long) tid); + if (pos < 0 || pos >= (int) sizeof (file)) + return DDS_RETCODE_ERROR; + if ((fp = fopen (file, "r")) == NULL) + return DDS_RETCODE_NOT_FOUND; + enum { ERROR, READ_HEADING, SKIP_TO_EOL, READ_VCSW, READ_IVCSW } state = READ_HEADING; + savepos = 0; + while (state != ERROR && (c = fgetc (fp)) != EOF) + { + switch (state) + { + case READ_HEADING: + if (savepos < sizeof (save) - 1) + save[savepos++] = (char) c; + if (c == ':') + { + save[savepos] = 0; + savepos = 0; + if (strcmp (save, "voluntary_ctxt_switches:") == 0) + state = READ_VCSW; + else if (strcmp (save, "nonvoluntary_ctxt_switches:") == 0) + state = READ_IVCSW; + else + state = SKIP_TO_EOL; + } + break; + case SKIP_TO_EOL: + if (c == '\n') + state = READ_HEADING; + break; + case READ_VCSW: + case READ_IVCSW: + if (fscanf (fp, "%zu", (state == READ_VCSW) ? &usage->nvcsw : &usage->nivcsw) != 1) + state = ERROR; + else + state = SKIP_TO_EOL; + break; + case ERROR: + break; + } + } + fclose (fp); + return (state == ERROR) ? DDS_RETCODE_ERROR : DDS_RETCODE_OK; +} + +dds_return_t +ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage) +{ + struct rusage buf; + + assert (who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD); + assert (usage != NULL); + + memset (&buf, 0, sizeof(buf)); + if (getrusage ((who == DDSRT_RUSAGE_SELF) ? RUSAGE_SELF : RUSAGE_THREAD, &buf) == -1) + return DDS_RETCODE_ERROR; + + usage->utime = (buf.ru_utime.tv_sec * DDS_NSECS_IN_SEC) + (buf.ru_utime.tv_usec * DDS_NSECS_IN_USEC); + usage->stime = (buf.ru_stime.tv_sec * DDS_NSECS_IN_SEC) + (buf.ru_stime.tv_usec * DDS_NSECS_IN_USEC); + usage->maxrss = 1024 * (size_t) buf.ru_maxrss; + usage->idrss = (size_t) buf.ru_idrss; + usage->nvcsw = (size_t) buf.ru_nvcsw; + usage->nivcsw = (size_t) buf.ru_nivcsw; + return DDS_RETCODE_OK; +} +#elif defined (__APPLE__) #include #include #include -#endif -#include "dds/ddsrt/rusage.h" - -dds_retcode_t -ddsrt_getrusage(int who, ddsrt_rusage_t *usage) +dds_return_t +ddsrt_getrusage_anythread ( + ddsrt_thread_list_id_t tid, + ddsrt_rusage_t * __restrict usage) { - int err = 0; - struct rusage buf; - dds_retcode_t rc; + mach_msg_type_number_t cnt; + thread_basic_info_data_t info; + cnt = THREAD_BASIC_INFO_COUNT; + if (thread_info ((mach_port_t) tid, THREAD_BASIC_INFO, (thread_info_t) &info, &cnt) != KERN_SUCCESS) + return DDS_RETCODE_ERROR; - assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD); - assert(usage != NULL); - - memset(&buf, 0, sizeof(buf)); - -#if defined(__linux) - if ((who == DDSRT_RUSAGE_SELF && getrusage(RUSAGE_SELF, &buf) == -1) || - (who == DDSRT_RUSAGE_THREAD && getrusage(RUSAGE_THREAD, &buf) == -1)) - { - err = errno; - } else { - buf.ru_maxrss *= 1024; - } -#else - if (getrusage(RUSAGE_SELF, &buf) == -1) { - err = errno; - } else if (who == DDSRT_RUSAGE_THREAD) { - memset(&buf.ru_utime, 0, sizeof(buf.ru_utime)); - memset(&buf.ru_stime, 0, sizeof(buf.ru_stime)); - buf.ru_nvcsw = 0; - buf.ru_nivcsw = 0; - -#if defined(__APPLE__) - kern_return_t ret; - mach_port_t thr; - mach_msg_type_number_t cnt; - thread_basic_info_data_t info; - - thr = mach_thread_self(); - assert(thr != MACH_PORT_DEAD); - if (thr == MACH_PORT_NULL) { - /* Resource shortage prevented reception of send right. */ - err = ENOMEM; - } else { - cnt = THREAD_BASIC_INFO_COUNT; - ret = thread_info( - thr, THREAD_BASIC_INFO, (thread_info_t)&info, &cnt); - assert(ret != KERN_INVALID_ARGUMENT); - /* Assume MIG_ARRAY_TOO_LARGE will not happen. */ - buf.ru_utime.tv_sec = info.user_time.seconds; - buf.ru_utime.tv_usec = info.user_time.microseconds; - buf.ru_stime.tv_sec = info.system_time.seconds; - buf.ru_stime.tv_usec = info.system_time.microseconds; - mach_port_deallocate(mach_task_self(), thr); - } -#endif /* __APPLE__ */ - } -#endif /* __linux */ - - if (err == 0) { - rc = DDS_RETCODE_OK; - usage->utime = - (buf.ru_utime.tv_sec * DDS_NSECS_IN_SEC) + - (buf.ru_utime.tv_usec * DDS_NSECS_IN_USEC); - usage->stime = - (buf.ru_stime.tv_sec * DDS_NSECS_IN_SEC) + - (buf.ru_stime.tv_usec * DDS_NSECS_IN_USEC); - usage->maxrss = (size_t)buf.ru_maxrss; - usage->idrss = (size_t)buf.ru_idrss; - usage->nvcsw = (size_t)buf.ru_nvcsw; - usage->nivcsw = (size_t)buf.ru_nivcsw; - } else if (err == ENOMEM) { - rc = DDS_RETCODE_OUT_OF_RESOURCES; - } else { - rc = DDS_RETCODE_ERROR; - } - - return rc; + /* Don't see an (easy) way to get context switch counts */ + usage->utime = info.user_time.seconds * DDS_NSECS_IN_SEC + info.user_time.microseconds * DDS_NSECS_IN_USEC; + usage->stime = info.system_time.seconds * DDS_NSECS_IN_SEC + info.system_time.microseconds * DDS_NSECS_IN_USEC; + usage->idrss = 0; + usage->maxrss = 0; + usage->nivcsw = 0; + usage->nvcsw = 0; + return DDS_RETCODE_OK; } + +dds_return_t +ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage) +{ + struct rusage buf; + dds_return_t rc; + + assert (usage != NULL); + + memset (&buf, 0, sizeof(buf)); + if (getrusage (RUSAGE_SELF, &buf) == -1) + return DDS_RETCODE_ERROR; + + switch (who) { + case DDSRT_RUSAGE_THREAD: + if ((rc = ddsrt_getrusage_anythread (pthread_mach_thread_np (pthread_self()), usage)) < 0) + return rc; + break; + case DDSRT_RUSAGE_SELF: + usage->utime = (buf.ru_utime.tv_sec * DDS_NSECS_IN_SEC) + (buf.ru_utime.tv_usec * DDS_NSECS_IN_USEC); + usage->stime = (buf.ru_stime.tv_sec * DDS_NSECS_IN_SEC) + (buf.ru_stime.tv_usec * DDS_NSECS_IN_USEC); + usage->nvcsw = (size_t) buf.ru_nvcsw; + usage->nivcsw = (size_t) buf.ru_nivcsw; + break; + } + usage->maxrss = (size_t) buf.ru_maxrss; + usage->idrss = (size_t) buf.ru_idrss; + return DDS_RETCODE_OK; +} +#endif diff --git a/src/ddsrt/src/rusage/windows/rusage.c b/src/ddsrt/src/rusage/windows/rusage.c index 71d763d..5f9e1f1 100644 --- a/src/ddsrt/src/rusage/windows/rusage.c +++ b/src/ddsrt/src/rusage/windows/rusage.c @@ -18,36 +18,60 @@ #include dds_time_t -filetime_to_time(const FILETIME *ft) +filetime_to_time (const FILETIME *ft) { /* FILETIME structures express times in 100-nanosecond time units. */ - return ((ft->dwHighDateTime << 31) + (ft->dwLowDateTime)) * 100; + return (dds_time_t) ((((uint64_t) ft->dwHighDateTime << 31) + (ft->dwLowDateTime)) * 100); } -dds_retcode_t -ddsrt_getrusage(int who, ddsrt_rusage_t *usage) +dds_return_t +ddsrt_getrusage_anythread (ddsrt_thread_list_id_t tid, ddsrt_rusage_t * __restrict usage) { FILETIME stime, utime, ctime, etime; - PROCESS_MEMORY_COUNTERS pmctrs; - assert(who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD); - assert(usage != NULL); + assert (usage != NULL); /* Memory counters are per process, but populate them if thread resource usage is requested to keep in sync with Linux. */ - if ((!GetProcessMemoryInfo(GetCurrentProcess(), &pmctrs, sizeof(pmctrs))) - || (who == DDSRT_RUSAGE_SELF && - !GetProcessTimes(GetCurrentProcess(), &ctime, &etime, &stime, &utime)) - || (who == DDSRT_RUSAGE_THREAD && - !GetThreadTimes(GetCurrentThread(), &ctime, &etime, &stime, &utime))) - { - return GetLastError(); - } - - memset(usage, 0, sizeof(*usage)); - usage->stime = filetime_to_time(&stime); - usage->utime = filetime_to_time(&utime); - usage->maxrss = pmctrs.PeakWorkingSetSize; + if (!GetThreadTimes (tid, &ctime, &etime, &stime, &utime)) + return DDS_RETCODE_ERROR; + memset (usage, 0, sizeof (*usage)); + usage->stime = filetime_to_time (&stime); + usage->utime = filetime_to_time (&utime); return DDS_RETCODE_OK; } + +dds_return_t +ddsrt_getrusage (enum ddsrt_getrusage_who who, ddsrt_rusage_t *usage) +{ + PROCESS_MEMORY_COUNTERS pmctrs; + + assert (who == DDSRT_RUSAGE_SELF || who == DDSRT_RUSAGE_THREAD); + assert (usage != NULL); + + /* Memory counters are per process, but populate them if thread resource + usage is requested to keep in sync with Linux. */ + if (!GetProcessMemoryInfo (GetCurrentProcess (), &pmctrs, sizeof (pmctrs))) + return DDS_RETCODE_ERROR; + + if (who == DDSRT_RUSAGE_THREAD) + { + dds_return_t rc; + if ((rc = ddsrt_getrusage_anythread (GetCurrentThread (), usage)) < 0) + return rc; + } + else + { + FILETIME stime, utime, ctime, etime; + if (!GetProcessTimes (GetCurrentProcess (), &ctime, &etime, &stime, &utime)) + return DDS_RETCODE_ERROR; + memset(usage, 0, sizeof(*usage)); + usage->stime = filetime_to_time(&stime); + usage->utime = filetime_to_time(&utime); + } + + usage->maxrss = pmctrs.PeakWorkingSetSize; + return DDS_RETCODE_OK; +} + diff --git a/src/ddsrt/src/sockets.c b/src/ddsrt/src/sockets.c index d559a80..69d183b 100644 --- a/src/ddsrt/src/sockets.c +++ b/src/ddsrt/src/sockets.c @@ -15,19 +15,21 @@ #include #include -#if !defined(_WIN32) -#include -#include -#include -# if defined(__linux) -# include /* 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 +# include +# include +# if defined(__linux) +# include /* sockaddr_ll */ +# endif /* __linux */ +# endif /* _WIN32 */ +#endif /* LWIP_SOCKET */ + extern inline struct timeval * ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv); @@ -37,7 +39,7 @@ const struct in6_addr ddsrt_in6addr_loopback = IN6ADDR_LOOPBACK_INIT; #endif const int afs[] = { -#ifdef __linux +#if defined(__linux) && !LWIP_SOCKET AF_PACKET, #endif /* __linux */ #if DDSRT_HAVE_IPV6 @@ -62,7 +64,7 @@ ddsrt_sockaddr_get_size(const struct sockaddr *const sa) sz = sizeof(struct sockaddr_in6); break; #endif /* DDSRT_HAVE_IPV6 */ -#ifdef __linux +#if defined(__linux) && !LWIP_SOCKET case AF_PACKET: sz = sizeof(struct sockaddr_ll); break; @@ -175,7 +177,7 @@ ddsrt_sockaddr_insamesubnet( return eq; } -dds_retcode_t +dds_return_t ddsrt_sockaddrfromstr(int af, const char *str, void *sa) { assert(str != NULL); @@ -184,13 +186,19 @@ ddsrt_sockaddrfromstr(int af, const char *str, void *sa) switch (af) { case AF_INET: { struct in_addr buf; +#if DDSRT_HAVE_INET_PTON if (inet_pton(af, str, &buf) != 1) { return DDS_RETCODE_BAD_PARAMETER; - } else { - memset(sa, 0, sizeof(struct sockaddr_in)); - ((struct sockaddr_in *)sa)->sin_family = AF_INET; - memcpy(&((struct sockaddr_in *)sa)->sin_addr, &buf, sizeof(buf)); } +#else + buf.s_addr = inet_addr (str); + if (buf.s_addr == (in_addr_t)-1) { + return DDS_RETCODE_BAD_PARAMETER; + } +#endif + memset(sa, 0, sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)sa)->sin_family = AF_INET; + memcpy(&((struct sockaddr_in *)sa)->sin_addr, &buf, sizeof(buf)); } break; #if DDSRT_HAVE_IPV6 case AF_INET6: { @@ -211,17 +219,28 @@ ddsrt_sockaddrfromstr(int af, const char *str, void *sa) return DDS_RETCODE_OK; } -dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size) +dds_return_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size) { const char *ptr; assert(sa != NULL); assert(buf != NULL); +#if LWIP_SOCKET +DDSRT_WARNING_GNUC_OFF(sign-conversion) +#endif switch (((struct sockaddr *)sa)->sa_family) { case AF_INET: +#if DDSRT_HAVE_INET_NTOP ptr = inet_ntop( AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf, (socklen_t)size); +#else + { + in_addr_t x = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + snprintf(buf,size,"%u.%u.%u.%u",(x>>24),(x>>16)&0xff,(x>>8)&0xff,x&0xff); + ptr = buf; + } +#endif break; #if DDSRT_HAVE_IPV6 case AF_INET6: @@ -232,6 +251,9 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size) default: return DDS_RETCODE_BAD_PARAMETER; } +#if LWIP_SOCKET +DDSRT_WARNING_GNUC_ON(sign-conversion) +#endif if (ptr == NULL) { return DDS_RETCODE_NOT_ENOUGH_SPACE; @@ -241,7 +263,8 @@ dds_retcode_t ddsrt_sockaddrtostr(const void *sa, char *buf, size_t size) } #if DDSRT_HAVE_DNS -dds_retcode_t +#if DDSRT_HAVE_GETADDRINFO +dds_return_t ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp) { int gai_err = 0; @@ -279,7 +302,6 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp) NOTE: Error codes returned by getaddrinfo map directly onto Windows Socket error codes and WSAGetLastError can be used instead. */ - DDS_TRACE("getaddrinfo for %s returned %d\n", name, gai_err); switch (gai_err) { #if defined(EAI_AGAIN) case EAI_AGAIN: @@ -312,10 +334,14 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp) /* Other system error. */ return DDS_RETCODE_ERROR; #endif +#if defined(EAI_BADFLAGS) case EAI_BADFLAGS: /* Invalid flags in hints.ai_flags. */ +#endif case EAI_FAMILY: /* Address family not supported. */ case EAI_SERVICE: /* Service not available for socket type. */ +#if defined(EAI_SOCKTYPE) case EAI_SOCKTYPE: /* Socket type not supported. */ +#endif case 0: { struct addrinfo *ai; size_t addrno, naddrs, size; @@ -344,11 +370,30 @@ ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp) freeaddrinfo(res); } break; default: - DDS_ERROR("getaddrinfo returned unkown error %d\n", gai_err); + DDS_ERROR ("getaddrinfo returned unkown error %d\n", gai_err); return DDS_RETCODE_ERROR; } *hentp = hent; return DDS_RETCODE_OK; } +#else +dds_return_t +ddsrt_gethostbyname(const char *name, int af, ddsrt_hostent_t **hentp) +{ + struct hostent hest, *he; + char buf[256]; + int err; + he = gethostbyname_r (name, &hest, buf, sizeof (buf), &err); + if (he == NULL) { + return DDS_RETCODE_HOST_NOT_FOUND; + } else { + size_t size = sizeof(**hentp) + (1 * sizeof((*hentp)->addrs[0])); + *hentp = ddsrt_calloc_s(1, size); + (*hentp)->naddrs = 1; + memcpy(&(*hentp)->addrs[0], he->h_addr, he->h_length); + return DDS_RETCODE_OK; + } +} +#endif /* DDSRT_HAVE_GETADDRINFO */ #endif /* DDSRT_HAVE_DNS */ diff --git a/src/ddsrt/src/sockets/include/dds/ddsrt/sockets_priv.h b/src/ddsrt/src/sockets/include/dds/ddsrt/sockets_priv.h index 8a41203..d29f817 100644 --- a/src/ddsrt/src/sockets/include/dds/ddsrt/sockets_priv.h +++ b/src/ddsrt/src/sockets/include/dds/ddsrt/sockets_priv.h @@ -17,6 +17,7 @@ #include "dds/ddsrt/misc.h" #include "dds/ddsrt/sockets.h" #include "dds/ddsrt/time.h" +#include "dds/ddsrt/static_assert.h" #if defined(__cplusplus) extern "C" { @@ -27,12 +28,8 @@ typedef long ddsrt_tv_sec_t; typedef long ddsrt_tv_usec_t; #else typedef time_t ddsrt_tv_sec_t; -typedef suseconds_t ddsrt_tv_usec_t; #endif -#define DDSRT_TIME_T_MAX \ - (DDSRT_MAX_INTEGER(ddsrt_tv_sec_t)) - /** * @brief Convert a relative time to a timeval rounding up. * @@ -52,19 +49,21 @@ ddsrt_duration_to_timeval_ceil(dds_duration_t reltime, struct timeval *tv) return NULL; } else if (reltime > 0) { dds_duration_t max_nsecs; - if (DDS_INFINITY > DDSRT_TIME_T_MAX) { - assert(DDSRT_TIME_T_MAX == INT32_MAX); + DDSRT_STATIC_ASSERT (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32 || CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 64); + if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32) max_nsecs = INT32_MAX * DDS_NSECS_IN_SEC; - } else { - max_nsecs = DDSRT_TIME_T_MAX / DDS_NSECS_IN_SEC; - } + else + max_nsecs = INT64_MAX / DDS_NSECS_IN_SEC; if (reltime < (max_nsecs - DDS_NSECS_IN_USEC - 1)) { reltime += (DDS_NSECS_IN_USEC - 1); tv->tv_sec = (ddsrt_tv_sec_t)(reltime / DDS_NSECS_IN_SEC); - tv->tv_usec = (ddsrt_tv_usec_t)((reltime % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC); + tv->tv_usec = (int)((reltime % DDS_NSECS_IN_SEC) / DDS_NSECS_IN_USEC); } else { - tv->tv_sec = DDSRT_TIME_T_MAX; + if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32) + tv->tv_sec = (ddsrt_tv_sec_t) INT32_MAX; + else + tv->tv_sec = (ddsrt_tv_sec_t) INT64_MAX; tv->tv_usec = 999999; } } else { diff --git a/src/ddsrt/src/sockets/posix/gethostname.c b/src/ddsrt/src/sockets/posix/gethostname.c index de71a44..109af1e 100644 --- a/src/ddsrt/src/sockets/posix/gethostname.c +++ b/src/ddsrt/src/sockets/posix/gethostname.c @@ -10,22 +10,46 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include -#include #include #include +#include "dds/ddsrt/sockets.h" +#include "dds/ddsrt/string.h" + +#if !LWIP_SOCKET +#include +#endif + #if defined(__VXWORKS__) #include #endif /* __VXWORKS__ */ -#if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX) -# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +#if !defined(HOST_NAME_MAX) +# if LWIP_SOCKET +# define HOST_NAME_MAX DNS_MAX_NAME_LENGTH +# elif defined(_POSIX_HOST_NAME_MAX) +# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX +# endif #endif -#include "dds/ddsrt/sockets.h" -#include "dds/ddsrt/string.h" -dds_retcode_t +#if LWIP_SOCKET +dds_return_t +ddsrt_gethostname( + char *name, + size_t len) +{ + if (ddsrt_strlcpy(name, "localhost", len) >= len) { + return DDS_RETCODE_NOT_ENOUGH_SPACE; + } + return DDS_RETCODE_OK; +} +#else +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 256 +#endif + +dds_return_t ddsrt_gethostname( char *name, size_t len) @@ -59,3 +83,4 @@ ddsrt_gethostname( return DDS_RETCODE_ERROR; } +#endif diff --git a/src/ddsrt/src/sockets/posix/socket.c b/src/ddsrt/src/sockets/posix/socket.c index 94b7f89..e64b0c4 100644 --- a/src/ddsrt/src/sockets/posix/socket.c +++ b/src/ddsrt/src/sockets/posix/socket.c @@ -10,10 +10,14 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include -#include #include #include +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/sockets_priv.h" + +#if !LWIP_SOCKET #if defined(__VXWORKS__) #include #include @@ -21,6 +25,7 @@ #else #include #endif /* __VXWORKS__ */ +#include #include #include #ifdef __sun @@ -30,12 +35,9 @@ #ifdef __APPLE__ #include #endif /* __APPLE__ */ +#endif /* LWIP_SOCKET */ -#include "dds/ddsrt/log.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsrt/sockets_priv.h" - -dds_retcode_t +dds_return_t ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol) { ddsrt_socket_t sock; @@ -66,7 +68,7 @@ ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_close( ddsrt_socket_t sock) { @@ -85,7 +87,7 @@ ddsrt_close( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_bind( ddsrt_socket_t sock, const struct sockaddr *addr, @@ -110,7 +112,7 @@ ddsrt_bind( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_listen( ddsrt_socket_t sock, int backlog) @@ -133,7 +135,7 @@ ddsrt_listen( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_connect( ddsrt_socket_t sock, const struct sockaddr *addr, @@ -175,7 +177,7 @@ ddsrt_connect( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_accept( ddsrt_socket_t sock, struct sockaddr *addr, @@ -222,7 +224,7 @@ ddsrt_accept( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_getsockname( ddsrt_socket_t sock, struct sockaddr *addr, @@ -246,7 +248,7 @@ ddsrt_getsockname( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_getsockopt( ddsrt_socket_t sock, int32_t level, @@ -254,6 +256,15 @@ ddsrt_getsockopt( void *optval, socklen_t *optlen) { +#if LWIP_SOCKET + if (optname == SO_SNDBUF || optname == SO_RCVBUF) + return DDS_RETCODE_BAD_PARAMETER; +# if !SO_REUSE + if (optname == SO_REUSEADDR) + return DDS_RETCODE_BAD_PARAMETER; +# endif /* SO_REUSE */ +#endif /* LWIP_SOCKET */ + if (getsockopt(sock, level, optname, optval, optlen) == 0) return DDS_RETCODE_OK; @@ -271,7 +282,7 @@ ddsrt_getsockopt( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_setsockopt( ddsrt_socket_t sock, int32_t level, @@ -279,6 +290,15 @@ ddsrt_setsockopt( const void *optval, socklen_t optlen) { +#if LWIP_SOCKET + if (optname == SO_SNDBUF || optname == SO_RCVBUF) + return DDS_RETCODE_BAD_PARAMETER; +# if !SO_REUSE + if (optname == SO_REUSEADDR) + return DDS_RETCODE_BAD_PARAMETER; +# endif /* SO_REUSE */ +#endif /* LWIP_SOCKET */ + switch (optname) { case SO_SNDBUF: case SO_RCVBUF: @@ -319,7 +339,7 @@ err_setsockopt: return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_setsocknonblocking( ddsrt_socket_t sock, bool nonblock) @@ -357,7 +377,7 @@ err_fcntl: return DDS_RETCODE_ERROR; } -static inline dds_retcode_t +static inline dds_return_t recv_error_to_retcode(int errnum) { switch (errnum) { @@ -386,7 +406,7 @@ recv_error_to_retcode(int errnum) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_recv( ddsrt_socket_t sock, void *buf, @@ -405,7 +425,25 @@ ddsrt_recv( return recv_error_to_retcode(errno); } -dds_retcode_t +#if LWIP_SOCKET && !defined(recvmsg) +static ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags) +{ + assert(msg->msg_iovlen == 1); + assert(msg->msg_controllen == 0); + + msg->msg_flags = 0; + + return recvfrom( + sockfd, + msg->msg_iov[0].iov_base, + msg->msg_iov[0].iov_len, + flags, + msg->msg_name, + &msg->msg_namelen); +} +#endif /* LWIP_SOCKET */ + +dds_return_t ddsrt_recvmsg( ddsrt_socket_t sock, ddsrt_msghdr_t *msg, @@ -423,11 +461,12 @@ ddsrt_recvmsg( return recv_error_to_retcode(errno); } -static inline dds_retcode_t +static inline dds_return_t send_error_to_retcode(int errnum) { switch (errnum) { case EACCES: + case EPERM: return DDS_RETCODE_NOT_ALLOWED; case EAGAIN: #if EAGAIN != EWOULDBLOCK @@ -465,7 +504,7 @@ send_error_to_retcode(int errnum) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_send( ddsrt_socket_t sock, const void *buf, @@ -484,7 +523,7 @@ ddsrt_send( return send_error_to_retcode(errno); } -dds_retcode_t +dds_return_t ddsrt_sendmsg( ddsrt_socket_t sock, const ddsrt_msghdr_t *msg, @@ -502,7 +541,7 @@ ddsrt_sendmsg( return send_error_to_retcode(errno); } -dds_retcode_t +dds_return_t ddsrt_select( int32_t nfds, fd_set *readfds, diff --git a/src/ddsrt/src/sockets/windows/socket.c b/src/ddsrt/src/sockets/windows/socket.c index bc96301..d2b3221 100644 --- a/src/ddsrt/src/sockets/windows/socket.c +++ b/src/ddsrt/src/sockets/windows/socket.c @@ -52,11 +52,11 @@ ddsrt_winsock_fini(void) WSACleanup(); } -dds_retcode_t +dds_return_t ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol) { int err; - dds_retcode_t ret = DDS_RETCODE_OK; + dds_return_t ret = DDS_RETCODE_OK; ddsrt_socket_t sock = DDSRT_INVALID_SOCKET; assert(sockptr != NULL); @@ -93,7 +93,7 @@ ddsrt_socket(ddsrt_socket_t *sockptr, int domain, int type, int protocol) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_close(ddsrt_socket_t sock) { int err; @@ -120,7 +120,7 @@ ddsrt_close(ddsrt_socket_t sock) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_accept( ddsrt_socket_t sock, struct sockaddr *addr, @@ -162,7 +162,7 @@ ddsrt_accept( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_bind(ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen) { int err; @@ -195,7 +195,7 @@ ddsrt_bind(ddsrt_socket_t sock, const struct sockaddr *addr, socklen_t addrlen) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_listen( ddsrt_socket_t sock, int backlog) @@ -227,7 +227,7 @@ ddsrt_listen( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_connect( ddsrt_socket_t sock, const struct sockaddr *addr, @@ -275,7 +275,7 @@ ddsrt_connect( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_getsockname( ddsrt_socket_t sock, struct sockaddr *addr, @@ -309,7 +309,7 @@ ddsrt_getsockname( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_getsockopt( ddsrt_socket_t sock, int32_t level, @@ -358,7 +358,7 @@ ddsrt_getsockopt( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_setsockopt( ddsrt_socket_t sock, int32_t level, @@ -404,7 +404,7 @@ ddsrt_setsockopt( return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_setsocknonblocking( ddsrt_socket_t sock, bool nonblock) @@ -435,7 +435,7 @@ ddsrt_setsocknonblocking( return DDS_RETCODE_ERROR; } -static dds_retcode_t recv_error_to_retcode(int errnum) +static dds_return_t recv_error_to_retcode(int errnum) { assert(errnum != WSANOTINITIALISED); switch (errnum) { @@ -470,7 +470,7 @@ static dds_retcode_t recv_error_to_retcode(int errnum) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_recv( ddsrt_socket_t sock, void *buf, @@ -490,7 +490,7 @@ ddsrt_recv( return recv_error_to_retcode(WSAGetLastError()); } -dds_retcode_t +dds_return_t ddsrt_recvmsg( ddsrt_socket_t sock, ddsrt_msghdr_t *msg, @@ -531,7 +531,7 @@ ddsrt_recvmsg( return recv_error_to_retcode(err); } -static dds_retcode_t +static dds_return_t send_error_to_retcode(int errnum) { assert(errnum != WSANOTINITIALISED); @@ -577,7 +577,7 @@ send_error_to_retcode(int errnum) return DDS_RETCODE_ERROR; } -dds_retcode_t +dds_return_t ddsrt_send( ddsrt_socket_t sock, const void *buf, @@ -608,7 +608,7 @@ struct iovec_matches_WSABUF { char len_size_matches[sizeof(((ddsrt_iovec_t *)8)->iov_len) == sizeof(((WSABUF *)8)->len) ? 1 : -1]; }; -dds_retcode_t +dds_return_t ddsrt_sendmsg( ddsrt_socket_t sock, const ddsrt_msghdr_t *msg, @@ -639,7 +639,7 @@ ddsrt_sendmsg( return send_error_to_retcode(WSAGetLastError()); } -dds_retcode_t +dds_return_t ddsrt_select( int32_t nfds, fd_set *readfds, diff --git a/src/ddsrt/src/string.c b/src/ddsrt/src/string.c index 3e4ed64..d048e5f 100644 --- a/src/ddsrt/src/string.c +++ b/src/ddsrt/src/string.c @@ -12,9 +12,6 @@ #include #include #include -#if defined(__IAR_SYSTEMS_ICC__) -#define _DLIB_ADD_EXTRA_SYMBOLS /* Export strtok_r. */ -#endif #include #include "dds/ddsrt/heap.h" @@ -65,19 +62,6 @@ ddsrt_strncasecmp( return cr; } -char * -ddsrt_strtok_r( - char *str, - const char *delim, - char **saveptr) -{ -#if _WIN32 - return strtok_s(str, delim, saveptr); -#else - return strtok_r(str, delim, saveptr); -#endif -} - char * ddsrt_strsep(char **str, const char *sep) { @@ -178,4 +162,3 @@ ddsrt_strdup( return ddsrt_memdup(str, strlen(str) + 1); } - diff --git a/src/ddsrt/src/string/posix/strerror.c b/src/ddsrt/src/string/posix/strerror.c index f467e30..cbd1009 100644 --- a/src/ddsrt/src/string/posix/strerror.c +++ b/src/ddsrt/src/string/posix/strerror.c @@ -21,7 +21,7 @@ #include "dds/ddsrt/string.h" -dds_retcode_t +dds_return_t ddsrt_strerror_r(int errnum, char *buf, size_t buflen) { assert(buf != NULL); diff --git a/src/ddsrt/src/string/solaris2.6/strerror.c b/src/ddsrt/src/string/solaris2.6/strerror.c new file mode 100644 index 0000000..d3177f9 --- /dev/null +++ b/src/ddsrt/src/string/solaris2.6/strerror.c @@ -0,0 +1,34 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +/* Make sure we get the XSI compliant version of strerror_r */ +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE +#undef _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L + +#include +#include +#include +#include + +#include "dds/ddsrt/string.h" + +dds_return_t +ddsrt_strerror_r(int errnum, char *buf, size_t buflen) +{ + assert(buf != NULL); + assert(buflen > 0); + if (snprintf (buf, buflen, "errno=%d", errnum) >= buflen) + return DDS_RETCODE_NOT_ENOUGH_SPACE; + else + return DDS_RETCODE_OK; +} diff --git a/src/ddsrt/src/strtod.c b/src/ddsrt/src/strtod.c index 99e4f05..7d0c0ba 100644 --- a/src/ddsrt/src/strtod.c +++ b/src/ddsrt/src/strtod.c @@ -96,12 +96,12 @@ os_lcNumericReplace(char *str) { } } -dds_retcode_t +dds_return_t ddsrt_strtod(const char *nptr, char **endptr, double *dblptr) { double dbl; int orig_errno; - dds_retcode_t ret = DDS_RETCODE_OK; + dds_return_t ret = DDS_RETCODE_OK; assert(nptr != NULL); assert(dblptr != NULL); @@ -161,7 +161,7 @@ ddsrt_strtod(const char *nptr, char **endptr, double *dblptr) return ret; } -dds_retcode_t +dds_return_t ddsrt_strtof(const char *nptr, char **endptr, float *fltptr) { /* Just use os_strtod(). */ @@ -169,7 +169,7 @@ ddsrt_strtof(const char *nptr, char **endptr, float *fltptr) point number is definitely not a double-precision floating point number. */ double dbl = 0.0; - dds_retcode_t ret; + dds_return_t ret; assert(nptr != NULL); assert(fltptr != NULL); diff --git a/src/ddsrt/src/strtol.c b/src/ddsrt/src/strtol.c index c6b6a5f..5269d96 100644 --- a/src/ddsrt/src/strtol.c +++ b/src/ddsrt/src/strtol.c @@ -16,7 +16,7 @@ #include "dds/ddsrt/strtol.h" -int ddsrt_todigit(const int chr) +static int ddsrt_todigit(const int chr) { if (chr >= '0' && chr <= '9') { return chr - '0'; @@ -29,7 +29,7 @@ int ddsrt_todigit(const int chr) return -1; } -static dds_retcode_t +static dds_return_t ullfstr( const char *str, char **endptr, @@ -37,7 +37,7 @@ ullfstr( unsigned long long *ullng, unsigned long long max) { - dds_retcode_t rc = DDS_RETCODE_OK; + dds_return_t rc = DDS_RETCODE_OK; int num; size_t cnt = 0; unsigned long long tot = 0; @@ -86,14 +86,14 @@ ullfstr( return rc; } -dds_retcode_t +dds_return_t ddsrt_strtoll( const char *str, char **endptr, int32_t base, long long *llng) { - dds_retcode_t rc = DDS_RETCODE_OK; + dds_return_t rc = DDS_RETCODE_OK; size_t cnt = 0; long long tot = 1; unsigned long long ullng = 0, max = INT64_MAX; @@ -122,14 +122,14 @@ ddsrt_strtoll( return rc; } -dds_retcode_t +dds_return_t ddsrt_strtoull( const char *str, char **endptr, int32_t base, unsigned long long *ullng) { - dds_retcode_t rc = DDS_RETCODE_OK; + dds_return_t rc = DDS_RETCODE_OK; size_t cnt = 0; unsigned long long tot = 1; unsigned long long max = UINT64_MAX; @@ -157,7 +157,7 @@ ddsrt_strtoull( return rc; } -dds_retcode_t +dds_return_t ddsrt_atoll( const char *str, long long *llng) @@ -165,7 +165,7 @@ ddsrt_atoll( return ddsrt_strtoll(str, NULL, 10, llng); } -dds_retcode_t +dds_return_t ddsrt_atoull( const char *str, unsigned long long *ullng) diff --git a/src/ddsrt/src/sync/freertos/sync.c b/src/ddsrt/src/sync/freertos/sync.c new file mode 100644 index 0000000..f38b0c2 --- /dev/null +++ b/src/ddsrt/src/sync/freertos/sync.c @@ -0,0 +1,467 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/timeconv.h" + +void ddsrt_mutex_init(ddsrt_mutex_t *mutex) +{ + SemaphoreHandle_t sem; + + assert(mutex != NULL); + + if ((sem = xSemaphoreCreateMutex()) == NULL) { + abort(); + } + + (void)memset(mutex, 0, sizeof(*mutex)); + mutex->sem = sem; +} + +void ddsrt_mutex_destroy(ddsrt_mutex_t *mutex) +{ + assert(mutex != NULL); + + vSemaphoreDelete(mutex->sem); + (void)memset(mutex, 0, sizeof(*mutex)); +} + +static bool +mutex_lock(ddsrt_mutex_t *mutex, int blk) +{ + assert(mutex != NULL); + + if (xSemaphoreTake(mutex->sem, (blk == 1 ? portMAX_DELAY : 0)) != pdPASS) { + /* xSemaphoreTake will only return pdFAIL on timeout. The wait will be + indefinite if INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h + and portMAX_DELAY was passed. */ + assert(blk == 0); + return false; + } + + return true; +} + +void ddsrt_mutex_lock(ddsrt_mutex_t *mutex) +{ + if (!mutex_lock(mutex, 1)) { + DDS_FATAL("Failed to lock 0x%p", mutex); + } +} + +bool ddsrt_mutex_trylock(ddsrt_mutex_t *mutex) +{ + return mutex_lock(mutex, 0); +} + +void ddsrt_mutex_unlock(ddsrt_mutex_t *mutex) +{ + assert(mutex != NULL); + + if (xSemaphoreGive(mutex->sem) != pdPASS) { + DDS_FATAL("Failed to unlock 0x%p", mutex->sem); + } +} + +static dds_return_t +cond_timedwait( + ddsrt_cond_t *cond, + ddsrt_mutex_t *mutex, + dds_duration_t reltime) +{ + dds_return_t rc = DDS_RETCODE_OK; + dds_time_t abstime; + TaskHandle_t task; + TickType_t ticks = 0; + + assert(cond != NULL); + assert(mutex != NULL); + + abstime = ddsrt_time_add_duration(dds_time(), reltime); + ticks = ddsrt_duration_to_ticks_ceil(reltime); + + xSemaphoreTake(cond->sem, portMAX_DELAY); + ddsrt_mutex_unlock(mutex); + + task = xTaskGetCurrentTaskHandle(); + /* Register current task with condition. */ + ddsrt_tasklist_push(&cond->tasks, task); + /* Discard pending notifications. */ + ulTaskNotifyTake(1, 0); + + xSemaphoreGive(cond->sem); + /* Wait to be notified. */ + switch (ulTaskNotifyTake(1, ticks)) { + case 0: + xSemaphoreTake(cond->sem, ticks); + ddsrt_tasklist_pop(&cond->tasks, task); + xSemaphoreGive(cond->sem); + break; + default: + /* Task already removed from condition. */ + break; + } + + /* Timeout must only be returned if the time has actually passed. */ + if (dds_time() >= abstime) { + rc = DDS_RETCODE_TIMEOUT; + } + + ddsrt_mutex_lock(mutex); + + return rc; +} + +void ddsrt_cond_init(ddsrt_cond_t *cond) +{ + SemaphoreHandle_t sem; + ddsrt_tasklist_t tasks; + + assert(cond != NULL); + + if (ddsrt_tasklist_init(&tasks) == -1) { + abort(); + } + if ((sem = xSemaphoreCreateMutex()) == NULL) { + ddsrt_tasklist_fini(&tasks); + abort(); + } + + (void)memset(cond, 0, sizeof(*cond)); + cond->sem = sem; + cond->tasks = tasks; +} + +void ddsrt_cond_destroy(ddsrt_cond_t *cond) +{ + assert(cond != NULL); + + vSemaphoreDelete(cond->sem); + ddsrt_tasklist_fini(&cond->tasks); + (void)memset(cond, 0, sizeof(*cond)); +} + +void ddsrt_cond_wait(ddsrt_cond_t *cond, ddsrt_mutex_t *mutex) +{ + assert(cond != NULL); + assert(mutex != NULL); + + (void)cond_timedwait(cond, mutex, DDS_INFINITY); +} + +bool +ddsrt_cond_waitfor( + ddsrt_cond_t *cond, + ddsrt_mutex_t *mutex, + dds_duration_t reltime) +{ + dds_return_t rc; + + assert(cond != NULL); + assert(mutex != NULL); + + switch ((rc = cond_timedwait(cond, mutex, reltime))) { + case DDS_RETCODE_OUT_OF_RESOURCES: + abort(); + case DDS_RETCODE_TIMEOUT: + return false; + default: + assert(rc == DDS_RETCODE_OK); + break; + } + + return true; +} + +bool +ddsrt_cond_waituntil( + ddsrt_cond_t *cond, + ddsrt_mutex_t *mutex, + dds_time_t abstime) +{ + dds_return_t rc; + dds_time_t time; + dds_duration_t reltime; + + assert(cond != NULL); + assert(mutex != NULL); + + time = dds_time(); + reltime = (abstime > time ? abstime - time : 0); + + switch ((rc = cond_timedwait(cond, mutex, reltime))) { + case DDS_RETCODE_OUT_OF_RESOURCES: + abort(); + case DDS_RETCODE_TIMEOUT: + return false; + default: + assert(rc == DDS_RETCODE_OK); + break; + } + + return true; +} + +void ddsrt_cond_signal(ddsrt_cond_t *cond) +{ + TaskHandle_t task; + + assert(cond != NULL); + + xSemaphoreTake(cond->sem, portMAX_DELAY); + if ((task = ddsrt_tasklist_pop(&cond->tasks, NULL)) != NULL) { + xTaskNotifyGive(task); + } + xSemaphoreGive(cond->sem); +} + +void ddsrt_cond_broadcast(ddsrt_cond_t *cond) +{ + TaskHandle_t task; + + assert(cond != NULL); + + xSemaphoreTake(cond->sem, portMAX_DELAY); + while ((task = ddsrt_tasklist_pop(&cond->tasks, NULL)) != NULL) { + xTaskNotifyGive(task); + } + xSemaphoreGive(cond->sem); +} + +#define WRITE_LOCKED (-1) +#define UNLOCKED (0) +#define READ_LOCKED (1) + +void ddsrt_rwlock_init(ddsrt_rwlock_t *rwlock) +{ + SemaphoreHandle_t sem; + ddsrt_tasklist_t tasks; + + assert(rwlock != NULL); + + if (ddsrt_tasklist_init(&tasks) == -1) { + abort(); + } + if ((sem = xSemaphoreCreateMutex()) == NULL) { + ddsrt_tasklist_fini(&tasks); + abort(); + } + + memset(rwlock, 0, sizeof(*rwlock)); + rwlock->sem = sem; + rwlock->tasks = tasks; + rwlock->state = UNLOCKED; +} + +void ddsrt_rwlock_destroy(ddsrt_rwlock_t *rwlock) +{ + assert(rwlock != NULL); + + vSemaphoreDelete(rwlock->sem); + ddsrt_tasklist_fini(&rwlock->tasks); + memset(rwlock, 0, sizeof(*rwlock)); +} + +void ddsrt_rwlock_read(ddsrt_rwlock_t *rwlock) +{ + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + + assert(rwlock != NULL); + + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + rwlock->rdcnt++; + if (rwlock->wrcnt != 0) { + ddsrt_tasklist_push(&rwlock->tasks, task); + /* Discard pending notifications. */ + ulTaskNotifyTake(1, 0); + xSemaphoreGive(rwlock->sem); + /* Wait to be notified. */ + ulTaskNotifyTake(1, portMAX_DELAY); + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + ddsrt_tasklist_pop(&rwlock->tasks, task); + } + assert(rwlock->state == UNLOCKED || + rwlock->state == READ_LOCKED); + rwlock->cnt++; + rwlock->state = READ_LOCKED; + /* Notify next task, if any. */ + if ((task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL) { + xTaskNotifyGive(task); + } + xSemaphoreGive(rwlock->sem); +} + +void ddsrt_rwlock_write(ddsrt_rwlock_t *rwlock) +{ + TaskHandle_t task = xTaskGetCurrentTaskHandle(); + + assert(rwlock != NULL); + + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + rwlock->wrcnt++; + if (rwlock->rdcnt != 0 || rwlock->wrcnt != 1) { + ddsrt_tasklist_push(&rwlock->tasks, task); + do { + /* Discard pending notifications. */ + ulTaskNotifyTake(1, 0); + xSemaphoreGive(rwlock->sem); + /* Wait to be notified. */ + ulTaskNotifyTake(1, portMAX_DELAY); + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + } while (rwlock->state != UNLOCKED); + ddsrt_tasklist_pop(&rwlock->tasks, task); + } + assert(rwlock->cnt == 0); + assert(rwlock->state == UNLOCKED); + rwlock->cnt++; + rwlock->state = WRITE_LOCKED; + xSemaphoreGive(rwlock->sem); +} + +bool ddsrt_rwlock_tryread(ddsrt_rwlock_t *rwlock) +{ + bool locked = false; + TaskHandle_t task; + + assert(rwlock != NULL); + + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + if (rwlock->wrcnt == 0) { + locked = true; + rwlock->cnt++; + rwlock->rdcnt++; + rwlock->state = READ_LOCKED; + /* Notify next task, if any. */ + if ((task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL) { + xTaskNotifyGive(task); + } + } + xSemaphoreGive(rwlock->sem); + + return locked; +} + +bool ddsrt_rwlock_trywrite(ddsrt_rwlock_t *rwlock) +{ + bool locked = false; + + assert(rwlock != NULL); + + xSemaphoreTake(rwlock->sem, 0); + if (rwlock->rdcnt == 0 && rwlock->wrcnt == 0) { + locked = true; + rwlock->cnt++; + rwlock->wrcnt++; + rwlock->state = WRITE_LOCKED; + } + xSemaphoreGive(rwlock->sem); + + return locked; +} + +void ddsrt_rwlock_unlock(ddsrt_rwlock_t *rwlock) +{ + TaskHandle_t task; + + assert(rwlock != NULL); + + xSemaphoreTake(rwlock->sem, portMAX_DELAY); + assert(rwlock->cnt != 0); + rwlock->cnt--; + if (rwlock->state == READ_LOCKED) { + assert(rwlock->rdcnt != 0); + rwlock->rdcnt--; + if (rwlock->rdcnt == 0) { + rwlock->state = UNLOCKED; + } + } else { + assert(rwlock->state == WRITE_LOCKED); + assert(rwlock->wrcnt != 0); + assert(rwlock->cnt == 0); + rwlock->wrcnt--; + rwlock->state = UNLOCKED; + } + /* Notify next task, if any. */ + if ((rwlock->state == UNLOCKED) && + (task = ddsrt_tasklist_peek(&rwlock->tasks, NULL)) != NULL) + { + assert(rwlock->rdcnt != 0 || + rwlock->wrcnt != 0); + xTaskNotifyGive(task); + } + xSemaphoreGive(rwlock->sem); +} + +#define ONCE_NOT_STARTED (1<<0) +#define ONCE_IN_PROGRESS (1<<1) +#define ONCE_FINISHED (1<<2) + +/* Wait one millisecond (tick) between polls. */ +static const TickType_t once_delay = (configTICK_RATE_HZ / 1000); + +void +ddsrt_once( + ddsrt_once_t *control, + ddsrt_once_fn init_fn) +{ + int ret, brk = 0; + uint32_t stat; + + while (brk == 0) { + stat = ddsrt_atomic_ld32(control); + /* Verify once control was initialized properly. */ + assert(stat == ONCE_NOT_STARTED || + stat == ONCE_IN_PROGRESS || + stat == ONCE_FINISHED); + + if ((stat & ONCE_FINISHED) != 0) { + /* The initialization function has been executed. No reason to block + execution of this thread. Continue. */ + brk = 1; + } else if ((stat & ONCE_IN_PROGRESS) != 0) { + /* Another thread is executing the initialization function. Wait around + for it to be finished. The polling loop is required because FreeRTOS + does not offer futexes. */ + vTaskDelay(once_delay); + /* Repeat. */ + } else { + /* No thread was executing the initialization function (one might be + executing it now) at the time of the load. If the atomic compare and + swap operation is successful, this thread will run the initialization + function. */ + if (ddsrt_atomic_cas32( + control, ONCE_NOT_STARTED, ONCE_IN_PROGRESS) != 0) + { + /* Function must never block or yield, see reference manual. */ + init_fn(); + + ret = (0 == ddsrt_atomic_cas32( + control, ONCE_IN_PROGRESS, ONCE_FINISHED)); + assert(ret == 0); (void)ret; + + brk = 1; + } else { + /* Another thread updated the state first. Repeat. */ + } + } + } + + return; +} diff --git a/src/ddsrt/src/sync/freertos/tasklist.c b/src/ddsrt/src/sync/freertos/tasklist.c new file mode 100644 index 0000000..6d03415 --- /dev/null +++ b/src/ddsrt/src/sync/freertos/tasklist.c @@ -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 +#include +#include + +#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; +} diff --git a/src/ddsrt/src/sync/solaris2.6/sync.c b/src/ddsrt/src/sync/solaris2.6/sync.c new file mode 100644 index 0000000..884f597 --- /dev/null +++ b/src/ddsrt/src/sync/solaris2.6/sync.c @@ -0,0 +1,236 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include + +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/timeconv.h" + +void ddsrt_mutex_init (ddsrt_mutex_t *mutex) +{ + int shared; + assert (mutex != NULL); + + pthread_mutex_init (&mutex->mutex, NULL); + (void)shared; +} + +void ddsrt_mutex_destroy (ddsrt_mutex_t *mutex) +{ + assert (mutex != NULL); + + if (pthread_mutex_destroy (&mutex->mutex) != 0) + abort(); +} + +void ddsrt_mutex_lock (ddsrt_mutex_t *mutex) +{ + assert (mutex != NULL); + + if (pthread_mutex_lock (&mutex->mutex) != 0) + abort(); +} + +bool +ddsrt_mutex_trylock (ddsrt_mutex_t *mutex) +{ + int err; + assert (mutex != NULL); + + err = pthread_mutex_trylock (&mutex->mutex); + if (err != 0 && err != EBUSY) + abort(); + return (err == 0); +} + +void +ddsrt_mutex_unlock (ddsrt_mutex_t *mutex) +{ + assert (mutex != NULL); + + if (pthread_mutex_unlock (&mutex->mutex) != 0) + abort(); +} + +void +ddsrt_cond_init (ddsrt_cond_t *cond) +{ + assert (cond != NULL); + + pthread_cond_init (&cond->cond, NULL); +} + +void +ddsrt_cond_destroy (ddsrt_cond_t *cond) +{ + assert (cond != NULL); + + if (pthread_cond_destroy (&cond->cond) != 0) + abort(); +} + +void +ddsrt_cond_wait (ddsrt_cond_t *cond, ddsrt_mutex_t *mutex) +{ + assert (cond != NULL); + assert (mutex != NULL); + + if (pthread_cond_wait (&cond->cond, &mutex->mutex) != 0) + abort(); +} + +bool +ddsrt_cond_waituntil( + ddsrt_cond_t *cond, + ddsrt_mutex_t *mutex, + dds_time_t abstime) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; + + assert(cond != NULL); + assert(mutex != NULL); + + if (abstime == DDS_NEVER) { + ddsrt_cond_wait(cond, mutex); + return true; + } + if (abstime > 0) { + ts.tv_sec = abstime / DDS_NSECS_IN_SEC; + ts.tv_nsec = abstime % DDS_NSECS_IN_SEC; + } + + switch (pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts)) { + case 0: + return true; + case ETIMEDOUT: + return false; + default: + break; + } + + abort(); +} + +bool +ddsrt_cond_waitfor( + ddsrt_cond_t *cond, + ddsrt_mutex_t *mutex, + dds_duration_t reltime) +{ + assert(cond != NULL); + assert(mutex != NULL); + + return ddsrt_cond_waituntil( + cond, mutex, ddsrt_time_add_duration(dds_time(), reltime)); +} + +void +ddsrt_cond_signal (ddsrt_cond_t *cond) +{ + assert (cond != NULL); + + if (pthread_cond_signal (&cond->cond) != 0) + abort(); +} + +void +ddsrt_cond_broadcast (ddsrt_cond_t *cond) +{ + assert (cond != NULL); + + if (pthread_cond_broadcast (&cond->cond) != 0) + abort(); +} + +void +ddsrt_rwlock_init (ddsrt_rwlock_t *rwlock) +{ + int err = 0; + + assert(rwlock != NULL); + + /* process-shared attribute is set to PTHREAD_PROCESS_PRIVATE by default */ + if ((err = pthread_mutex_init(&rwlock->rwlock, NULL)) != 0) + abort(); +} + +void +ddsrt_rwlock_destroy (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + if ((err = pthread_mutex_destroy (&rwlock->rwlock)) != 0) + abort(); +} + +void ddsrt_rwlock_read (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + err = pthread_mutex_lock(&rwlock->rwlock); + assert(err == 0); + (void)err; +} + +void ddsrt_rwlock_write (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + err = pthread_mutex_lock (&rwlock->rwlock); + assert(err == 0); + (void)err; +} + +bool ddsrt_rwlock_tryread (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + err = pthread_mutex_trylock(&rwlock->rwlock); + assert(err == 0 || err == EBUSY); + return err == 0; +} + +bool ddsrt_rwlock_trywrite (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + err = pthread_mutex_trylock(&rwlock->rwlock); + assert(err == 0 || err == EBUSY); + + return err == 0; +} + +void ddsrt_rwlock_unlock (ddsrt_rwlock_t *rwlock) +{ + int err; + + assert(rwlock != NULL); + err = pthread_mutex_unlock(&rwlock->rwlock); + assert(err == 0); + (void)err; +} + +void ddsrt_once (ddsrt_once_t *control, ddsrt_once_fn init_fn) +{ + /* There are no defined errors that can be returned by pthread_once */ + (void)pthread_once(control, init_fn); +} diff --git a/src/ddsrt/src/thread_pool.c b/src/ddsrt/src/thread_pool.c index 48cba27..bc240e4 100644 --- a/src/ddsrt/src/thread_pool.c +++ b/src/ddsrt/src/thread_pool.c @@ -88,13 +88,13 @@ static uint32_t ddsrt_thread_start_fn (void * arg) return 0; } -static dds_retcode_t ddsrt_thread_pool_new_thread (ddsrt_thread_pool pool) +static dds_return_t ddsrt_thread_pool_new_thread (ddsrt_thread_pool pool) { static unsigned char pools = 0; /* Pool counter - TODO make atomic */ char name [64]; ddsrt_thread_t id; - dds_retcode_t res; + dds_return_t res; (void) snprintf (name, sizeof (name), "OSPL-%u-%u", pools++, pool->m_count++); res = ddsrt_thread_create (&id, name, &pool->m_attr, &ddsrt_thread_start_fn, pool); @@ -205,9 +205,9 @@ void ddsrt_thread_pool_free (ddsrt_thread_pool pool) ddsrt_free (pool); } -dds_retcode_t ddsrt_thread_pool_submit (ddsrt_thread_pool pool, void (*fn) (void *arg), void * arg) +dds_return_t ddsrt_thread_pool_submit (ddsrt_thread_pool pool, void (*fn) (void *arg), void * arg) { - dds_retcode_t res = DDS_RETCODE_OK; + dds_return_t res = DDS_RETCODE_OK; ddsi_work_queue_job_t job; ddsrt_mutex_lock (&pool->m_mutex); diff --git a/src/ddsrt/src/threads/freertos/threads.c b/src/ddsrt/src/threads/freertos/threads.c new file mode 100644 index 0000000..be4e177 --- /dev/null +++ b/src/ddsrt/src/threads/freertos/threads.c @@ -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 +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/threads_priv.h" + +typedef enum { + THREAD_STARTING = 0, + THREAD_RUNNING, + THREAD_EXITING /* Indicates the thread has returned from the specified + start_routine, but FreeRTOS may not report it as deleted + yet. */ +} thread_state_t; + +typedef struct { + ddsrt_thread_routine_t func; + void *arg; + TaskHandle_t task; /* Thread identifier for looking up thread context from + another thread. Read-only, read by other threads. */ + thread_state_t stat; + thread_cleanup_t *dtors; /* Cleanup routines. Private. */ + uint32_t ret; /* Return value. NULL if thread has not terminated, maybe + NULL if thread has terminated, read by other thread(s) + after termination. */ + TaskHandle_t blkd; /* Thread blocked until thread terminates. may or may + not be empty when thread terminates. Written by other + thread, protected by registry mutex. */ +} thread_context_t; + +/* Thread registry (in combination with thread context) is required to properly + implement thread join functionality. */ + +/* Threads have their own context. The context is automatically allocated and + initialized, either when the thread is created (local threads) or when the + API is first used. */ + +/* FIXME: The same mechanism more-or-less exists in DDSI, perhaps more of the + logic in DDSI can be moved down at some point? */ +typedef struct { + ddsrt_mutex_t mutex; + /* The number of available spaces in the thread context array does not have + to equal the number of used spaces. e.g. when a memory allocation for a + new thread context array fails when destroying a context it is better to + leave one space unused. */ + thread_context_t **ctxs; + size_t cnt; + size_t len; +} thread_registry_t; + +static ddsrt_thread_local thread_context_t *thread_context = NULL; + +static thread_registry_t thread_registry; + +static ddsrt_once_t thread_registry_once = DDSRT_ONCE_INIT; + +static uint32_t non_local_thread(void *arg) { (void)arg; return 0;} + +/* FreeRTOS documentation states vTaskGetInfo is intended for debugging because + its use results in the scheduler remaining suspended for an extended period, + but the scheduler is only suspended if eTaskState is not eInvalid. */ +ddsrt_tid_t +ddsrt_gettid(void) +{ + TaskStatus_t status; + + vTaskGetInfo(xTaskGetCurrentTaskHandle(), &status, pdFALSE, eInvalid); + + return status.xTaskNumber; +} + +ddsrt_thread_t +ddsrt_thread_self(void) +{ + ddsrt_thread_t thr = { .task = xTaskGetCurrentTaskHandle() }; + + return thr; +} + +bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b) +{ + return (a.task == b.task); +} + +size_t +ddsrt_thread_getname(char *__restrict name, size_t size) +{ + char *ptr; + + assert(name != NULL); + assert(size >= 1); + + if ((ptr = pcTaskGetName(NULL)) == NULL) { + ptr = ""; + } + + return ddsrt_strlcpy(name, ptr, size); +} + +static void +thread_registry_init(void) +{ + /* One time initialization guaranteed by ddsrt_once. */ + (void)memset(&thread_registry, 0, sizeof(thread_registry)); + ddsrt_mutex_init(&thread_registry.mutex); +} + +static thread_context_t * +thread_context_find(TaskHandle_t task) +{ + thread_context_t *ctx = NULL; + + for (size_t i = 0; i < thread_registry.cnt && ctx == NULL; i++) { + if (thread_registry.ctxs[i] != NULL && + thread_registry.ctxs[i]->task == task) + { + ctx = thread_registry.ctxs[i]; + } + } + + return ctx; +} + +static dds_return_t +thread_context_create(thread_context_t **ctxptr) +{ + dds_return_t rc = DDS_RETCODE_OK; + size_t len; + thread_context_t *ctx = NULL, **ctxs = NULL; + + assert(ctxptr != NULL); + + ctx = ddsrt_calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + if (thread_registry.cnt < thread_registry.len) { + len = thread_registry.len; + ctxs = thread_registry.ctxs; + } else { + assert(thread_registry.cnt == thread_registry.len); + len = thread_registry.len + 1; + ctxs = ddsrt_realloc(thread_registry.ctxs, len * sizeof(ctx)); + } + + if (ctxs == NULL) { + ddsrt_free(ctx); + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + ctxs[thread_registry.cnt++] = *ctxptr = ctx; + thread_registry.len = len; + thread_registry.ctxs = ctxs; + } + } + + return rc; +} + +#define thread_context_require() thread_context_acquire(NULL) + +static dds_return_t +thread_context_acquire(thread_context_t **ctxptr) +{ + dds_return_t rc = DDS_RETCODE_OK; + thread_context_t *ctx = thread_context; + + if (ctx == NULL) { + /* Dynamically initialize global thread registry (exactly once). */ + ddsrt_once(&thread_registry_once, &thread_registry_init); + + ddsrt_mutex_lock(&thread_registry.mutex); + if ((rc = thread_context_create(&ctx)) == 0) { + /* This situation only arises for non-native (not created in our code) + threads. Some members must therefore still be initialized to ensure + proper operation. */ + ctx->func = &non_local_thread; + ctx->stat = THREAD_RUNNING; + ctx->task = xTaskGetCurrentTaskHandle(); + } + ddsrt_mutex_unlock(&thread_registry.mutex); + thread_context = ctx; + } else { + assert(ctx->func != NULL); + assert(ctx->stat == THREAD_RUNNING); + assert(ctx->task == xTaskGetCurrentTaskHandle()); + } + + if (rc == DDS_RETCODE_OK && ctxptr != NULL) { + assert(ctx != NULL); + *ctxptr = ctx; + } + + return rc; +} + +static void +thread_context_destroy(thread_context_t *ctx) +{ + size_t i = 0; + thread_context_t **arr; + + if (ctx != NULL) { + while (i < thread_registry.cnt && thread_registry.ctxs[i] != ctx) { + i++; + } + + if (i < thread_registry.cnt) { + thread_registry.ctxs[i] = NULL; + if (i < (thread_registry.cnt - 1)) { + (void)memmove( + thread_registry.ctxs + (i), + thread_registry.ctxs + (i+1), + (thread_registry.cnt - (i+1)) * sizeof(*thread_registry.ctxs)); + } + thread_registry.cnt--; + + /* Free contexts when count reaches zero. */ + if (thread_registry.cnt == 0) { + ddsrt_free(thread_registry.ctxs); + thread_registry.ctxs = NULL; + thread_registry.len = 0; + } else { + arr = ddsrt_realloc( + thread_registry.ctxs, + thread_registry.cnt * sizeof(*thread_registry.ctxs)); + /* Ignore allocation failure, save free spot. */ + if (arr != NULL) { + thread_registry.ctxs = arr; + thread_registry.len = thread_registry.cnt; + } + } + } + + ddsrt_free(ctx); + } +} + +static void +thread_fini(thread_context_t *ctx, uint32_t ret) +{ + thread_cleanup_t *tail; + + assert(ctx != NULL); + + /* Acquire registry lock to publish task result and state. */ + ddsrt_mutex_lock(&thread_registry.mutex); + + /* Pop all cleanup handlers from the thread's cleanup stack. */ + while ((tail = ctx->dtors) != NULL) { + ctx->dtors = tail->prev; + if (tail->routine != 0) { + tail->routine(tail->arg); + } + ddsrt_free(tail); + } + + /* FreeRTOS can report task state, but doesn't register the result or + notifies a thread that wants to join. */ + ctx->ret = ret; + ctx->stat = THREAD_EXITING; + + /* Thread resources will be leaked (especially for non-local threads) + if not reclaimed by a thread join. Local threads (threads created + within the DDS stack) are required to be joined. Thread resource + leakage for local threads must be considered a bug. Non-local + threads, however, are not aware that there are resources that must + be reclaimed and local threads might not be aware that there are + non-local threads that must be joined. Therefore, if a non-local thread + exits, it's resources are reclaimed if no thread is waiting to join. */ + if (ctx->blkd != NULL) { + /* Task join functionality is based on notifications, as it is + significantly faster than using a queue, semaphore or event group to + perform an equivalent operation. + + When a task receives a notification, it's notification state is set to + pending. When it reads it's notification state, the notification state + is set to not-pending. A task can wait, with an optional time out, for + it's notification state to become pending. */ + + /* Ignore result, there's nothing that can be done on failure and it always + returns pdPASS. */ + (void)xTaskNotifyGive(ctx->blkd); + } else if (ctx->func == &non_local_thread) { + assert(ret == 0); + thread_context_destroy(ctx); + } + + ddsrt_mutex_unlock(&thread_registry.mutex); +} + +static void +thread_start_routine(void *arg) +{ + thread_context_t *ctx = (thread_context_t *)arg; + uint32_t ret; + + ddsrt_mutex_lock(&thread_registry.mutex); + /* Context for the current task is always correctly initialized and + registered at this stage. It's not strictly required to update task + state, but the synchronization itself is. */ + ctx->stat = THREAD_RUNNING; + ddsrt_mutex_unlock(&thread_registry.mutex); + + /* Thread-local storage is initialized by the function that creates the + thread because a reference to the thread's context is stored and + synchronization is considerably easier if it's handled there. */ + + thread_context = ctx; + ret = ctx->func(ctx->arg); + + thread_fini(ctx, ret); /* DO NOT DEREFERENCE THREAD CONTEXT ANYMORE! */ + + /* Delete current task. */ + vTaskDelete(NULL); +} + +/* xTaskCreate takes the stack depth in the number of words (NOT bytes). In + practice this simply means it multiplies the given number with the size + of StackType_t in bytes (see tasks.c). FreeRTOSConfig.h must define + configMINIMAL_STACK_SIZE, which is the stack size in words allocated for + the idle task. */ +#define WORD_SIZE (sizeof(StackType_t)) +/* configMINIMAL_STACK_SIZE is applied as the default stack size. Whether or + not this is considered a sane default depends on the target. The default can + be adjusted in FreeRTOSConfig.h Of course the configuration file also allows + the user to change it on a per-thread basis at runtime. */ +#define MIN_STACK_SIZE ((uint16_t)(configMINIMAL_STACK_SIZE * WORD_SIZE)) + +dds_return_t +ddsrt_thread_create( + ddsrt_thread_t *thread, + const char *name, + const ddsrt_threadattr_t *attr, + ddsrt_thread_routine_t start_routine, + void *arg) +{ + dds_return_t rc; + TaskHandle_t task; + UBaseType_t prio; + uint16_t size = MIN_STACK_SIZE; + thread_context_t *ctx = NULL; + + assert(thread != NULL); + assert(name != NULL); + assert(attr != NULL); + assert(start_routine != 0); + + if ((rc = thread_context_require()) != DDS_RETCODE_OK) { + return rc; + } + + /* Non-realtime scheduling does not exist in FreeRTOS. */ + if (attr->schedClass != DDSRT_SCHED_DEFAULT && + attr->schedClass != DDSRT_SCHED_REALTIME) + { + return DDS_RETCODE_BAD_PARAMETER; + } else if (attr->schedPriority < 0 || + attr->schedPriority > (configMAX_PRIORITIES - 1)) + { + return DDS_RETCODE_BAD_PARAMETER; + } + + /* Stack size is quietly increased to match at least the minimum. */ + if (attr->stackSize > size) { + size = (uint16_t)(attr->stackSize / WORD_SIZE); + if (attr->stackSize % WORD_SIZE) { + size++; + } + } + + /* Assume that when the default priority of zero (0) is specified, the user + wants the thread to inherit the priority of the calling thread. */ + assert(0 == tskIDLE_PRIORITY); + if (attr->schedPriority == 0) { + prio = uxTaskPriorityGet(NULL); + } else { + prio = (UBaseType_t)attr->schedPriority; + } + + ddsrt_mutex_lock(&thread_registry.mutex); + + /* Thread context is allocated here so that it can be handled when no more + memory is available. Simply storing the entire context in thread-local + storage would have been possible, but would require the implementation to + define and allocate a separate struct in order to support thread joins. */ + if ((rc = thread_context_create(&ctx)) == DDS_RETCODE_OK) { + ctx->func = start_routine; + ctx->arg = arg; + + if (pdPASS != xTaskCreate( + &thread_start_routine, name, size, ctx, prio, &task)) + { + thread_context_destroy(ctx); + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + thread->task = ctx->task = task; + } + } + + ddsrt_mutex_unlock(&thread_registry.mutex); + + return rc; +} + +void +ddsrt_thread_init(void) +{ + if (thread_context_require() != DDS_RETCODE_OK) { + assert(0); + } +} + +void +ddsrt_thread_fini(void) +{ + thread_context_t *ctx; + + /* NO-OP if no context exists since thread-local storage and cleanup + handler references are both stored in the thread context. */ + if ((ctx = thread_context) != NULL) { + assert(ctx->func != &non_local_thread); + thread_fini(ctx, 0); + } +} + +dds_return_t +ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result) +{ + dds_return_t rc; + thread_context_t *ctx; + eTaskState status; + + if ((rc = thread_context_require()) != DDS_RETCODE_OK) { + return rc; + } + + ddsrt_mutex_lock(&thread_registry.mutex); + ctx = thread_context_find(thread.task); + if (ctx != NULL) { + /* Task should never be joined by multiple tasks simultaneously */ + assert(ctx->blkd == NULL); + rc = DDS_RETCODE_TRY_AGAIN; + + do { + (void)memset(&status, 0, sizeof(status)); + status = eTaskGetState(thread.task); + if (status == eDeleted) { + /* FreeRTOS reports the task is deleted. Require the context to exist, + fetch the result and free the context afterwards. */ + assert(ctx != NULL); + rc = DDS_RETCODE_OK; + } else if (status != eInvalid) { + assert(ctx != NULL); + /* FreeRTOS reports the task is still active. That does not mean the + task has not yet returned from start_routine. */ + if (ctx->stat == THREAD_EXITING) { + /* Thread context will not be accessed by the thread itself anymore + and it should be safe to free it. */ + rc = DDS_RETCODE_OK; + } else { + ctx->blkd = xTaskGetCurrentTaskHandle(); + + /* Reset notify state and counter. */ + ulTaskNotifyTake(pdTRUE, 0); + + ddsrt_mutex_unlock(&thread_registry.mutex); + + /* Wait to be notified. */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + ddsrt_mutex_lock(&thread_registry.mutex); + } + } else { + rc = DDS_RETCODE_BAD_PARAMETER; + } + } while (rc == DDS_RETCODE_TRY_AGAIN); + + if (rc == DDS_RETCODE_OK) { + if (thread_result != NULL) { + *thread_result = ctx->ret; + } + thread_context_destroy(ctx); + } + } + + ddsrt_mutex_unlock(&thread_registry.mutex); + + return rc; +} + +dds_return_t +ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg) +{ + dds_return_t rc = DDS_RETCODE_OK; + thread_cleanup_t *tail = NULL; + thread_context_t *ctx; + + assert(routine != NULL); + + if (thread_context_acquire(&ctx) == 0) { + if ((tail = ddsrt_malloc(sizeof(*tail))) == NULL) { + rc = DDS_RETCODE_OUT_OF_RESOURCES; + } else { + tail->prev = ctx->dtors; + tail->routine = routine; + tail->arg = arg; + ctx->dtors = tail; + } + } + + return rc; +} + +dds_return_t +ddsrt_thread_cleanup_pop(int execute) +{ + thread_cleanup_t *tail; + thread_context_t *ctx; + + if (thread_context_acquire(&ctx) == 0) { + if ((tail = ctx->dtors) != NULL) { + ctx->dtors = tail->prev; + if (execute) { + tail->routine(tail->arg); + } + ddsrt_free(tail); + } + } + + return DDS_RETCODE_OK; +} diff --git a/src/ddsrt/src/threads/include/dds/ddsrt/threads_priv.h b/src/ddsrt/src/threads/include/dds/ddsrt/threads_priv.h index b10118c..659a201 100644 --- a/src/ddsrt/src/threads/include/dds/ddsrt/threads_priv.h +++ b/src/ddsrt/src/threads/include/dds/ddsrt/threads_priv.h @@ -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; diff --git a/src/ddsrt/src/threads/posix/threads.c b/src/ddsrt/src/threads/posix/threads.c index f8dbf4c..bbf5f8d 100644 --- a/src/ddsrt/src/threads/posix/threads.c +++ b/src/ddsrt/src/threads/posix/threads.c @@ -30,12 +30,24 @@ #include "dds/ddsrt/string.h" #include "dds/ddsrt/threads_priv.h" #include "dds/ddsrt/types.h" +#include "dds/ddsrt/static_assert.h" + +typedef struct { + char *name; + ddsrt_thread_routine_t routine; + void *arg; +} thread_context_t; #if defined(__linux) #include +#include #define MAXTHREADNAMESIZE (15) /* 16 bytes including null-terminating byte. */ #elif defined(__APPLE__) +#include #include /* MAXTHREADNAMESIZE */ +#include +#include +#include #elif defined(__sun) #define MAXTHREADNAMESIZE (31) #elif defined(__FreeBSD__) @@ -74,7 +86,11 @@ ddsrt_thread_getname(char *str, size_t size) (void)pthread_get_name_np(pthread_self(), buf, sizeof(buf)); cnt = ddsrt_strlcpy(str, buf, size); #elif defined(__sun) +#if !(__SunOS_5_6 || __SunOS_5_7 || __SunOS_5_8 || __SunOS_5_9 || __SunOS_5_10) (void)pthread_getname_np(pthread_self(), buf, sizeof(buf)); +#else + buf[0] = 0; +#endif cnt = ddsrt_strlcpy(str, buf, size); #elif defined(__VXWORKS__) { @@ -119,7 +135,9 @@ ddsrt_thread_setname(const char *__restrict name) #elif defined(__sun) /* Thread names are limited to 31 bytes on Solaris. Excess bytes are silently truncated. */ +#if !(__SunOS_5_6 || __SunOS_5_7 || __SunOS_5_8 || __SunOS_5_9 || __SunOS_5_10) (void)pthread_setname_np(pthread_self(), name); +#endif #else /* VxWorks does not support the task name to be set after a task is created. Setting the name of a task can be done through pthread_attr_setname. */ @@ -181,7 +199,7 @@ static void *os_startRoutineWrapper (void *threadContext) return (void *)resultValue; } -dds_retcode_t +dds_return_t ddsrt_thread_create ( ddsrt_thread_t *threadptr, const char *name, @@ -340,7 +358,7 @@ bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b) return (pthread_equal(a.v, b.v) != 0); } -dds_retcode_t +dds_return_t ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result) { int err; @@ -351,7 +369,7 @@ ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result) if ((err = pthread_join (thread.v, &vthread_result)) != 0) { - DDS_TRACE ("pthread_join(0x%"PRIxMAX") failed with error %d\n", (uintmax_t)((uintptr_t)thread.v), err); + DDS_ERROR ("pthread_join(0x%"PRIxMAX") failed with error %d\n", (uintmax_t)((uintptr_t)thread.v), err); return DDS_RETCODE_ERROR; } @@ -360,6 +378,104 @@ ddsrt_thread_join(ddsrt_thread_t thread, uint32_t *thread_result) return DDS_RETCODE_OK; } +#if defined __linux +dds_return_t +ddsrt_thread_list ( + ddsrt_thread_list_id_t * __restrict tids, + size_t size) +{ + DIR *dir; + struct dirent *de; + if ((dir = opendir ("/proc/self/task")) == NULL) + return DDS_RETCODE_ERROR; + dds_return_t n = 0; + while ((de = readdir (dir)) != NULL) + { + if (de->d_name[0] == '.' && (de->d_name[1] == 0 || (de->d_name[1] == '.' && de->d_name[2] == 0))) + continue; + int pos; + long tid; + if (sscanf (de->d_name, "%ld%n", &tid, &pos) != 1 || de->d_name[pos] != 0) + { + n = DDS_RETCODE_ERROR; + break; + } + if ((size_t) n < size) + tids[n] = (ddsrt_thread_list_id_t) tid; + n++; + } + closedir (dir); + /* If there were no threads, something must've gone badly wrong */ + return (n == 0) ? DDS_RETCODE_ERROR : n; +} + +dds_return_t +ddsrt_thread_getname_anythread ( + ddsrt_thread_list_id_t tid, + char *__restrict name, + size_t size) +{ + char file[100]; + FILE *fp; + int pos; + pos = snprintf (file, sizeof (file), "/proc/self/task/%lu/stat", (unsigned long) tid); + if (pos < 0 || pos >= (int) sizeof (file)) + return DDS_RETCODE_ERROR; + if ((fp = fopen (file, "r")) == NULL) + return DDS_RETCODE_NOT_FOUND; + int c; + size_t namelen = 0, namepos = 0; + while ((c = fgetc (fp)) != EOF) + if (c == '(') + break; + while ((c = fgetc (fp)) != EOF) + { + if (c == ')') + namelen = namepos; + if (namepos + 1 < size) + name[namepos++] = (char) c; + } + fclose (fp); + assert (size == 0 || namelen < size); + if (size > 0) + name[namelen] = 0; + return DDS_RETCODE_OK; +} +#elif defined __APPLE__ +DDSRT_STATIC_ASSERT (sizeof (ddsrt_thread_list_id_t) == sizeof (mach_port_t)); + +dds_return_t +ddsrt_thread_list ( + ddsrt_thread_list_id_t * __restrict tids, + size_t size) +{ + thread_act_array_t tasks; + mach_msg_type_number_t count; + if (task_threads (mach_task_self (), &tasks, &count) != KERN_SUCCESS) + return DDS_RETCODE_ERROR; + for (mach_msg_type_number_t i = 0; i < count && (size_t) i < size; i++) + tids[i] = (ddsrt_thread_list_id_t) tasks[i]; + vm_deallocate (mach_task_self (), (vm_address_t) tasks, count * sizeof (thread_act_t)); + return (dds_return_t) count; +} + +dds_return_t +ddsrt_thread_getname_anythread ( + ddsrt_thread_list_id_t tid, + char *__restrict name, + size_t size) +{ + if (size > 0) + { + pthread_t pt = pthread_from_mach_thread_np ((mach_port_t) tid); + name[0] = '\0'; + if (pt == NULL || pthread_getname_np (pt, name, size) != 0 || name[0] == 0) + snprintf (name, size, "task%"PRIu64, (uint64_t) tid); + } + return DDS_RETCODE_OK; +} +#endif + static pthread_key_t thread_cleanup_key; static pthread_once_t thread_once = PTHREAD_ONCE_INIT; @@ -380,7 +496,7 @@ static void thread_init(void) (void)pthread_once(&thread_once, &thread_init_once); } -dds_retcode_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg) +dds_return_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg) { int err; thread_cleanup_t *prev, *tail; @@ -402,7 +518,7 @@ dds_retcode_t ddsrt_thread_cleanup_push (void (*routine) (void *), void *arg) return DDS_RETCODE_OUT_OF_RESOURCES; } -dds_retcode_t ddsrt_thread_cleanup_pop (int execute) +dds_return_t ddsrt_thread_cleanup_pop (int execute) { int err; thread_cleanup_t *tail; diff --git a/src/ddsrt/src/threads/windows/threads.c b/src/ddsrt/src/threads/windows/threads.c index ffba453..ab83246 100644 --- a/src/ddsrt/src/threads/windows/threads.c +++ b/src/ddsrt/src/threads/windows/threads.c @@ -16,6 +16,66 @@ #include "dds/ddsrt/string.h" #include "dds/ddsrt/threads_priv.h" +/* tlhelp32 for ddsrt_thread_list */ +#include +#include +#include + +/* {Get,Set}ThreadDescription is the Windows 10 interface for dealing with thread names, but it at + least in some setups the linker can't find the symbols in kernel32.lib, even though kernel32.dll + exports them. (Perhaps it is just a broken installation, who knows ...) Looking them up + dynamically works fine. */ +typedef HRESULT (WINAPI *SetThreadDescription_t) (HANDLE hThread, PCWSTR lpThreadDescription); +typedef HRESULT (WINAPI *GetThreadDescription_t) (HANDLE hThread, PWSTR *ppszThreadDescription); +static volatile SetThreadDescription_t SetThreadDescription_ptr = 0; +static volatile GetThreadDescription_t GetThreadDescription_ptr = 0; + +static HRESULT WINAPI SetThreadDescription_dummy (HANDLE hThread, PCWSTR lpThreadDescription) +{ + (void) hThread; + (void) lpThreadDescription; + return E_FAIL; +} + +static HRESULT WINAPI GetThreadDescription_dummy (HANDLE hThread, PWSTR *ppszThreadDescription) +{ + (void) hThread; + return E_FAIL; +} + +static void getset_threaddescription_addresses (void) +{ + /* Rely on MSVC's interpretation of the meaning of volatile + to order checking & setting the pointers */ + if (GetThreadDescription_ptr == 0) + { + HMODULE mod; + FARPROC p; + if (!GetModuleHandleExA (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "kernel32.dll", &mod)) + { + SetThreadDescription_ptr = SetThreadDescription_dummy; + GetThreadDescription_ptr = GetThreadDescription_dummy; + } + else + { + if ((p = GetProcAddress (mod, "SetThreadDescription")) != 0) + SetThreadDescription_ptr = (SetThreadDescription_t) p; + else + SetThreadDescription_ptr = SetThreadDescription_dummy; + if ((p = GetProcAddress (mod, "GetThreadDescription")) != 0) + GetThreadDescription_ptr = (GetThreadDescription_t) p; + else + GetThreadDescription_ptr = GetThreadDescription_dummy; + } + } +} + +typedef struct { + char *name; + ddsrt_thread_routine_t routine; + void *arg; +} thread_context_t; + static uint32_t os_startRoutineWrapper( void *threadContext) @@ -37,7 +97,7 @@ os_startRoutineWrapper( return resultValue; } -dds_retcode_t +dds_return_t ddsrt_thread_create( ddsrt_thread_t *thrptr, const char *name, @@ -133,7 +193,7 @@ bool ddsrt_thread_equal(ddsrt_thread_t a, ddsrt_thread_t b) * should not be closed until the os_threadWaitExit(...) call is called. * CloseHandle (threadHandle); */ -dds_retcode_t +dds_return_t ddsrt_thread_join( ddsrt_thread_t thread, uint32_t *thread_result) @@ -170,7 +230,10 @@ ddsrt_thread_join( } /* Thread names on Linux are limited to 16 bytes, no reason to provide - more storage than that as internal threads must adhere to that limit. */ + more storage than that as internal threads must adhere to that limit. + Use the thread-local variable instead of relying on GetThreadDescription + to avoid the dynamic memory allocation, as the thread name is used by + the logging code and the overhead there matters. */ static ddsrt_thread_local char thread_name[16] = ""; size_t @@ -191,6 +254,16 @@ ddsrt_thread_getname( return cnt; } +/** \brief Set thread name for debugging and system monitoring + * + * Windows 10 introduced the SetThreadDescription function, which is + * obviously the sane interface. For reasons unknown to me, the + * linker claims to have no knowledge of the function, even though + * they appear present, and so it seems to sensible to retain the + * old exception-based trick as a fall-back mechanism. At least + * until the reason for {Get,Set}Description's absence from the + * regular libraries. + */ static const DWORD MS_VC_EXCEPTION=0x406D1388; #pragma pack(push,8) @@ -203,19 +276,23 @@ typedef struct tagTHREADNAME_INFO } THREADNAME_INFO; #pragma pack(pop) -/** \brief Wrap thread start routine - * - * \b os_startRoutineWrapper wraps a threads starting routine. - * before calling the user routine. It tries to set a thread name - * that will be visible if the process is running under the MS - * debugger. - */ void ddsrt_thread_setname( const char *__restrict name) { - assert(name != NULL); - + assert (name != NULL); + getset_threaddescription_addresses (); + if (SetThreadDescription_ptr != SetThreadDescription_dummy) + { + size_t size = strlen (name) + 1; + wchar_t *wname = malloc (size * sizeof (*wname)); + size_t cnt = 0; + mbstowcs_s (&cnt, wname, size, name, _TRUNCATE); + SetThreadDescription_ptr (GetCurrentThread (), wname); + free (wname); + } + else + { THREADNAME_INFO info; info.dwType = 0x1000; info.szName = name; @@ -235,14 +312,77 @@ ddsrt_thread_setname( /* Suppress warnings. */ } #pragma warning(pop) - - ddsrt_strlcpy(thread_name, name, sizeof(thread_name)); + } + ddsrt_strlcpy (thread_name, name, sizeof (thread_name)); } +dds_return_t +ddsrt_thread_list ( + ddsrt_thread_list_id_t * __restrict tids, + size_t size) +{ + HANDLE hThreadSnap; + THREADENTRY32 te32; + const DWORD pid = GetCurrentProcessId (); + int32_t n = 0; + + if ((hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0)) == INVALID_HANDLE_VALUE) + return 0; + + memset (&te32, 0, sizeof (te32)); + te32.dwSize = sizeof (THREADENTRY32); + if (!Thread32First (hThreadSnap, &te32)) + { + CloseHandle (hThreadSnap); + return 0; + } + + do { + if (te32.th32OwnerProcessID != pid) + continue; + if ((size_t) n < size) + { + /* get a handle to the thread, not counting the thread the thread if no such + handle is obtainable */ + if ((tids[n] = OpenThread (THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID)) == NULL) + continue; + } + n++; + } while (Thread32Next (hThreadSnap, &te32)); + CloseHandle (hThreadSnap); + return n; +} + +dds_return_t +ddsrt_thread_getname_anythread ( + ddsrt_thread_list_id_t tid, + char * __restrict name, + size_t size) +{ + getset_threaddescription_addresses (); + if (size > 0) + { + PWSTR data; + HRESULT hr = GetThreadDescription_ptr (tid, &data); + if (! SUCCEEDED (hr)) + name[0] = 0; + else + { + size_t cnt; + wcstombs_s (&cnt, name, size, data, _TRUNCATE); + LocalFree (data); + } + if (name[0] == 0) + { + snprintf (name, sizeof (name), "%"PRIdTID, GetThreadId (tid)); + } + } + return DDS_RETCODE_OK; +} static ddsrt_thread_local thread_cleanup_t *thread_cleanup = NULL; -dds_retcode_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg) +dds_return_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg) { thread_cleanup_t *tail; @@ -259,7 +399,7 @@ dds_retcode_t ddsrt_thread_cleanup_push(void (*routine)(void *), void *arg) return DDS_RETCODE_OUT_OF_RESOURCES; } -dds_retcode_t ddsrt_thread_cleanup_pop(int execute) +dds_return_t ddsrt_thread_cleanup_pop(int execute) { thread_cleanup_t *tail; diff --git a/src/ddsrt/src/time.c b/src/ddsrt/src/time.c index 01e4033..e8c845f 100644 --- a/src/ddsrt/src/time.c +++ b/src/ddsrt/src/time.c @@ -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 void dds_sleepfor(dds_duration_t n) @@ -47,7 +47,12 @@ size_t ddsrt_ctime(dds_time_t n, char *str, size_t size) { struct tm tm; +#if __SunOS_5_6 + /* Solaris 2.6 doesn't recognize %z so we just leave it out */ + static const char fmt[] = "%Y-%m-%d %H:%M:%S"; +#else static const char fmt[] = "%Y-%m-%d %H:%M:%S%z"; +#endif char buf[] = "YYYY-mm-dd HH:MM:SS.hh:mm"; /* RFC 3339 */ size_t cnt; time_t sec = (time_t)(n / DDS_NSECS_IN_SEC); @@ -61,12 +66,14 @@ ddsrt_ctime(dds_time_t n, char *str, size_t size) #endif /* _WIN32 */ cnt = strftime(buf, sizeof(buf), fmt, &tm); +#if ! __SunOS_5_6 + /* %z is without a separator between hours and minutes, fixup */ assert(cnt == (sizeof(buf) - 2 /* ':' + '\0' */)); buf[sizeof(buf) - 1] = '\0'; buf[sizeof(buf) - 2] = buf[sizeof(buf) - 3]; buf[sizeof(buf) - 3] = buf[sizeof(buf) - 4]; buf[sizeof(buf) - 4] = ':'; - +#endif (void)cnt; return ddsrt_strlcpy(str, buf, size); diff --git a/src/ddsrt/src/time/darwin/time.c b/src/ddsrt/src/time/darwin/time.c index a8a35c4..71e2ccb 100644 --- a/src/ddsrt/src/time/darwin/time.c +++ b/src/ddsrt/src/time/darwin/time.c @@ -13,21 +13,29 @@ #include #include #include + +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12 #include +#endif #include "dds/ddsrt/time.h" dds_time_t dds_time(void) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 + return (int64_t) clock_gettime_nsec_np (CLOCK_REALTIME); +#else struct timeval tv; - (void)gettimeofday(&tv, NULL); - return ((tv.tv_sec * DDS_NSECS_IN_SEC) + (tv.tv_usec * DDS_NSECS_IN_USEC)); +#endif } dds_time_t ddsrt_time_monotonic(void) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 + return (int64_t) clock_gettime_nsec_np (CLOCK_UPTIME_RAW); +#else static mach_timebase_info_data_t timeInfo; uint64_t mt; @@ -49,10 +57,15 @@ dds_time_t ddsrt_time_monotonic(void) } return (dds_time_t)(mt * timeInfo.numer / timeInfo.denom); +#endif } dds_time_t ddsrt_time_elapsed(void) { +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 + return (int64_t) clock_gettime_nsec_np (CLOCK_MONOTONIC_RAW); +#else /* Elapsed time clock not (yet) supported on this platform. */ return ddsrt_time_monotonic(); +#endif } diff --git a/src/ddsrt/src/time/freertos/time.c b/src/ddsrt/src/time/freertos/time.c new file mode 100644 index 0000000..39ee345 --- /dev/null +++ b/src/ddsrt/src/time/freertos/time.c @@ -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 +#include +#define _POSIX_TIMERS +#include + +#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); +} diff --git a/src/ddsrt/src/time/solaris2.6/time.c b/src/ddsrt/src/time/solaris2.6/time.c new file mode 100644 index 0000000..0c5fb7c --- /dev/null +++ b/src/ddsrt/src/time/solaris2.6/time.c @@ -0,0 +1,38 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "dds/ddsrt/time.h" + +dds_time_t dds_time(void) +{ + struct timespec ts; + + (void)clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * DDS_NSECS_IN_SEC) + ts.tv_nsec; +} + +dds_time_t ddsrt_time_monotonic(void) +{ + return gethrtime (); +} + +dds_time_t ddsrt_time_elapsed(void) +{ + /* Elapsed time clock not worth the bother for now. */ + return ddsrt_time_monotonic(); +} diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c index ded4337..cd3580f 100644 --- a/src/ddsrt/src/xmlparser.c +++ b/src/ddsrt/src/xmlparser.c @@ -35,6 +35,7 @@ struct ddsrt_xmlp_state { size_t cbufn; /* number of bytes in cbuf (cbufp <= cbufn) */ size_t cbufmax; /* allocated size of cbuf (cbufn <= cbufmax) */ size_t cbufmark; /* NORMARKER or marker position (cbufmark <= cbufp) for rewinding */ + int eof; /* fake EOF (for treating missing close tags as EOF) */ char *cbuf; /* parser input buffer */ FILE *fp; /* file to refill cbuf from, or NULL if parsing a string */ int line; /* current line number */ @@ -53,36 +54,40 @@ struct ddsrt_xmlp_state { struct ddsrt_xmlp_callbacks cb; /* user-supplied callbacks (or stubs) */ }; -static int cb_null_elem_open (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name) +static int cb_null_elem_open (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line) { DDSRT_UNUSED_ARG (varg); DDSRT_UNUSED_ARG (parentinfo); DDSRT_UNUSED_ARG (eleminfo); DDSRT_UNUSED_ARG (name); + DDSRT_UNUSED_ARG (line); return 0; } -static int cb_null_attr (void *varg, uintptr_t eleminfo, const char *name, const char *value) +static int cb_null_attr (void *varg, uintptr_t eleminfo, const char *name, const char *value, int line) { DDSRT_UNUSED_ARG (varg); DDSRT_UNUSED_ARG (eleminfo); DDSRT_UNUSED_ARG (name); DDSRT_UNUSED_ARG (value); + DDSRT_UNUSED_ARG (line); return 0; } -static int cb_null_elem_data (void *varg, uintptr_t eleminfo, const char *data) +static int cb_null_elem_data (void *varg, uintptr_t eleminfo, const char *data, int line) { DDSRT_UNUSED_ARG (varg); DDSRT_UNUSED_ARG (eleminfo); DDSRT_UNUSED_ARG (data); + DDSRT_UNUSED_ARG (line); return 0; } -static int cb_null_elem_close (void *varg, uintptr_t eleminfo) +static int cb_null_elem_close (void *varg, uintptr_t eleminfo, int line) { DDSRT_UNUSED_ARG (varg); DDSRT_UNUSED_ARG (eleminfo); + DDSRT_UNUSED_ARG (line); return 0; } @@ -97,6 +102,7 @@ static void ddsrt_xmlp_new_common (struct ddsrt_xmlp_state *st) { st->cbufp = 0; st->cbufmark = NOMARKER; + st->eof = 0; st->tpp = 0; st->tpescp = 0; st->tpsz = 1024; @@ -170,6 +176,9 @@ void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st) static int make_chars_available (struct ddsrt_xmlp_state *st, size_t nmin) { size_t n, pos; + if (st->eof) { + return 0; + } pos = (st->cbufmark != NOMARKER) ? st->cbufmark : st->cbufp; assert (st->cbufn >= st->cbufp); assert (st->cbufmax >= st->cbufn); @@ -215,6 +224,11 @@ static void discard_input_marker (struct ddsrt_xmlp_state *st) st->linemark = 0; } +static int have_input_marker (struct ddsrt_xmlp_state *st) +{ + return (st->cbufmark != NOMARKER); +} + static void rewind_to_input_marker (struct ddsrt_xmlp_state *st) { assert (st->cbufmark != NOMARKER); @@ -295,9 +309,9 @@ static char *unescape_into_utf8 (char *dst, unsigned cp) return dst; } -DDSRT_WARNING_MSVC_OFF(4996); static int unescape_insitu (char *buffer, size_t *n) { + DDSRT_WARNING_MSVC_OFF(4996); const char *src = buffer; char const * const srcend = buffer + *n; char *dst = buffer; @@ -351,8 +365,8 @@ static int unescape_insitu (char *buffer, size_t *n) } *n = (size_t) (dst - buffer); return 0; + DDSRT_WARNING_MSVC_ON(4996); } -DDSRT_WARNING_MSVC_ON(4996); static void discard_payload (struct ddsrt_xmlp_state *st) { @@ -596,7 +610,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) PE_LOCAL_ERROR ("expecting '<'", 0); } - if ((ret = st->cb.elem_open (st->varg, parentinfo, &eleminfo, name)) < 0) { + if ((ret = st->cb.elem_open (st->varg, parentinfo, &eleminfo, name, st->line)) < 0) { PE_ERROR ("failed in element open callback", name); } @@ -610,7 +624,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) ddsrt_free (content); PE_LOCAL_ERROR ("expecting string value for attribute", aname); } - ret = st->cb.attr (st->varg, eleminfo, aname, content); + ret = st->cb.attr (st->varg, eleminfo, aname, content, st->line); ddsrt_free (content); if (ret < 0) { PE_ERROR2 ("failed in attribute callback", name, aname); @@ -623,7 +637,7 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) switch (tok) { case TOK_SHORTHAND_CLOSE_TAG: - ret = st->cb.elem_close (st->varg, eleminfo); + ret = st->cb.elem_close (st->varg, eleminfo, st->line); goto ok; case '>': st->nest++; @@ -668,8 +682,8 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) if (save_payload (&content, st, 1) < 0) { PE_ERROR ("invalid character sequence", 0); } else if (content != NULL) { - if(*content != '\0') { - ret = st->cb.elem_data (st->varg, eleminfo, content); + if (*content != '\0') { + ret = st->cb.elem_data (st->varg, eleminfo, content, st->line); ddsrt_free (content); if (ret < 0) { PE_ERROR ("failed in data callback", 0); @@ -680,13 +694,23 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) } } st->nest--; + set_input_marker (st); if (((tok = next_token (st, &ename)) != TOK_CLOSE_TAG && tok != TOK_SHORTHAND_CLOSE_TAG) || next_char (st) != '>') { - PE_LOCAL_ERROR ("expecting closing tag", name); + if (!(st->options & DDSRT_XMLP_MISSING_CLOSE_AS_EOF)) { + PE_LOCAL_ERROR ("expecting closing tag", name); + } else { + rewind_to_input_marker (st); + st->eof = 1; + tok = TOK_SHORTHAND_CLOSE_TAG; + } } if (tok != TOK_SHORTHAND_CLOSE_TAG && strcmp (name, ename) != 0) { PE_LOCAL_ERROR ("open/close tag mismatch", ename); } - ret = st->cb.elem_close (st->varg, eleminfo); + if (have_input_marker (st)) { + discard_input_marker (st); + } + ret = st->cb.elem_close (st->varg, eleminfo, st->line); goto ok; default: PE_LOCAL_ERROR ("expecting '/>' or '>'", 0); @@ -722,7 +746,3 @@ int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st) } } } - -int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n) { - return unescape_insitu (buffer, n); -} diff --git a/src/ddsrt/tests/CMakeLists.txt b/src/ddsrt/tests/CMakeLists.txt index db27665..d5b479d 100644 --- a/src/ddsrt/tests/CMakeLists.txt +++ b/src/ddsrt/tests/CMakeLists.txt @@ -10,65 +10,38 @@ # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # include(CUnit) -include(GenerateExportHeader) +include(GenerateDummyExportHeader) -set(sources - "atomics.c" - "dynlib.c" - "environ.c" - "heap.c" - "ifaddrs.c" - "sync.c" - "strtoll.c" - "thread.c" - "thread_cleanup.c" - "string.c" - "log.c" - "random.c" - "strlcpy.c" - "socket.c" - "process.c" - "select.c") +list(APPEND sources + "atomics.c" + "dynlib.c" + "environ.c" + "heap.c" + "ifaddrs.c" + "sync.c" + "strtoll.c" + "thread.c" + "thread_cleanup.c" + "string.c" + "log.c" + "random.c" + "strlcpy.c" + "socket.c" + "select.c") -add_cunit_executable(cunit_ddsrt ${sources}) -target_link_libraries(cunit_ddsrt PRIVATE ddsrt) - -# Create a dummy export header. generate_export_header can only be used with -# library targets, but since the targets are linked statically, -# __declspec(dllimport) is not required anyway. -set(export_dir "${CMAKE_CURRENT_BINARY_DIR}/include/dds") -set(export_header "${export_dir}/export.h") -if(NOT EXISTS "${export_header}") - file(MAKE_DIRECTORY "${export_dir}") - file(WRITE "${export_header}" "#define DDS_EXPORT\n") +if(HAVE_MULTI_PROCESS) + list(APPEND sources "process.c") +endif() +if(WITH_FREERTOS) + list(APPEND sources "tasklist.c") endif() +add_cunit_executable(cunit_ddsrt ${sources}) +target_link_libraries( + cunit_ddsrt PRIVATE ddsrt) target_include_directories( cunit_ddsrt PRIVATE "$") -# Create a separate test application that will be used to -# test process management. -add_executable(process_app process_app.c) -target_link_libraries(process_app PRIVATE ddsrt) -target_include_directories( - process_app - PRIVATE - "$") -# Force the app to be at the same location, no matter what platform or build type. -set_target_properties( - process_app - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} - RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} ) -# Let the cunit application know the location and name of the test application. -set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}") -configure_file( - "process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY) - - # Create a separate shared library that will be used to # test dynamic library loading. @@ -89,7 +62,7 @@ set_target_properties( LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} ) # Use proper export for this test lib. -generate_export_header(${test_lib_name} BASE_NAME LIB_TEST) +#generate_dummy_export_header(${test_lib_name} BASE_NAME dds LIB_TEST) target_include_directories(${test_lib_name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") # Let the cunit application know the location and name of the library. file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" test_lib_native_dir) @@ -112,3 +85,38 @@ foreach(libtest ${test_lib_tests}) endif() endforeach() +generate_dummy_export_header( + cunit_ddsrt + BASE_NAME dds + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/export.h") + +generate_dummy_export_header( + ${test_lib_name} + BASE_NAME lib_test + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/lib_test_export.h") + +if(HAVE_MULTI_PROCESS) + # A separate application is required to test process management. + add_executable(process_app process_app.c) + target_link_libraries(process_app PRIVATE ddsrt) + target_include_directories( + process_app + PRIVATE + "$") + # Force the app to be at the same location, no matter what platform or build type. + # FIXME: What if custom targets are added? + # FIXME: What debug and release builds are mixed on Windows and macOS? + set_target_properties( + process_app + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} ) + # Let the cunit application know the location and name of the test application. + set(process_app_name "${CMAKE_CURRENT_BINARY_DIR}/process_app${CMAKE_EXECUTABLE_SUFFIX}") + configure_file( + "process_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/process_test.h" @ONLY) +endif() + diff --git a/src/ddsrt/tests/dllib.c b/src/ddsrt/tests/dllib.c index 21086e6..b63d34b 100644 --- a/src/ddsrt/tests/dllib.c +++ b/src/ddsrt/tests/dllib.c @@ -13,12 +13,14 @@ static int g_val = -1; -LIB_TEST_EXPORT void set_int(int val) +LIB_TEST_EXPORT void set_int(int val); +void set_int(int val) { g_val = val; } -LIB_TEST_EXPORT int get_int(void) +LIB_TEST_EXPORT int get_int(void); +int get_int(void) { return g_val; } diff --git a/src/ddsrt/tests/dynlib.c b/src/ddsrt/tests/dynlib.c index 3c3fc2a..d52d3a1 100644 --- a/src/ddsrt/tests/dynlib.c +++ b/src/ddsrt/tests/dynlib.c @@ -25,10 +25,10 @@ #define TEST_ABORT_IF_NULL(var, msg) \ do { \ if (var == NULL) { \ - char buffer[256]; \ - r = ddsrt_dlerror(buffer, sizeof(buffer)); \ + char err[256]; \ + r = ddsrt_dlerror(err, sizeof(err)); \ CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); \ - printf("\n%s", buffer); \ + printf("\n%s", err); \ CU_FAIL_FATAL(msg); \ } \ } while(0) @@ -39,7 +39,7 @@ do { \ */ CU_Test(ddsrt_library, dlopen_path) { - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; printf("Absolute lib: %s\n", TEST_LIB_ABSOLUTE); @@ -54,7 +54,7 @@ CU_Test(ddsrt_library, dlopen_path) CU_Test(ddsrt_library, dlopen_file) { - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; r = ddsrt_dlopen(TEST_LIB_FILE, false, &l); @@ -68,7 +68,7 @@ CU_Test(ddsrt_library, dlopen_file) CU_Test(ddsrt_library, dlopen_name) { - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); @@ -83,7 +83,7 @@ CU_Test(ddsrt_library, dlopen_name) CU_Test(ddsrt_library, dlopen_unknown) { char buffer[256]; - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; r = ddsrt_dlopen("UnknownLib", false, &l); @@ -97,7 +97,7 @@ CU_Test(ddsrt_library, dlopen_unknown) CU_Test(ddsrt_library, dlsym) { - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; void* f; @@ -118,7 +118,7 @@ CU_Test(ddsrt_library, dlsym) CU_Test(ddsrt_library, dlsym_unknown) { char buffer[256]; - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; void* f; @@ -146,7 +146,7 @@ CU_Test(ddsrt_library, call) int set_int = 1234; func_get_int f_get; func_set_int f_set; - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); @@ -171,7 +171,7 @@ CU_Test(ddsrt_library, call) CU_Test(ddsrt_library, dlclose_error) { - dds_retcode_t r; + dds_return_t r; ddsrt_dynlib_t l; r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); @@ -189,9 +189,10 @@ CU_Test(ddsrt_library, dlclose_error) CU_Test(ddsrt_library, dlerror_notfound) { char buffer[256]; - dds_retcode_t r; + dds_return_t r; ddsrt_dlerror(buffer, sizeof(buffer)); r = ddsrt_dlerror(buffer, sizeof(buffer)); CU_ASSERT_EQUAL(r, DDS_RETCODE_NOT_FOUND); } + diff --git a/src/ddsrt/tests/environ.c b/src/ddsrt/tests/environ.c index b69acf4..6e22876 100644 --- a/src/ddsrt/tests/environ.c +++ b/src/ddsrt/tests/environ.c @@ -22,7 +22,7 @@ CU_TheoryDataPoints(ddsrt_environ, bad_name) = { CU_Theory((const char *name), ddsrt_environ, bad_name) { - dds_retcode_t rc; + dds_return_t rc; static const char value[] = "bar"; static char dummy[] = "foobar"; char *ptr; @@ -40,7 +40,7 @@ CU_Theory((const char *name), ddsrt_environ, bad_name) DDSRT_WARNING_MSVC_OFF(4996) CU_Test(ddsrt_environ, setenv) { - dds_retcode_t rc; + dds_return_t rc; static const char name[] = "foo"; static char value[] = "bar"; char *ptr; @@ -64,7 +64,7 @@ DDSRT_WARNING_MSVC_ON(4996) CU_Test(ddsrt_environ, getenv) { - dds_retcode_t rc; + dds_return_t rc; static const char name[] = "foo"; static const char value[] = "bar"; static char dummy[] = "foobar"; @@ -111,7 +111,7 @@ CU_TheoryDataPoints(ddsrt_environ, expand) = { }; CU_Theory((const char *var, const char *expect), ddsrt_environ, expand) { - dds_retcode_t rc; + dds_return_t rc; static const char x_name[] = "X"; static const char x_value[] = "TEST"; static const char y_name[] = "Y"; @@ -131,7 +131,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand) CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); /* Expand a string with available environment variables. */ - ptr = ddsrt_expand_envvars(var); + ptr = ddsrt_expand_envvars(var,UINT32_MAX); if (ptr) { /* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */ CU_ASSERT_STRING_EQUAL(ptr, expect); @@ -163,7 +163,7 @@ CU_TheoryDataPoints(ddsrt_environ, expand_sh) = { }; CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh) { - dds_retcode_t rc; + dds_return_t rc; static const char x_name[] = "X"; static const char x_value[] = "TEST"; static const char y_name[] = "Y"; @@ -183,7 +183,7 @@ CU_Theory((const char *var, const char *expect), ddsrt_environ, expand_sh) CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); /* Expand a string with available environment variables. */ - ptr = ddsrt_expand_envvars_sh(var); + ptr = ddsrt_expand_envvars_sh(var,UINT32_MAX); if (ptr) { /* printf("==== %10s: expand(%s), expect(%s))\n", var, ptr, expect); */ CU_ASSERT_STRING_EQUAL(ptr, expect); diff --git a/src/ddsrt/tests/ifaddrs.c b/src/ddsrt/tests/ifaddrs.c index ae8ea0b..6035724 100644 --- a/src/ddsrt/tests/ifaddrs.c +++ b/src/ddsrt/tests/ifaddrs.c @@ -9,10 +9,10 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include "CUnit/Test.h" #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/ifaddrs.h" #include "dds/ddsrt/retcode.h" +#include "CUnit/Test.h" /* FIXME: It's not possible to predict what network interfaces are available on a given host. To properly test all combinations the abstracted @@ -64,7 +64,7 @@ CU_Clean(ddsrt_getifaddrs) IFF_LOOPBACK flags are properly set. */ CU_Test(ddsrt_getifaddrs, ipv4) { - dds_retcode_t ret; + dds_return_t ret; int seen = 0; ddsrt_ifaddrs_t *ifa_root, *ifa; const int afs[] = { AF_INET, DDSRT_AF_TERM }; @@ -90,7 +90,7 @@ CU_Test(ddsrt_getifaddrs, ipv4) CU_Test(ddsrt_getifaddrs, null_filter) { - dds_retcode_t ret; + dds_return_t ret; int cnt = 0; ddsrt_ifaddrs_t *ifa_root, *ifa; @@ -107,7 +107,7 @@ CU_Test(ddsrt_getifaddrs, null_filter) CU_Test(ddsrt_getifaddrs, empty_filter) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_ifaddrs_t *ifa_root; const int afs[] = { DDSRT_AF_TERM }; @@ -117,11 +117,11 @@ CU_Test(ddsrt_getifaddrs, empty_filter) ddsrt_freeifaddrs(ifa_root); } -#ifdef DDSRT_HAVE_IPV6 CU_Test(ddsrt_getifaddrs, ipv6) { +#ifdef DDSRT_HAVE_IPV6 if (ipv6_enabled == 1) { - dds_retcode_t ret; + dds_return_t ret; int have_ipv6 = 0; ddsrt_ifaddrs_t *ifa_root, *ifa; const int afs[] = { AF_INET6, DDSRT_AF_TERM }; @@ -149,14 +149,18 @@ CU_Test(ddsrt_getifaddrs, ipv6) } else { CU_PASS("IPv6 disabled in test environment"); } +#else + CU_PASS("IPv6 is not supported"); +#endif } /* Assume at least one IPv4 and one IPv6 interface are available when IPv6 is available on the platform. */ CU_Test(ddsrt_getifaddrs, ipv4_n_ipv6) { +#if DDSRT_HAVE_IPV6 if (ipv6_enabled == 1) { - dds_retcode_t ret; + dds_return_t ret; int have_ipv4 = 0; int have_ipv6 = 0; ddsrt_ifaddrs_t *ifa_root, *ifa; @@ -182,6 +186,8 @@ CU_Test(ddsrt_getifaddrs, ipv4_n_ipv6) } else { CU_PASS("IPv6 disabled in test environment"); } +#else + CU_PASS("IPv6 is not supported"); +#endif /* DDSRT_HAVE_IPV6 */ } -#endif /* DDSRT_HAVE_IPV6 */ diff --git a/src/ddsrt/tests/log.c b/src/ddsrt/tests/log.c index 2c619c9..63c0438 100644 --- a/src/ddsrt/tests/log.c +++ b/src/ddsrt/tests/log.c @@ -311,8 +311,8 @@ static ddsrt_mutex_t mutex; struct arg { ddsrt_cond_t *cond; ddsrt_mutex_t *mutex; - dds_time_t stamp; - dds_duration_t pause; + dds_time_t before; + dds_time_t after; }; static void dummy(void *ptr, const dds_log_data_t *data) @@ -326,10 +326,10 @@ static void block(void *ptr, const dds_log_data_t *data) (void)data; struct arg *arg = (struct arg *)ptr; ddsrt_mutex_lock(arg->mutex); - arg->stamp = dds_time(); + arg->before = dds_time(); ddsrt_cond_broadcast(arg->cond); ddsrt_mutex_unlock(arg->mutex); - dds_sleepfor(arg->pause); + arg->after = dds_time(); } static uint32_t run(void *ptr) @@ -347,17 +347,15 @@ static uint32_t run(void *ptr) CU_Test(dds_log, synchronous_sink_changes, .fini=reset) { struct arg arg; - dds_time_t diff, stamp; ddsrt_thread_t tid; ddsrt_threadattr_t tattr; - dds_retcode_t ret; + dds_return_t ret; ddsrt_mutex_init(&mutex); ddsrt_cond_init(&cond); (void)memset(&arg, 0, sizeof(arg)); arg.mutex = &mutex; arg.cond = &cond; - arg.pause = 1000000; ddsrt_mutex_lock(&mutex); dds_set_log_sink(&block, &arg); @@ -366,9 +364,7 @@ CU_Test(dds_log, synchronous_sink_changes, .fini=reset) CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); ddsrt_cond_wait(&cond, &mutex); dds_set_log_sink(dummy, NULL); - stamp = dds_time(); - CU_ASSERT(arg.stamp < stamp); - diff = stamp - arg.stamp; - CU_ASSERT(arg.pause < diff); + CU_ASSERT(arg.before < arg.after); + CU_ASSERT(arg.after < dds_time()); } diff --git a/src/ddsrt/tests/process.c b/src/ddsrt/tests/process.c index c000cf7..90ac385 100644 --- a/src/ddsrt/tests/process.c +++ b/src/ddsrt/tests/process.c @@ -26,7 +26,7 @@ */ static void create_and_test_exit(const char *arg, int code) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; int32_t status; char *argv[] = { NULL, NULL }; @@ -64,7 +64,7 @@ CU_Test(ddsrt_process, create) */ CU_Test(ddsrt_process, kill) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; /* Sleep for 20 seconds. It should be killed before then. */ @@ -98,7 +98,7 @@ CU_Test(ddsrt_process, kill) */ CU_Test(ddsrt_process, pid) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; int32_t status; char *argv[] = { TEST_PID_ARG, NULL }; @@ -126,7 +126,7 @@ CU_Test(ddsrt_process, pid) */ CU_Test(ddsrt_process, env) { - dds_retcode_t ret; + dds_return_t ret; ret = ddsrt_setenv(TEST_ENV_VAR_NAME, TEST_ENV_VAR_VALUE); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); @@ -141,7 +141,7 @@ CU_Test(ddsrt_process, env) */ CU_Test(ddsrt_process, invalid) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; ret = ddsrt_proc_create("ProbablyNotAnValidExecutable", NULL, &pid); @@ -177,7 +177,7 @@ CU_Test(ddsrt_process, arg_dquote) */ CU_Test(ddsrt_process, waitpids) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t child; ddsrt_pid_t pid1 = 0; ddsrt_pid_t pid2 = 0; @@ -225,7 +225,7 @@ CU_Test(ddsrt_process, waitpids) */ CU_Test(ddsrt_process, waitpid_timeout) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; /* Sleep for 20 seconds. We should have a timeout before then. */ @@ -238,7 +238,7 @@ CU_Test(ddsrt_process, waitpid_timeout) ret = ddsrt_proc_waitpid(pid, 0, NULL); CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); - /* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */ + /* Valid timeout should return DDS_RETURN_TIMEOUT when alive. */ ret = ddsrt_proc_waitpid(pid, DDS_SECS(1), NULL); CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT); @@ -257,7 +257,7 @@ CU_Test(ddsrt_process, waitpid_timeout) */ CU_Test(ddsrt_process, waitpids_timeout) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_pid_t pid; /* Sleep for 20 seconds. We should have a timeout before then. */ @@ -270,7 +270,7 @@ CU_Test(ddsrt_process, waitpids_timeout) ret = ddsrt_proc_waitpids(0, NULL, NULL); CU_ASSERT_EQUAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); - /* Valid timeout should return DDS_RETCODE_TIMEOUT when alive. */ + /* Valid timeout should return DDS_RETURN_TIMEOUT when alive. */ ret = ddsrt_proc_waitpids(DDS_SECS(1), NULL, NULL); CU_ASSERT_EQUAL(ret, DDS_RETCODE_TIMEOUT); diff --git a/src/ddsrt/tests/select.c b/src/ddsrt/tests/select.c index ab7bf0e..1012e82 100644 --- a/src/ddsrt/tests/select.c +++ b/src/ddsrt/tests/select.c @@ -9,10 +9,10 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include "CUnit/Theory.h" -#include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/sockets_priv.h" +#include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/threads.h" +#include "CUnit/Theory.h" CU_Init(ddsrt_select) { @@ -36,8 +36,13 @@ CU_Test(ddsrt_select, duration_to_timeval) { struct timeval tv, *tvptr; dds_duration_t nsecs_max; - dds_duration_t secs_max = DDSRT_MAX_INTEGER(ddsrt_tv_sec_t); dds_duration_t usecs_max = 999999; + dds_duration_t secs_max; + DDSRT_STATIC_ASSERT (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32 || CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 64); + if (CHAR_BIT * sizeof (ddsrt_tv_sec_t) == 32) + secs_max = INT32_MAX; + else + secs_max = INT64_MAX; if (DDS_INFINITY > secs_max) { CU_ASSERT_EQUAL_FATAL(secs_max, INT32_MAX); @@ -107,40 +112,45 @@ typedef struct { static void sockets_pipe(ddsrt_socket_t socks[2]) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_socket_t sock; - int reuseaddr = 1; + socklen_t addrlen; struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(54321); + addr.sin_port = 0; + fprintf (stderr, "sockets_pipe ... begin\n"); CU_ASSERT_PTR_NOT_NULL_FATAL(socks); rc = ddsrt_socket(&sock, AF_INET, SOCK_STREAM, 0); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); - rc = ddsrt_setsockopt( - sock, SOL_SOCKET, SO_REUSEADDR, (void*)&reuseaddr, sizeof(reuseaddr)); - CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); rc = ddsrt_socket(&socks[1], AF_INET, SOCK_STREAM, 0); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); rc = ddsrt_bind(sock, (struct sockaddr *)&addr, sizeof(addr)); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + addrlen = (socklen_t) sizeof(addr); + rc = ddsrt_getsockname(sock, (struct sockaddr *)&addr, &addrlen); + CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + fprintf (stderr, "sockets_pipe ... listen\n"); rc = ddsrt_listen(sock, 1); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + fprintf (stderr, "sockets_pipe ... connect\n"); rc = ddsrt_connect(socks[1], (struct sockaddr *)&addr, sizeof(addr)); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + fprintf (stderr, "sockets_pipe ... accept\n"); rc = ddsrt_accept(sock, NULL, NULL, &socks[0]); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); ddsrt_close(sock); + fprintf (stderr, "sockets_pipe ... done\n"); } static const char mesg[] = "foobar"; static uint32_t select_timeout_routine(void *ptr) { - int cnt = -1; - dds_retcode_t rc; + int32_t cnt = -1; + dds_return_t rc; dds_time_t before, after; dds_duration_t delay; fd_set rdset; @@ -148,7 +158,13 @@ static uint32_t select_timeout_routine(void *ptr) uint32_t res = 0; FD_ZERO(&rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_OFF(sign-conversion) +#endif FD_SET(arg->sock, &rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_ON(sign-conversion) +#endif before = dds_time(); rc = ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &cnt); @@ -157,11 +173,15 @@ static uint32_t select_timeout_routine(void *ptr) fprintf(stderr, "Waited for %"PRId64" (nanoseconds)\n", delay); fprintf(stderr, "Expected to wait %"PRId64" (nanoseconds)\n", arg->delay); - fprintf(stderr, "ddsrt_select returned %d\n", rc); - fprintf(stderr, "ddsrt_select reported %d ready\n", cnt); + fprintf(stderr, "ddsrt_select returned %"PRId32"\n", rc); + fprintf(stderr, "ddsrt_select reported %"PRId32" ready\n", cnt); if (rc == DDS_RETCODE_TIMEOUT) { res = (((after - delay) >= (arg->delay - arg->skew)) && (cnt == 0)); + /* Running in the FreeRTOS simulator causes some trouble as interrupts are + simulated using signals causing the select call to be interrupted. */ + } else if (rc == DDS_RETCODE_INTERRUPTED) { + res = (cnt == -1); } return res; @@ -169,7 +189,7 @@ static uint32_t select_timeout_routine(void *ptr) CU_Test(ddsrt_select, timeout) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_socket_t socks[2]; ddsrt_thread_t thr; ddsrt_threadattr_t attr; @@ -178,23 +198,26 @@ CU_Test(ddsrt_select, timeout) sockets_pipe(socks); - arg.delay = DDS_MSECS(100); + arg.delay = DDS_MSECS(300); /* Allow the delay to be off by x microseconds (arbitrarily chosen) for systems with a really poor clock. This test is just to get some confidence that time calculation is not completely broken, it is by no means proof that time calculation is entirely correct! */ - arg.skew = DDS_MSECS(20); + arg.skew = DDS_MSECS(50); arg.sock = socks[0]; + fprintf (stderr, "create thread\n"); ddsrt_threadattr_init(&attr); rc = ddsrt_thread_create(&thr, "select_timeout", &attr, &select_timeout_routine, &arg); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); /* Allow the thread some time to get ready. */ dds_sleepfor(arg.delay * 2); /* Send data to the read socket to avoid blocking indefinitely. */ + fprintf (stderr, "write data\n"); ssize_t sent = 0; rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + fprintf (stderr, "join thread\n"); rc = ddsrt_thread_join(thr, &res); CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); CU_ASSERT_EQUAL(res, 1); @@ -207,13 +230,19 @@ static uint32_t recv_routine(void *ptr) { thread_arg_t *arg = (thread_arg_t*)ptr; - int nfds = 0; + int32_t nfds = 0; fd_set rdset; ssize_t rcvd = -1; char buf[sizeof(mesg)]; FD_ZERO(&rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_OFF(sign-conversion) +#endif FD_SET(arg->sock, &rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_ON(sign-conversion) +#endif (void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds); @@ -226,7 +255,7 @@ static uint32_t recv_routine(void *ptr) CU_Test(ddsrt_select, send_recv) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_socket_t socks[2]; ddsrt_thread_t thr; ddsrt_threadattr_t attr; @@ -260,7 +289,7 @@ static uint32_t recvmsg_routine(void *ptr) { thread_arg_t *arg = (thread_arg_t*)ptr; - int nfds = 0; + int32_t nfds = 0; fd_set rdset; ssize_t rcvd = -1; char buf[sizeof(mesg)]; @@ -274,7 +303,13 @@ static uint32_t recvmsg_routine(void *ptr) msg.msg_iovlen = 1; FD_ZERO(&rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_OFF(sign-conversion) +#endif FD_SET(arg->sock, &rdset); +#if LWIP_SOCKET + DDSRT_WARNING_GNUC_ON(sign-conversion) +#endif (void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds); @@ -287,7 +322,7 @@ static uint32_t recvmsg_routine(void *ptr) CU_Test(ddsrt_select, sendmsg_recvmsg) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_socket_t socks[2]; ddsrt_thread_t thr; ddsrt_threadattr_t attr; diff --git a/src/ddsrt/tests/socket.c b/src/ddsrt/tests/socket.c index db89e2a..411524b 100644 --- a/src/ddsrt/tests/socket.c +++ b/src/ddsrt/tests/socket.c @@ -9,17 +9,17 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#include -#include -#include -#include - -#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 +#include +#include DDSRT_WARNING_MSVC_OFF(4305) #if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN @@ -48,15 +48,15 @@ static void teardown(void) CU_Test(ddsrt_sockaddrfromstr, bad_family) { - dds_retcode_t rc; + dds_return_t rc; struct sockaddr_storage sa; rc = ddsrt_sockaddrfromstr(AF_UNSPEC, "127.0.0.1", &sa); CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER); } -static void sockaddrfromstr_test(char *str, int af, dds_retcode_t exp) +static void sockaddrfromstr_test(char *str, int af, dds_return_t exp) { - dds_retcode_t rc; + dds_return_t rc; struct sockaddr_storage ss; rc = ddsrt_sockaddrfromstr(af, str, &ss); CU_ASSERT_EQUAL(rc, exp); @@ -70,37 +70,44 @@ CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv4) = { "nip"), CU_DataPoints(int, AF_INET, AF_INET, AF_INET), - CU_DataPoints(dds_retcode_t, DDS_RETCODE_OK, DDS_RETCODE_OK, + CU_DataPoints(dds_return_t, DDS_RETCODE_OK, DDS_RETCODE_OK, DDS_RETCODE_BAD_PARAMETER) }; -CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv4, .init=setup, .fini=teardown) +CU_Theory((char *str, int af, dds_return_t exp), ddsrt_sockaddrfromstr, ipv4, .init=setup, .fini=teardown) { sockaddrfromstr_test(str, af, exp); } -#if DDSRT_HAVE_IPV6 CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv6) = { +#if DDSRT_HAVE_IPV6 CU_DataPoints(char *, "127.0.0.1", "::1", "::1", "::", "nip"), CU_DataPoints(int, AF_INET6, AF_INET6, AF_INET, AF_INET6, AF_INET6), - CU_DataPoints(dds_retcode_t, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK, + CU_DataPoints(dds_return_t, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK, DDS_RETCODE_BAD_PARAMETER) +#endif /* DDSRT_HAVE_IPV6 */ }; -CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown) +CU_Theory((char *str, int af, dds_return_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown) { +#if DDSRT_HAVE_IPV6 sockaddrfromstr_test(str, af, exp); -} +#else + (void)str; + (void)af; + (void)exp; + CU_PASS("IPV6 is not supported"); #endif /* DDSRT_HAVE_IPV6 */ +} CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown) { - dds_retcode_t rc; + dds_return_t rc; char buf[128] = { 0 }; struct sockaddr_in sa; memcpy(&sa, &ipv4_loopback, sizeof(ipv4_loopback)); @@ -111,7 +118,7 @@ CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown) CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown) { - dds_retcode_t rc; + dds_return_t rc; char buf[1] = { 0 }; rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf)); CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE); @@ -119,7 +126,7 @@ CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown) CU_Test(ddsrt_sockaddrtostr, ipv4) { - dds_retcode_t rc; + dds_return_t rc; char buf[128] = { 0 }; rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf)); CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK); @@ -128,17 +135,20 @@ CU_Test(ddsrt_sockaddrtostr, ipv4) CU_Test(ddsrt_sockaddrtostr, ipv6) { - dds_retcode_t rc; +#if DDSRT_HAVE_IPV6 + dds_return_t rc; char buf[128] = { 0 }; rc = ddsrt_sockaddrtostr(&ipv6_loopback, buf, sizeof(buf)); CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK); CU_ASSERT_STRING_EQUAL(buf, "::1"); +#else + CU_PASS("IPv6 is not supported"); +#endif } CU_Test(ddsrt_sockets, gethostname) { - int ret; - dds_retcode_t rc; + dds_return_t rc; char sysbuf[200], buf[200]; buf[0] = '\0'; @@ -146,8 +156,12 @@ CU_Test(ddsrt_sockets, gethostname) CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK); sysbuf[0] = '\0'; - ret = gethostname(sysbuf, sizeof(sysbuf)); +#if LWIP_SOCKET + ddsrt_strlcpy(sysbuf, "localhost", sizeof(sysbuf)); +#else + int ret = gethostname(sysbuf, sizeof(sysbuf)); CU_ASSERT_EQUAL(ret, 0); +#endif CU_ASSERT(strcmp(buf, sysbuf) == 0); rc = ddsrt_gethostname(buf, strlen(buf) - 1); @@ -155,9 +169,9 @@ CU_Test(ddsrt_sockets, gethostname) } #if DDSRT_HAVE_DNS -static void gethostbyname_test(char *name, int af, dds_retcode_t exp) +static void gethostbyname_test(char *name, int af, dds_return_t exp) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_hostent_t *hent = NULL; rc = ddsrt_gethostbyname(name, af, &hent); CU_ASSERT_EQUAL(rc, exp); @@ -169,30 +183,44 @@ static void gethostbyname_test(char *name, int af, dds_retcode_t exp) } ddsrt_free(hent); } +#endif CU_TheoryDataPoints(ddsrt_gethostbyname, ipv4) = { CU_DataPoints(char *, "", "127.0.0.1", "127.0.0.1"), CU_DataPoints(int, AF_UNSPEC, AF_INET, AF_UNSPEC), - CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK) + CU_DataPoints(dds_return_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK) }; -CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv4, .init=setup, .fini=teardown) +CU_Theory((char *name, int af, dds_return_t exp), ddsrt_gethostbyname, ipv4, .init=setup, .fini=teardown) { +#if DDSRT_HAVE_DNS gethostbyname_test(name, af, exp); +#else + (void)name; + (void)af; + (void)exp; + CU_PASS("DNS is not supported"); +#endif } -#if DDSRT_HAVE_IPV6 /* Lookup of IPv4 address and specifying AF_INET6 is not invalid as it may return an IPV4-mapped IPv6 address. */ CU_TheoryDataPoints(ddsrt_gethostbyname, ipv6) = { +#if DDSRT_HAVE_IPV6 && DDSRT_HAVE_DNS CU_DataPoints(char *, "::1", "::1", "::1"), CU_DataPoints(int, AF_INET, AF_INET6, AF_UNSPEC), - CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK) + CU_DataPoints(dds_return_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK) +#endif /* DDSRT_HAVE_IPV6 */ }; -CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown) +CU_Theory((char *name, int af, dds_return_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown) { +#if DDSRT_HAVE_IPV6 && DDSRT_HAVE_DNS gethostbyname_test(name, af, exp); -} +#else + (void)name; + (void)af; + (void)exp; + CU_PASS("DNS and IPv6 are not supported"); #endif /* DDSRT_HAVE_IPV6 */ -#endif /* DDSRT_HAVE_DNS */ +} diff --git a/src/ddsrt/tests/string.c b/src/ddsrt/tests/string.c index cd3ffbf..eae2cc7 100644 --- a/src/ddsrt/tests/string.c +++ b/src/ddsrt/tests/string.c @@ -67,35 +67,3 @@ CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0)); } -CU_Test(ddsrt_string, strtok_r) -{ - char *res; - char *saveptr; - char ts1[] = "123,234"; - char ts2[] = ",;,123abc,,456,:,"; - char ts3[] = ",,,123,,456,789,,,"; - - res = ddsrt_strtok_r(ts1, ",", &saveptr); - CU_ASSERT(strcmp(res, "123") == 0); - res = ddsrt_strtok_r( NULL, ",", &saveptr); - CU_ASSERT(strcmp(res, "234") == 0); - res = ddsrt_strtok_r( NULL, ",", &saveptr); - CU_ASSERT(res == NULL); - - res = ddsrt_strtok_r(ts2, ",;", &saveptr); - CU_ASSERT(strcmp(res, "123abc") == 0); - res = ddsrt_strtok_r( NULL, ",", &saveptr); - CU_ASSERT(strcmp(res, "456") == 0); - res = ddsrt_strtok_r( NULL, ",:", &saveptr); - CU_ASSERT(res == NULL); - - res = ddsrt_strtok_r(ts3, ",", &saveptr); - CU_ASSERT(strcmp(res, "123") == 0); - res = ddsrt_strtok_r( NULL, ",", &saveptr); - CU_ASSERT(strcmp(res, "456") == 0); - res = ddsrt_strtok_r( NULL, ",", &saveptr); - CU_ASSERT(strcmp(res, "789") == 0); - res = ddsrt_strtok_r( NULL, ",:", &saveptr); - CU_ASSERT(res == NULL); -} - diff --git a/src/ddsrt/tests/strtoll.c b/src/ddsrt/tests/strtoll.c index d22e813..9640693 100644 --- a/src/ddsrt/tests/strtoll.c +++ b/src/ddsrt/tests/strtoll.c @@ -27,9 +27,9 @@ char str_xllmin[99], str_xllmax[99]; /* Really test with the maximum values supported on a platform, not some made up number. */ -long long llmin = DDSRT_MIN_INTEGER(long long); -long long llmax = DDSRT_MAX_INTEGER(long long); -unsigned long long ullmax = DDSRT_MAX_INTEGER(unsigned long long); +long long llmin = INT64_MIN; +long long llmax = INT64_MAX; +unsigned long long ullmax = UINT64_MAX; CU_Init(ddsrt_strtoll) { @@ -52,7 +52,7 @@ CU_Clean(ddstr_strtoll) CU_Test(ddsrt_strtoll, strtoll) { - dds_retcode_t rc; + dds_return_t rc; long long ll; static char dummy[] = "dummy"; @@ -248,7 +248,7 @@ CU_Test(ddsrt_strtoll, strtoll) CU_Test(ddsrt_strtoll, strtoull) { - dds_retcode_t rc; + dds_return_t rc; unsigned long long ull; str = "0xffffffffffffffff"; @@ -272,7 +272,7 @@ CU_Test(ddsrt_strtoll, strtoull) CU_Test(ddsrt_strtoll, atoll) { - dds_retcode_t rc; + dds_return_t rc; long long ll; str = "10"; @@ -284,7 +284,7 @@ CU_Test(ddsrt_strtoll, atoll) CU_Test(ddsrt_strtoll, atoull) { - dds_retcode_t rc; + dds_return_t rc; unsigned long long ull; str = "10"; diff --git a/src/ddsrt/tests/sync.c b/src/ddsrt/tests/sync.c index 1f8031c..e2b2cda 100644 --- a/src/ddsrt/tests/sync.c +++ b/src/ddsrt/tests/sync.c @@ -55,7 +55,7 @@ static uint32_t mutex_lock_routine(void *ptr) main thread before a lock operation is attempted by the second thread. */ CU_Test(ddsrt_sync, mutex_lock_conc) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thr; ddsrt_threadattr_t attr; thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0) }; @@ -133,7 +133,7 @@ static uint32_t rwlock_trywrite_routine(void *ptr) CU_Test(ddsrt_sync, mutex_trylock_conc) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thr; ddsrt_threadattr_t attr; thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(1) }; @@ -164,7 +164,7 @@ CU_TheoryDataPoints(ddsrt_sync, rwlock_trylock_conc) = { CU_Theory((uint32_t lock, uint32_t trylock, uint32_t exp), ddsrt_sync, rwlock_trylock_conc) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thr; ddsrt_threadattr_t attr; ddsrt_thread_routine_t func; @@ -219,7 +219,7 @@ static uint32_t once_routine(void *ptr) CU_Test(ddsrt_sync, once_conc) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thrs[ONCE_THREADS]; ddsrt_threadattr_t attr; uint32_t res; @@ -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 @@ -284,7 +284,7 @@ static uint32_t waitfor_routine(void *ptr) CU_Test(ddsrt_sync, cond_waitfor) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_thread_t thr; ddsrt_threadattr_t attr; thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0), .reltime = DDS_MSECS(100) }; @@ -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. */ @@ -333,7 +333,7 @@ static uint32_t waituntil_routine(void *ptr) CU_Test(ddsrt_sync, cond_waituntil) { - dds_retcode_t rc; + dds_return_t rc; dds_duration_t delay = DDS_MSECS(100); ddsrt_thread_t thr; ddsrt_threadattr_t attr; diff --git a/src/ddsrt/tests/tasklist.c b/src/ddsrt/tests/tasklist.c new file mode 100644 index 0000000..81134c8 --- /dev/null +++ b/src/ddsrt/tests/tasklist.c @@ -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); +} diff --git a/src/ddsrt/tests/thread.c b/src/ddsrt/tests/thread.c index 8b3ff5d..a217ac6 100644 --- a/src/ddsrt/tests/thread.c +++ b/src/ddsrt/tests/thread.c @@ -11,9 +11,12 @@ */ #include #include -#if !defined(_WIN32) -#include -#include +#if DDSRT_WITH_FREERTOS +# include +# include +#elif !defined(_WIN32) +# include +# include #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; @@ -59,7 +65,7 @@ typedef struct { ddsrt_threadattr_t *attr; } thread_arg_t; -uint32_t thread_main(void *ptr) +static uint32_t thread_main(void *ptr) { thread_arg_t *arg = (thread_arg_t *)ptr; ddsrt_threadattr_t *attr; @@ -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(); @@ -108,12 +119,17 @@ CU_Theory((ddsrt_sched_t sched, int32_t *prio, uint32_t exp), ddsrt_thread, crea { int skip = 0; uint32_t res = 50505; - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thr; 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 @@ -172,7 +193,7 @@ CU_Test(ddsrt_thread, thread_id) static ddsrt_mutex_t locks[2]; -uint32_t thread_main_waitforme(void *ptr) +static uint32_t thread_main_waitforme(void *ptr) { uint32_t ret = 0; (void)ptr; @@ -182,7 +203,7 @@ uint32_t thread_main_waitforme(void *ptr) return ret; } -uint32_t thread_main_waitforit(void *ptr) +static uint32_t thread_main_waitforit(void *ptr) { uint32_t res = 0; ddsrt_thread_t *thr = (ddsrt_thread_t *)ptr; @@ -194,7 +215,7 @@ uint32_t thread_main_waitforit(void *ptr) CU_Test(ddsrt_thread, stacked_join) { - dds_retcode_t ret; + dds_return_t ret; ddsrt_thread_t thrs[2]; ddsrt_threadattr_t attr; uint32_t res = 0; @@ -230,4 +251,3 @@ CU_Test(ddsrt_thread, attribute) CU_ASSERT_EQUAL(attr.schedPriority, 0); CU_ASSERT_EQUAL(attr.stackSize, 0); } - diff --git a/src/ddsrt/tests/thread_cleanup.c b/src/ddsrt/tests/thread_cleanup.c index 4e9bf24..795819c 100644 --- a/src/ddsrt/tests/thread_cleanup.c +++ b/src/ddsrt/tests/thread_cleanup.c @@ -122,7 +122,7 @@ static void setup( struct thread_argument *arg) { - dds_retcode_t rc; + dds_return_t rc; ddsrt_thread_t thr; ddsrt_threadattr_t attr; diff --git a/src/docs/CMakeLists.txt b/src/docs/CMakeLists.txt deleted file mode 100644 index 6b95a4d..0000000 --- a/src/docs/CMakeLists.txt +++ /dev/null @@ -1,218 +0,0 @@ -# -# 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 - -# TODO depending on requirements we can add/remove options as needed, -# these are examples of generators we'll need as a minimum. -# Perhaps we should also consider options for building subset of all docs. -# When a certain doc is related to a target, no option is needed; you can simply check if the target exists -# (i.e. if a target 'ddsc' exists, build ddsc api docs). And possibly make the target definition dependent on an option. - -option(BUILD_DOCS "Build documentation." OFF) -option(DOWNLOAD_DOCS "Download documentation." OFF) - -# When BUILD_DOCS is set, missing deps are treated as fatal errors -if (BUILD_DOCS) - set(mode FATAL_ERROR) -else() - set(mode STATUS) -endif() - -find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Sphinx documentation builder") -if (NOT SPHINX_EXECUTABLE) - message(${mode} "${CMAKE_PROJECT_NAME} documentation: unable to find sphinx-build executable") -endif() - -find_package(Doxygen) -if (NOT Doxygen_FOUND) - message(${mode} "${CMAKE_PROJECT_NAME} documentation: unable to find Doxygen") -endif() - -# Creating pdf from latex requires latexmk (which depends on perl, latexpdf et. al) -find_program(LATEXMK_EXECUTABLE NAMES latexmk DOC "LateX PDF Generator") -if (NOT LATEXMK_EXECUTABLE) - message(${mode} "${CMAKE_PROJECT_NAME} documentation: unable to find latexmk") -endif() - -if ((NOT DOWNLOAD_DOCS) AND SPHINX_EXECUTABLE AND Doxygen_FOUND AND LATEXMK_EXECUTABLE) - # User requested docs (USE_DOCS=1) and did not explicitely request to download docs (DOWNLOAD_DOCS=0) - # All prerequisites are available to build docs, so force BUILD_DOCS even when the user did not enable it explicitely - set(BUILD_DOCS ON PARENT_SCOPE) # for examples' docs - set(BUILD_DOCS ON) - message(STATUS "${CMAKE_PROJECT_NAME} documentation: Success (build)") -else() - # User requested docs (USE_DOCS=1) and prefers to download instead of build (or prerequisites are not available). - # So force DOWNLOAD_DOCS even when user did not enable it explicitely - set(DOWNLOAD_DOCS ON PARENT_SCOPE) # for examples' docs - set(DOWNLOAD_DOCS ON) - message(STATUS "${CMAKE_PROJECT_NAME} documentation: Success (download)") -endif() - -#set(DOCS_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/..") - -if (DOWNLOAD_DOCS) - set(JENKINS_BASE_URI "http://jenkins.prismtech.com:8080/") - set(JENKINS_DOCS_JOB_NAME "BuildChameleonLinux64bit") - set(PROJECT_PDF_URI "${JENKINS_BASE_URI}/job/${JENKINS_DOCS_JOB_NAME}/lastSuccessfulBuild/artifact/cham/builds/docs/${CMAKE_PROJECT_NAME}.pdf") - set(PROJECT_HTML_URI "${JENKINS_BASE_URI}/job/${JENKINS_DOCS_JOB_NAME}/lastSuccessfulBuild/artifact/cham/builds/docs/${CMAKE_PROJECT_NAME}HTML.tar.gz") - - add_custom_target(docs ALL) - find_program(WGET_EXECUTABLE NAMES wget DOC "wget") - if (WGET_EXECUTABLE) - # prevent wget to create numbered downloads. - add_custom_command(TARGET docs - COMMAND ${CMAKE_COMMAND} - -E remove -f "${CMAKE_PROJECT_NAME}HTML.tar.gz" - VERBATIM) - - add_custom_command(TARGET docs - COMMAND ${WGET_EXECUTABLE} - -q ${PROJECT_HTML_URI} ${PROJECT_PDF_URI} - COMMENT "Downloading documentation from target." - VERBATIM) - - # To make downloading and packaging easier. -# add_custom_command(TARGET docs -# COMMAND ${CMAKE_COMMAND} -# -E rename ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.pdf ${DOCS_OUTPUT_DIR}/${CMAKE_PROJECT_NAME}.pdf -# VERBATIM) - else() - message(STATUS "Unable to find wget. Download docs now.") - # Just try to download the docs straight away. - file(DOWNLOAD ${PROJECT_HTML_URI} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}HTML.tar.gz) - file(DOWNLOAD ${PROJECT_PDF_URI} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.pdf) - endif() - - add_custom_command(TARGET docs - COMMAND ${CMAKE_COMMAND} - -E tar "zxf" "${CMAKE_PROJECT_NAME}HTML.tar.gz" . - VERBATIM) - - # Remove downloaded files when cleaning the build tree - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - html - ${CMAKE_PROJECT_NAME}HTML.tar.gz - ${CMAKE_PROJECT_NAME}.pdf) - -elseif(BUILD_DOCS) - # Generate ddsc API docs in XML format using Doxygen, if the ddsc target is defined. - # The XML will serve as input for sphinx' breathe plugin - if (TARGET ${CMAKE_PROJECT_NAME}::ddsc) - # Process doxygen configuration file, for ddsc - set(doxy_conf_project "${CMAKE_PROJECT_NAME_FULL} C API Documentation") - set(doxy_conf_outputdir "ddsc_api") - set(doxy_conf_input "${PROJECT_SOURCE_DIR}/core/ddsc/include/dds/dds.h ${PROJECT_SOURCE_DIR}/core/ddsc/include/dds") - configure_file(Doxyfile.in Doxyfile @ONLY) - - add_custom_target(ddsc_docs - ${DOXYGEN_EXECUTABLE} Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Running Doxygen for API docs generation" - VERBATIM - ) - - # Remove generated files when cleaning the build tree - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${doxy_conf_outputdir}) - - # Add ddsc api docs to sphinx' breathe projects - set(sph_conf_breathe_projs "\"ddsc_api\": \"${doxy_conf_outputdir}/xml\"") - - add_custom_command(TARGET ddsc_docs - POST_BUILD - WORKING_DIRECTORY "${doxy_conf_outputdir}" - COMMAND ${CMAKE_COMMAND} -E tar "zcf" "${CMAKE_PROJECT_NAME}_C_HTML.tar.gz" "ddsc") - endif() - - # Process sphinx configuration file - set(sph_conf_author "Eclipse Cyclone DDS project") - set(sph_conf_version "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") - set(sph_conf_release "${PROJECT_VERSION}") - configure_file(conf.py.in conf.py @ONLY) - - # Define a list of output formats (-b option for sphinx-build) - set(docs_builders "") - list(APPEND docs_builders html) - list(APPEND docs_builders latex) - - # Define custom commands for running sphinx-build for different docs builders - set(docs_outputs "") - foreach(builder ${docs_builders}) - set(docs_builder_output "docs_${builder}_output") - # Log stdout (not stderr) to a file instead of messing up build output - set(docs_builder_log "sphinx-build-${builder}.log") - - add_custom_command(OUTPUT ${docs_builder_output} - COMMAND ${SPHINX_EXECUTABLE} - -b ${builder} - -d ${CMAKE_CURRENT_BINARY_DIR}/cache - -c ${CMAKE_CURRENT_BINARY_DIR} - ${PROJECT_SOURCE_DIR}/docs - ${CMAKE_CURRENT_BINARY_DIR}/${builder} > ${docs_builder_log} - COMMENT "Running Sphinx for ${builder} output" - VERBATIM) - - # FIXME: This is definitely in the wrong location - if(builder STREQUAL html) - add_custom_command(OUTPUT ${docs_builder_output} - COMMAND ${CMAKE_COMMAND} - -E tar "zcf" - "${CMAKE_PROJECT_NAME}HTML.tar.gz" - "html" - APPEND - VERBATIM) - endif() - - # Create a pdf from the latex builder output, by appending a latexmk command - # TODO look into rinohtype as an alternative (don't bother with rst2pdf, it's no good) - if(builder STREQUAL latex) - add_custom_command(OUTPUT ${docs_builder_output} - COMMAND ${LATEXMK_EXECUTABLE} - -interaction=nonstopmode - -silent - -output-directory=${builder} - -pdf -dvi- -ps- -cd- ${builder}/${CMAKE_PROJECT_NAME}.tex - APPEND - VERBATIM) - - # Move the pdf, so that install rules don't need to differentiate between built and downloaded docs - add_custom_command(OUTPUT ${docs_builder_output} - COMMAND ${CMAKE_COMMAND} - -E rename - "latex/${CMAKE_PROJECT_NAME}.pdf" - "${CMAKE_PROJECT_NAME}.pdf" - APPEND - VERBATIM) - endif() - - # OUTPUT is a fake target / symbolic name, not an actual file - set_property(SOURCE ${docs_builder_output} PROPERTY SYMBOLIC 1) - # Remove generated files when cleaning the build tree - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - ${builder} - ${docs_builder_log}) - - # Include this builder as a dependency of the general 'docs' target - list(APPEND docs_outputs ${docs_builder_output}) - endforeach() - - # Remove generated files when cleaning the build tree - set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES - ${CMAKE_PROJECT_NAME}HTML.tar.gz - ${CMAKE_PROJECT_NAME}.pdf) - - add_custom_target(docs ALL DEPENDS ddsc_docs ${docs_outputs}) -endif() - -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html - DESTINATION ${CMAKE_INSTALL_DOCDIR} - COMPONENT dev) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.pdf - DESTINATION ${CMAKE_INSTALL_DOCDIR} - COMPONENT dev) diff --git a/src/docs/Doxyfile.in b/src/docs/Doxyfile.in deleted file mode 100644 index 32aebfe..0000000 --- a/src/docs/Doxyfile.in +++ /dev/null @@ -1,2427 +0,0 @@ -# Doxyfile 1.8.11 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "@doxy_conf_project@" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify a logo or an icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy -# the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = @doxy_conf_outputdir@ - -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new -# page for each member. If set to NO, the documentation of a member will be part -# of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. -# -# Note: For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# If one adds a struct or class to a group and this option is enabled, then also -# any nested class or struct is added to the same group. By default this option -# is disabled and one has to add nested compounds explicitly via \ingroup. -# The default value is: NO. - -GROUP_NESTED_COMPOUNDS = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO, -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. If set to YES, local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO, only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO, these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES, the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will -# append additional text to a page's title, such as Class Reference. If set to -# YES the compound reference will be hidden. -# The default value is: NO. - -HIDE_COMPOUND_REFERENCE = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo -# list. This list is created by putting \todo commands in the documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test -# list. This list is created by putting \test commands in the documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST = YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES, the -# list will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = NO - -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = NO - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = NO - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. -# The default value is: NO. - -WARN_AS_ERROR = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING -# Note: If this tag is empty the current directory is searched. - -INPUT = @doxy_conf_input@ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. -# -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, -# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = */tests/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse-libclang=ON option for CMake. -# The default value is: NO. - -# CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -# CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = ddsc - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefore more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra style sheet files is of importance (e.g. the last -# style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated -# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , / - auto true true diff --git a/src/mpt/tests/basic/etc/config_specific.xml b/src/mpt/tests/basic/etc/config_specific.xml index c6ccf33..0532aa0 100644 --- a/src/mpt/tests/basic/etc/config_specific.xml +++ b/src/mpt/tests/basic/etc/config_specific.xml @@ -14,7 +14,6 @@ ${DOMAIN_ID} - auto true true diff --git a/src/mpt/tests/basic/helloworld.c b/src/mpt/tests/basic/helloworld.c index c959edb..934262a 100644 --- a/src/mpt/tests/basic/helloworld.c +++ b/src/mpt/tests/basic/helloworld.c @@ -13,13 +13,13 @@ /* Environments */ static mpt_env_t environment_any[] = { { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" }, - { "CYCLONEDDS_URI", "file://${ETC_DIR}/config_any.xml" }, + { "CYCLONEDDS_URI", "${CYCLONEDDS_URI},file://${ETC_DIR}/config_any.xml" }, { NULL, NULL } }; static mpt_env_t environment_42[] = { { "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" }, { "DOMAIN_ID", "42" }, - { "CYCLONEDDS_URI", "file://${ETC_DIR}/config_specific.xml" }, + { "CYCLONEDDS_URI", "${CYCLONEDDS_URI},file://${ETC_DIR}/config_specific.xml" }, { NULL, NULL } }; diff --git a/src/mpt/tests/basic/procs/hello.c b/src/mpt/tests/basic/procs/hello.c index 2c68a84..84e6c5e 100644 --- a/src/mpt/tests/basic/procs/hello.c +++ b/src/mpt/tests/basic/procs/hello.c @@ -5,7 +5,6 @@ #include "mpt/mpt.h" #include "dds/dds.h" -#include "helloworlddata.h" #include "dds/ddsrt/time.h" #include "dds/ddsrt/strtol.h" @@ -14,6 +13,8 @@ #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/sync.h" +#include "hello.h" +#include "helloworlddata.h" /* An array of one message (aka sample in dds terms) will be used. */ #define MAX_SAMPLES 1 @@ -173,13 +174,7 @@ MPT_ProcessEntry(hello_subscriber, printf("--- [Subscriber(%d)] Start(%d) ...\n", id, domainid); - /* - * A reliable volatile sample, written after publication matched, can still - * be lost when the subscriber wasn't able to match its subscription yet. - * Use transient_local reliable to make sure the sample is received. - */ qos = dds_create_qos(); - dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL); dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10)); /* Use listener to get data available trigger. */ @@ -206,8 +201,7 @@ MPT_ProcessEntry(hello_subscriber, ddsrt_mutex_lock(&g_mutex); recv_cnt = 0; while (recv_cnt < sample_cnt) { - /* Use a take with mask to work around the #146 issue. */ - rc = dds_take_mask(reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES, DDS_NEW_VIEW_STATE); + rc = dds_take(reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES); MPT_ASSERT_GEQ(rc, 0, "Could not read: %s\n", dds_strretcode(-rc)); /* Check if we read some data and it is valid. */ diff --git a/src/mpt/tests/qos/CMakeLists.txt b/src/mpt/tests/qos/CMakeLists.txt new file mode 100644 index 0000000..0632570 --- /dev/null +++ b/src/mpt/tests/qos/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright(c) 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include(${MPT_CMAKE}) + +add_compile_options("-I${PROJECT_SOURCE_DIR}/src/core/ddsi/include") + +idlc_generate(mpt_rwdata_lib "procs/rwdata.idl") + +set(sources_qosmatch + "procs/rw.c" + "qosmatch.c") +add_mpt_executable(mpt_qosmatch ${sources_qosmatch}) +target_link_libraries(mpt_qosmatch PRIVATE mpt_rwdata_lib) + +set(sources_ppuserdata + "procs/ppud.c" + "ppuserdata.c") +add_mpt_executable(mpt_ppuserdata ${sources_ppuserdata}) +target_link_libraries(mpt_ppuserdata PRIVATE mpt_rwdata_lib) diff --git a/src/mpt/tests/qos/ppuserdata.c b/src/mpt/tests/qos/ppuserdata.c new file mode 100644 index 0000000..4951311 --- /dev/null +++ b/src/mpt/tests/qos/ppuserdata.c @@ -0,0 +1,71 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "mpt/mpt.h" +#include "procs/ppud.h" + + +/* + * Checks whether participant user_data QoS changes work. + */ +#define TEST_A_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, true, 10) +#define TEST_B_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, false, 0) +MPT_TestProcess(qos, ppuserdata, a, ppud, TEST_A_ARGS); +MPT_TestProcess(qos, ppuserdata, b, ppud, TEST_B_ARGS); +MPT_Test(qos, ppuserdata, .init=ppud_init, .fini=ppud_fini); +#undef TEST_A_ARGS +#undef TEST_B_ARGS + +/* + * Checks whether reader/writer user_data QoS changes work. + */ +#define TEST_A_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwuserdata", true, 10, RWUD_USERDATA, NULL) +#define TEST_B_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwuserdata", false, 0, RWUD_USERDATA, NULL) +MPT_TestProcess(qos, rwuserdata, a, rwud, TEST_A_ARGS); +MPT_TestProcess(qos, rwuserdata, b, rwud, TEST_B_ARGS); +MPT_Test(qos, rwuserdata, .init=ppud_init, .fini=ppud_fini); +#undef TEST_A_ARGS +#undef TEST_B_ARGS + +/* + * Checks whether topic_data QoS changes become visible in reader/writer. + */ +#define TEST_A_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwtopicdata", true, 10, RWUD_TOPICDATA, NULL) +#define TEST_B_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwtopicdata", false, 0, RWUD_TOPICDATA, NULL) +MPT_TestProcess(qos, rwtopicdata, a, rwud, TEST_A_ARGS); +MPT_TestProcess(qos, rwtopicdata, b, rwud, TEST_B_ARGS); +MPT_Test(qos, rwtopicdata, .init=ppud_init, .fini=ppud_fini); +#undef TEST_A_ARGS +#undef TEST_B_ARGS + +/* + * Checks whether group_data QoS changes become visible in reader/writer. + */ +#define TEST_A_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwgroupdata", true, 10, RWUD_GROUPDATA, NULL) +#define TEST_B_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "rwgroupdata", false, 0, RWUD_GROUPDATA, NULL) +MPT_TestProcess(qos, rwgroupdata, a, rwud, TEST_A_ARGS); +MPT_TestProcess(qos, rwgroupdata, b, rwud, TEST_B_ARGS); +MPT_Test(qos, rwgroupdata, .init=ppud_init, .fini=ppud_fini); +#undef TEST_A_ARGS +#undef TEST_B_ARGS + +/* + * Checks whether topic_data QoS changes become visible in reader/writer, + * but doing so in 2 domains simultaneously -- the specified domain id, + * and the one immediately above that + */ +#define TEST_A_ARGS MPT_ArgValues(3, "rwtopicdataM", true, 10, RWUD_TOPICDATA) +#define TEST_B_ARGS MPT_ArgValues(3, "rwtopicdataM", false, 0, RWUD_TOPICDATA) +MPT_TestProcess(qos, rwtopicdataM, a, rwudM, TEST_A_ARGS); +MPT_TestProcess(qos, rwtopicdataM, b, rwudM, TEST_B_ARGS); +MPT_Test(qos, rwtopicdataM, .init=ppud_init, .fini=ppud_fini); +#undef TEST_A_ARGS +#undef TEST_B_ARGS diff --git a/src/mpt/tests/qos/procs/ppud.c b/src/mpt/tests/qos/procs/ppud.c new file mode 100644 index 0000000..25ae30a --- /dev/null +++ b/src/mpt/tests/qos/procs/ppud.c @@ -0,0 +1,448 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "mpt/mpt.h" + +#include "dds/dds.h" + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsrt/heap.h" + +#include "ppud.h" +#include "rwdata.h" + +void ppud_init (void) { } +void ppud_fini (void) { } + +MPT_ProcessEntry (ppud, + MPT_Args (dds_domainid_t domainid, + bool master, + unsigned ncycles)) +{ +#define prefix "ppuserdata:" + static const char *exp_ud[] = { + prefix "a", prefix "bc", prefix "def", prefix "" + }; + const char *expud = master ? prefix "X" : prefix; + size_t expusz = strlen (expud); + dds_entity_t dp, rd, ws; + dds_instance_handle_t dpih; + dds_return_t rc; + dds_qos_t *qos; + int id = (int) ddsrt_getpid (); + + printf ("=== [Check(%d)] master=%d ncycles=%u Start(%d) ...\n", id, master, ncycles, (int) domainid); + + qos = dds_create_qos (); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dds_qset_userdata (qos, expud, expusz); + dp = dds_create_participant (domainid, qos, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + rc = dds_get_instance_handle (dp, &dpih); + MPT_ASSERT_FATAL_EQ (rc, 0, "Could not get participant instance handle: %s\n", dds_strretcode (rc)); + rd = dds_create_reader (dp, DDS_BUILTIN_TOPIC_DCPSPARTICIPANT, qos, NULL); + MPT_ASSERT_FATAL_GT (rd, 0, "Could not create DCPSParticipant reader: %s\n", dds_strretcode (rd)); + rc = dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS); + MPT_ASSERT_FATAL_EQ (rc, 0, "Could not set status mask: %s\n", dds_strretcode (rc)); + ws = dds_create_waitset (dp); + MPT_ASSERT_FATAL_GT (ws, 0, "Could not create waitset: %s\n", dds_strretcode (ws)); + rc = dds_waitset_attach (ws, rd, 0); + MPT_ASSERT_FATAL_EQ (rc, 0, "Could not attach reader to waitset: %s\n", dds_strretcode (rc)); + + bool done = false; + bool synced = !master; + unsigned exp_index = 0; + unsigned exp_cycle = 0; + while (!done) + { + rc = dds_waitset_wait (ws, NULL, 0, DDS_INFINITY); + MPT_ASSERT_FATAL_GEQ (rc, 0, "Wait failed: %s\n", dds_strretcode (ws)); + + void *raw = NULL; + dds_sample_info_t si; + int32_t n; + while ((n = dds_take (rd, &raw, &si, 1, 1)) == 1) + { + const dds_builtintopic_participant_t *sample = raw; + if (si.instance_state != DDS_IST_ALIVE) + done = true; + else if (si.instance_handle == dpih || !si.valid_data) + continue; + else + { + void *ud = NULL; + size_t usz = 0; + if (!dds_qget_userdata (sample->qos, &ud, &usz)) + MPT_ASSERT (0, "%d: user data not set in QoS\n", id); + if (ud == NULL || strncmp (ud, prefix, sizeof (prefix) - 1) != 0) + { + /* presumably another process */ + } + else if (!synced && strcmp (ud, expud) != 0) + { + /* slave hasn't discovered us yet */ + } + else if (synced && master && strcmp (ud, prefix "X") == 0 && exp_index == 1 && exp_cycle == 0) + { + /* FIXME: don't want no stutter of the initial sample ... */ + } + else + { + synced = true; + if (master) + { + bool eq = (usz == expusz && (usz == 0 || memcmp (ud, expud, usz) == 0)); + printf ("%d: expected %u %zu/%s received %zu/%s\n", + id, exp_index, expusz, expud, usz, ud ? (char *) ud : "(null)"); + MPT_ASSERT (eq, "user data mismatch: expected %u %zu/%s received %zu/%s\n", + exp_index, expusz, expud ? expud : "(null)", usz, ud ? (char *) ud : "(null)"); + if (++exp_index == sizeof (exp_ud) / sizeof (exp_ud[0])) + { + exp_index = 0; + exp_cycle++; + } + + if (exp_cycle == ncycles) + done = true; + + expud = exp_ud[exp_index]; + expusz = strlen (expud); + } + else + { + printf ("%d: slave: received %zu/%s\n", id, usz, ud ? (char *) ud : "(null)"); + expud = ud; + expusz = usz; + } + + dds_qset_userdata (qos, expud, expusz); + rc = dds_set_qos (dp, qos); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "Set QoS failed: %s\n", dds_strretcode (rc)); + + dds_qos_t *chk = dds_create_qos (); + rc = dds_get_qos (dp, chk); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "Get QoS failed: %s\n", dds_strretcode (rc)); + + void *chkud = NULL; + size_t chkusz = 0; + if (!dds_qget_userdata (chk, &chkud, &chkusz)) + MPT_ASSERT (0, "Check QoS: no user data present\n"); + MPT_ASSERT (chkusz == expusz && (expusz == 0 || memcmp (chkud, expud, expusz) == 0), + "Retrieved user data differs from user data just set (%zu/%s vs %zu/%s)\n", + chkusz, chkud ? (char *) chkud : "(null)", expusz, expud ? (char *) expud : "(null)"); + dds_free (chkud); + dds_delete_qos (chk); + } + dds_free (ud); + } + } + MPT_ASSERT_FATAL_EQ (n, 0, "Read failed: %s\n", dds_strretcode (n)); + dds_return_loan (rd, &raw, 1); + fflush (stdout); + } + dds_delete_qos (qos); + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Check(%d)] Done\n", id); +#undef prefix +} + +static const char *exp_rwud[2][4] = { + { "a", "bc", "def", "" }, + { "p", "qr", "stu", "" } +}; + +struct rwud_barrier { + ddsrt_mutex_t lock; + ddsrt_cond_t cond; + int initcount; + int count; +}; + +static void barrierwait (struct rwud_barrier *barrier, int id) +{ + printf ("%d waiting at barrier\n", id); + fflush (stdout); + ddsrt_mutex_lock (&barrier->lock); + assert (barrier->initcount > 0); + if (barrier->count == 0) + barrier->count = barrier->initcount; + if (--barrier->count == 0) + ddsrt_cond_broadcast (&barrier->cond); + while (barrier->count > 0) + ddsrt_cond_wait (&barrier->cond, &barrier->lock); + ddsrt_mutex_unlock (&barrier->lock); + printf ("%d continuing past barrier\n", id); + fflush (stdout); +} + +MPT_ProcessEntry (rwud, + MPT_Args (dds_domainid_t domainid, + const char *topic_name, + bool master, + unsigned ncycles, + enum rwud which, + struct rwud_barrier *barrier)) +{ + bool (*qget) (const dds_qos_t * __restrict qos, void **value, size_t *sz) = 0; + void (*qset) (dds_qos_t * __restrict qos, const void *value, size_t sz) = 0; + const char *qname = "UNDEFINED"; + + dds_entity_t dp, tp, ep, grp, rdep, qent = 0, ws; + dds_return_t rc; + dds_qos_t *qos; + int id = (int) ddsrt_getpid (); + + const char *expud = master ? "X" : ""; + size_t expusz = strlen (expud); + + printf ("=== [Check(%d)] master=%d ncycles=%u Start(%d) ...\n", id, master, ncycles, (int) domainid); + + qos = dds_create_qos (); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dp = dds_create_participant (domainid, NULL, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + tp = dds_create_topic (dp, &RWData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT (tp, 0, "Could not create topic: %s\n", dds_strretcode (tp)); + if (master) + { + rdep = dds_create_reader (dp, DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, qos, NULL); + MPT_ASSERT_FATAL_GT (rdep, 0, "Could not create DCPSSubscription reader: %s\n", dds_strretcode (rdep)); + grp = dds_create_publisher (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (grp, 0, "Could not create publisher: %s\n", dds_strretcode (grp)); + ep = dds_create_writer (grp, tp, qos, NULL); + MPT_ASSERT_FATAL_GT (ep, 0, "Could not create writer: %s\n", dds_strretcode (ep)); + } + else + { + rdep = dds_create_reader (dp, DDS_BUILTIN_TOPIC_DCPSPUBLICATION, qos, NULL); + MPT_ASSERT_FATAL_GT (rdep, 0, "Could not create DCPSPublication reader: %s\n", dds_strretcode (rdep)); + grp = dds_create_subscriber (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (grp, 0, "Could not create subscriber: %s\n", dds_strretcode (grp)); + ep = dds_create_reader (grp, tp, qos, NULL); + MPT_ASSERT_FATAL_GT (ep, 0, "Could not create reader: %s\n", dds_strretcode (ep)); + } + rc = dds_set_status_mask (rdep, DDS_DATA_AVAILABLE_STATUS); + MPT_ASSERT_FATAL_EQ (rc, 0, "Could not set status mask: %s\n", dds_strretcode (rc)); + ws = dds_create_waitset (dp); + MPT_ASSERT_FATAL_GT (ws, 0, "Could not create waitset: %s\n", dds_strretcode (ws)); + rc = dds_waitset_attach (ws, rdep, 0); + MPT_ASSERT_FATAL_EQ (rc, 0, "Could not attach built-in reader to waitset: %s\n", dds_strretcode (rc)); + + switch (which) + { + case RWUD_USERDATA: + qget = dds_qget_userdata; + qset = dds_qset_userdata; + qname = "user data"; + qent = ep; + break; + case RWUD_GROUPDATA: + qget = dds_qget_groupdata; + qset = dds_qset_groupdata; + qname = "group data"; + qent = grp; + MPT_ASSERT_FATAL_GT (qent, 0, "Could not get pub/sub from wr/rd: %s\n", dds_strretcode (qent)); + break; + case RWUD_TOPICDATA: + qget = dds_qget_topicdata; + qset = dds_qset_topicdata; + qname = "topic data"; + qent = tp; + break; + } + + if (master) + { + qset (qos, expud, expusz); + rc = dds_set_qos (qent, qos); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "Set QoS failed: %s\n", dds_strretcode (rc)); + } + + if (barrier) + { + barrierwait (barrier, id); + } + + bool done = false; + bool synced = !master; + const unsigned exp_setindex = (unsigned) domainid % 2; + unsigned exp_index = 0; + unsigned exp_cycle = 0; + dds_instance_handle_t peer = 0; + while (!done) + { + rc = dds_waitset_wait (ws, NULL, 0, DDS_INFINITY); + MPT_ASSERT_FATAL_GEQ (rc, 0, "Wait failed: %s\n", dds_strretcode (ws)); + + void *raw = NULL; + dds_sample_info_t si; + int32_t n; + while ((n = dds_take (rdep, &raw, &si, 1, 1)) == 1) + { + const dds_builtintopic_endpoint_t *sample = raw; + if (si.instance_state != DDS_IST_ALIVE && si.instance_handle == peer) + done = true; + else if (!si.valid_data) + continue; + else if ((peer && si.instance_handle != peer) || strcmp (sample->topic_name, topic_name) != 0) + continue; + else + { + void *ud = NULL; + size_t usz = 0; + if (!qget (sample->qos, &ud, &usz)) + MPT_ASSERT (0, "%d: %s not set in QoS\n", id, qname); + else if (!synced && (ud == NULL || strcmp (ud, expud) != 0)) + { + /* slave hasn't discovered us yet */ + } + else + { + peer = si.instance_handle; + synced = true; + if (master) + { + bool eq = (usz == expusz && (usz == 0 || memcmp (ud, expud, usz) == 0)); + printf ("%d: expected %u %zu/%s received %zu/%s\n", + id, exp_index, expusz, expud, usz, ud ? (char *) ud : "(null)"); + MPT_ASSERT (eq, "%s mismatch: expected %u %zu/%s received %zu/%s\n", + qname, exp_index, expusz, expud ? expud : "(null)", usz, ud ? (char *) ud : "(null)"); + if (++exp_index == sizeof (exp_rwud[0]) / sizeof (exp_rwud[0][0])) + { + exp_index = 0; + exp_cycle++; + } + + if (exp_cycle == ncycles) + done = true; + + expud = exp_rwud[exp_setindex][exp_index]; + expusz = strlen (expud); + } + else + { + printf ("%d: slave: received %zu/%s\n", id, usz, ud ? (char *) ud : "(null)"); + expud = ud; + expusz = usz; + } + + qset (qos, expud, expusz); + rc = dds_set_qos (qent, qos); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "Set QoS failed: %s\n", dds_strretcode (rc)); + + dds_qos_t *chk = dds_create_qos (); + rc = dds_get_qos (ep, chk); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "Get QoS failed: %s\n", dds_strretcode (rc)); + + void *chkud = NULL; + size_t chkusz = 0; + if (!qget (chk, &chkud, &chkusz)) + MPT_ASSERT (0, "Check QoS: no %s present\n", qname); + MPT_ASSERT (chkusz == expusz && (expusz == 0 || memcmp (chkud, expud, expusz) == 0), + "Retrieved %s differs from group data just set (%zu/%s vs %zu/%s)\n", qname, + chkusz, chkud ? (char *) chkud : "(null)", expusz, expud ? (char *) expud : "(null)"); + dds_free (chkud); + dds_delete_qos (chk); + } + dds_free (ud); + } + } + MPT_ASSERT_FATAL_EQ (n, 0, "Read failed: %s\n", dds_strretcode (n)); + dds_return_loan (rdep, &raw, 1); + fflush (stdout); + } + dds_delete_qos (qos); + + if (barrier) + { + barrierwait (barrier, id); + } + + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Check(%d)] Done\n", id); +} + +struct rwudM_thread_arg { + dds_domainid_t domainid; + const char *topic_name; + bool master; + unsigned ncycles; + enum rwud which; + mpt_retval_t retval; + struct rwud_barrier *barrier; + const mpt_data_t *mpt__args__; +}; + +static uint32_t rwudM_thread (void *varg) +{ + struct rwudM_thread_arg *arg = varg; + const mpt_data_t *mpt__args__ = arg->mpt__args__; + mpt_retval_t *mpt__retval__ = &arg->retval; + MPT_ProcessEntryName(rwud) (MPT_ArgValues (arg->domainid, arg->topic_name, arg->master, arg->ncycles, arg->which, arg->barrier)); + return 0; +} + +MPT_ProcessEntry (rwudM, + MPT_Args (dds_domainid_t domainid, + const char *topic_name, + bool master, + unsigned ncycles, + enum rwud which)) +{ + dds_return_t ret; + uint32_t dummy; + ddsrt_thread_t thr[2]; + ddsrt_threadattr_t attr; + struct rwud_barrier barrier; + struct rwudM_thread_arg a = { + .domainid = domainid, + .topic_name = topic_name, + .master = master, + .ncycles = ncycles, + .which = which, + .barrier = &barrier, + .retval = MPT_SUCCESS, + .mpt__args__ = mpt__args__ + }; + struct rwudM_thread_arg b; + b = a; ++b.domainid; + + ddsrt_mutex_init (&barrier.lock); + ddsrt_cond_init (&barrier.cond); + barrier.initcount = 2; + barrier.count = 0; + + ddsrt_threadattr_init (&attr); + ret = ddsrt_thread_create (&thr[0], "a", &attr, &rwudM_thread, &a); + MPT_ASSERT_FATAL_EQ (ret, DDS_RETCODE_OK, "failed to create thread a\n"); + ret = ddsrt_thread_create (&thr[1], "b", &attr, &rwudM_thread, &b); + MPT_ASSERT_FATAL_EQ (ret, DDS_RETCODE_OK, "failed to create thread b\n"); + ret = ddsrt_thread_join (thr[0], &dummy); + MPT_ASSERT_FATAL_EQ (ret, DDS_RETCODE_OK, "failed to join thread a\n"); + ret = ddsrt_thread_join (thr[1], &dummy); + MPT_ASSERT_FATAL_EQ (ret, DDS_RETCODE_OK, "failed to join thread b\n"); + /* forward thread failures to process failures */ + MPT_ASSERT_EQ (a.retval, MPT_SUCCESS, "thread a failed\n"); + MPT_ASSERT_EQ (b.retval, MPT_SUCCESS, "thread b failed\n"); + + ddsrt_cond_destroy (&barrier.cond); + ddsrt_mutex_destroy (&barrier.lock); +} diff --git a/src/mpt/tests/qos/procs/ppud.h b/src/mpt/tests/qos/procs/ppud.h new file mode 100644 index 0000000..598cc59 --- /dev/null +++ b/src/mpt/tests/qos/procs/ppud.h @@ -0,0 +1,61 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef MPT_QOSMATCH_PROCS_PPUD_H +#define MPT_QOSMATCH_PROCS_PPUD_H + +#include +#include + +#include "dds/dds.h" +#include "mpt/mpt.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +void ppud_init (void); +void ppud_fini (void); + +enum rwud { + RWUD_USERDATA, + RWUD_GROUPDATA, + RWUD_TOPICDATA +}; + +struct rwud_barrier; + +MPT_ProcessEntry (ppud, + MPT_Args (dds_domainid_t domainid, + bool master, + unsigned ncycles)); + +MPT_ProcessEntry (rwud, + MPT_Args (dds_domainid_t domainid, + const char *topic_name, + bool master, + unsigned ncycles, + enum rwud which, + struct rwud_barrier *barrier)); + +MPT_ProcessEntry (rwudM, + MPT_Args (dds_domainid_t domainid, + const char *topic_name, + bool master, + unsigned ncycles, + enum rwud which)); + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/mpt/tests/qos/procs/rw.c b/src/mpt/tests/qos/procs/rw.c new file mode 100644 index 0000000..abe6a64 --- /dev/null +++ b/src/mpt/tests/qos/procs/rw.c @@ -0,0 +1,447 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "mpt/mpt.h" + +#include "dds/dds.h" + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" + +#include "dds/ddsi/q_xqos.h" + +#include "rwdata.h" +#include "rw.h" + +#define NPUB 10 +#define NWR_PUB 2 + +void rw_init (void) +{ +} + +void rw_fini (void) +{ +} + +static void setqos (dds_qos_t *q, size_t i, bool isrd, bool create) +{ + size_t psi = i - (i % NWR_PUB); + /* Participant, publisher & topic get created with i == 0, + so make sure those have some crazy data set. The writers + should inherit the topic and group data, but the user data + should be updated for each writer */ + if (create) + { + if (psi == 1) + { + dds_qset_userdata (q, NULL, 0); + dds_qset_topicdata (q, NULL, 0); + dds_qset_groupdata (q, NULL, 0); + } + else + { + char buf[20]; + snprintf (buf, sizeof (buf), "ud%zu%c", i, isrd ? 'r' : 'w'); + dds_qset_userdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "td%zu", i); + dds_qset_topicdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "gd%zu", psi); + dds_qset_groupdata (q, buf, strlen (buf)); + } + } + else + { + if (psi == 1) + { + dds_qset_userdata (q, NULL, 0); + dds_qset_topicdata (q, NULL, 0); + dds_qset_groupdata (q, NULL, 0); + } + else + { + char buf[20]; + snprintf (buf, sizeof (buf), "ud%zu%c", i, isrd ? 'r' : 'w'); + dds_qset_userdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "td%zu", (size_t) 0); + dds_qset_topicdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "gd%zu", psi); + dds_qset_groupdata (q, buf, strlen (buf)); + } + } + + /* Cyclone's accepting unimplemented QoS settings is a bug, but it does allow + us to feed it all kinds of nonsense and see whether discovery manages it */ + + /* this makes topic transient-local, keep-last 1 */ + dds_qset_durability (q, (dds_durability_kind_t) ((i + 1) % 4)); + dds_qset_history (q, (dds_history_kind_t) ((i + 1) % 2), (int32_t) (i + 1)); + dds_qset_resource_limits (q, (int32_t) i + 3, (int32_t) i + 2, (int32_t) i + 1); + dds_qset_presentation (q, (dds_presentation_access_scope_kind_t) ((psi + 1) % 3), 1, 1); + dds_qset_lifespan (q, INT64_C (23456789012345678) + (int32_t) i); + dds_qset_deadline (q, INT64_C (67890123456789012) + (int32_t) i); + dds_qset_latency_budget (q, INT64_C (45678901234567890) + (int32_t) i); + dds_qset_ownership (q, (dds_ownership_kind_t) ((i + 1) % 2)); + dds_qset_ownership_strength (q, 0x12345670 + (int32_t) i); + dds_qset_liveliness (q, (dds_liveliness_kind_t) ((i + i) % 2), INT64_C (456789012345678901) + (int32_t) i); + dds_qset_time_based_filter (q, INT64_C (34567890123456789) + (int32_t) i); /* must be <= deadline */ + if (psi == 0) + dds_qset_partition1 (q, "p"); + else if (psi == 1) + dds_qset_partition (q, 0, NULL); + else + { + char **ps = ddsrt_malloc (psi * sizeof (*ps)); + for (size_t j = 0; j < psi; j++) + { + const size_t n = 40; + ps[j] = ddsrt_malloc (n); + snprintf (ps[j], n, "p%zu_%zu", psi, isrd ? (psi-j-1) : j); + } + dds_qset_partition (q, (uint32_t) psi, (const char **) ps); + for (size_t j = 0; j < psi; j++) + ddsrt_free (ps[j]); + ddsrt_free (ps); + } + dds_qset_reliability (q, (dds_reliability_kind_t) ((i + 1) % 2), INT64_C (890123456789012345) + (int32_t) i); + dds_qset_transport_priority (q, 0x23456701 + (int32_t) i); + dds_qset_destination_order (q, (dds_destination_order_kind_t) ((i + 1) % 2)); + dds_qset_writer_data_lifecycle (q, ((i + 1) % 2) != 0); + dds_qset_reader_data_lifecycle (q, INT64_C (41234567890123456) + (int32_t) i, INT64_C (912345678901234567) + (int32_t) i); + dds_qset_durability_service (q, INT64_C (123456789012345678) + (int32_t) i, (dds_history_kind_t) ((i + 1) % 2), (int32_t) (i + 1), (int32_t) i + 3, (int32_t) i + 2, (int32_t) i + 1); +} + +static bool pubsub_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + /* internal interface is more luxurious that a simple compare for equality, and + using that here saves us a ton of code */ + uint64_t delta = nn_xqos_delta (a, b, QP_GROUP_DATA | QP_PRESENTATION | QP_PARTITION); + if (delta) + { + struct ddsrt_log_cfg logcfg; + dds_log_cfg_init (&logcfg, 0, DDS_LC_ERROR, stderr, stderr); + DDS_CLOG (DDS_LC_ERROR, &logcfg, "pub/sub: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + nn_log_xqos (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +static uint64_t reader_qos_delta (const dds_qos_t *a, const dds_qos_t *b) +{ + return nn_xqos_delta (a, b, QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DURABILITY | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRESENTATION | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | QP_PARTITION | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_READER_DATA_LIFECYCLE); +} + +static bool reader_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + uint64_t delta = reader_qos_delta (a, b); + if (delta) + { + struct ddsrt_log_cfg logcfg; + dds_log_cfg_init (&logcfg, 0, DDS_LC_ERROR, stderr, stderr); + DDS_CLOG (DDS_LC_ERROR, &logcfg, "reader: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + nn_log_xqos (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +static uint64_t writer_qos_delta (const dds_qos_t *a, const dds_qos_t *b) +{ + return nn_xqos_delta (a, b, QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DURABILITY | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRESENTATION | QP_LIFESPAN | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_OWNERSHIP_STRENGTH | QP_LIVELINESS | QP_PARTITION | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_WRITER_DATA_LIFECYCLE); +} + +static bool writer_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + uint64_t delta = writer_qos_delta (a, b); + if (delta) + { + struct ddsrt_log_cfg logcfg; + dds_log_cfg_init (&logcfg, 0, DDS_LC_ERROR, stderr, stderr); + DDS_CLOG (DDS_LC_ERROR, &logcfg, "writer: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + nn_log_xqos (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +#define UD_QMPUB "qosmatch_publisher" +#define UD_QMPUBDONE UD_QMPUB ":ok" + +MPT_ProcessEntry (rw_publisher, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)) +{ + dds_entity_t dp; + dds_entity_t tp; + dds_entity_t pub[NPUB]; + dds_entity_t wr[NPUB][NWR_PUB]; + bool chk[NPUB][NWR_PUB] = { { false } }; + dds_return_t rc; + dds_qos_t *qos, *ppqos; + int id = (int) ddsrt_getpid (); + + printf ("=== [Publisher(%d)] Start(%d) ...\n", id, (int) domainid); + + ppqos = dds_create_qos (); + dds_qset_userdata (ppqos, UD_QMPUB, sizeof (UD_QMPUB) - 1); + dp = dds_create_participant (domainid, ppqos, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + + qos = dds_create_qos (); + setqos (qos, 0, false, true); + tp = dds_create_topic (dp, &RWData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT (tp, 0, "Could not create topic: %s\n", dds_strretcode (tp)); + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, false, true); + pub[i] = dds_create_publisher (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (pub[i], 0, "Could not create publisher %zu: %s\n", i, dds_strretcode (pub[i])); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, false, true); + wr[i][j] = dds_create_writer (pub[i], tp, qos, NULL); + MPT_ASSERT_FATAL_GT (wr[i][j], 0, "Could not create writer %zu %zu: %s\n", i, j, dds_strretcode (wr[i][j])); + } + } + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, false, false); + MPT_ASSERT (pubsub_qos_eq_h (qos, pub[i]), "publisher %zu QoS mismatch\n", i); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, false, false); + MPT_ASSERT (writer_qos_eq_h (qos, wr[i][j]), "writer %zu %zu QoS mismatch\n", i, j); + } + } + + /* Each writer should match exactly one reader */ + uint32_t nchk = 0; + while (nchk != NPUB * NWR_PUB) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + if (chk[i][j]) + continue; + dds_instance_handle_t ih; + dds_builtintopic_endpoint_t *ep; + rc = dds_get_matched_subscriptions (wr[i][j], &ih, 1); + MPT_ASSERT (rc == 0 || rc == 1, "Unexpected return from get_matched_subscriptions for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (rc == 1) + { + ep = dds_get_matched_subscription_data (wr[i][j], ih); + MPT_ASSERT (ep != NULL, "Failed to retrieve matched subscription data for writer %zu %zu\n", i, j); + setqos (qos, i * NWR_PUB + j, true, false); + uint64_t delta = reader_qos_delta (qos, ep->qos); + if (delta) + { + struct ddsrt_log_cfg logcfg; + dds_log_cfg_init (&logcfg, 0, DDS_LC_ERROR, stderr, stderr); + DDS_CLOG (DDS_LC_ERROR, &logcfg, "matched reader: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, &logcfg, qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + nn_log_xqos (DDS_LC_ERROR, &logcfg, ep->qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + } + MPT_ASSERT (delta == 0, "writer %zu %zu matched reader QoS mismatch\n", i, j); + dds_delete_qos (ep->qos); + dds_free (ep->topic_name); + dds_free (ep->type_name); + dds_free (ep); + chk[i][j] = true; + nchk++; + } + } + } + dds_sleepfor (DDS_MSECS (100)); + } + + dds_qset_userdata (ppqos, UD_QMPUBDONE, sizeof (UD_QMPUBDONE) - 1); + rc = dds_set_qos (dp, ppqos); + MPT_ASSERT_FATAL_EQ (rc, DDS_RETCODE_OK, "failed to participant QoS: %s\n", dds_strretcode (rc)); + + /* Wait until subscribers terminate */ + printf ("wait for subscribers to terminate\n"); + fflush (stdout); + while (true) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + dds_publication_matched_status_t st; + rc = dds_get_publication_matched_status (wr[i][j], &st); + MPT_ASSERT_FATAL_EQ (rc, DDS_RETCODE_OK, "dds_get_matched_publication_status failed for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (st.current_count) + { + printf ("%zu %zu: %d\n", i, j, (int) st.current_count); + fflush (stdout); + goto have_matches; + } + } + } + break; + have_matches: + ; + } + + dds_delete_qos (qos); + dds_delete_qos (ppqos); + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Publisher(%d)] Done\n", id); +} + +static void wait_for_done (dds_entity_t rd, const char *userdata) +{ + int32_t n; + void *raw = NULL; + dds_sample_info_t si; + bool done = false; + while (!done) + { + while (!done && (n = dds_take (rd, &raw, &si, 1, 1)) == 1) + { + const dds_builtintopic_participant_t *sample = raw; + void *ud = NULL; + size_t usz = 0; + if (!si.valid_data || !dds_qget_userdata (sample->qos, &ud, &usz)) + continue; + if (ud && strcmp (ud, userdata) == 0) + done = true; + dds_free (ud); + dds_return_loan (rd, &raw, 1); + } + + if (!done) + dds_sleepfor (DDS_MSECS (100)); + } +} + +MPT_ProcessEntry (rw_subscriber, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)) +{ + dds_entity_t dp, pprd; + dds_entity_t tp; + dds_entity_t sub[NPUB]; + dds_entity_t rd[NPUB][NWR_PUB]; + bool chk[NPUB][NWR_PUB] = { { false } }; + dds_return_t rc; + dds_qos_t *qos; + int id = (int) ddsrt_getpid (); + + printf ("=== [Subscriber(%d)] Start(%d) ...\n", id, (int) domainid); + + dp = dds_create_participant (domainid, NULL, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + pprd = dds_create_reader (dp, DDS_BUILTIN_TOPIC_DCPSPARTICIPANT, NULL, NULL); + MPT_ASSERT_FATAL_GT (pprd, 0, "Could not create DCPSParticipant reader: %s\n", dds_strretcode (pprd)); + + qos = dds_create_qos (); + setqos (qos, 0, true, true); + tp = dds_create_topic (dp, &RWData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT (tp, 0, "Could not create topic: %s\n", dds_strretcode (tp)); + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, true, true); + sub[i] = dds_create_subscriber (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (sub[i], 0, "Could not create subscriber %zu: %s\n", i, dds_strretcode (sub[i])); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, true, true); + rd[i][j] = dds_create_reader (sub[i], tp, qos, NULL); + MPT_ASSERT_FATAL_GT (rd[i][j], 0, "Could not create reader %zu %zu: %s\n", i, j, dds_strretcode (rd[i][j])); + } + } + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, true, false); + MPT_ASSERT (pubsub_qos_eq_h (qos, sub[i]), "subscriber %zu QoS mismatch\n", i); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, true, false); + MPT_ASSERT (reader_qos_eq_h (qos, rd[i][j]), "reader %zu %zu QoS mismatch\n", i, j); + } + } + + /* Each writer should match exactly one reader */ + uint32_t nchk = 0; + while (nchk != NPUB * NWR_PUB) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + if (chk[i][j]) + continue; + dds_instance_handle_t ih; + dds_builtintopic_endpoint_t *ep; + rc = dds_get_matched_publications (rd[i][j], &ih, 1); + MPT_ASSERT (rc == 0 || rc == 1, "Unexpected return from get_matched_publications for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (rc == 1) + { + ep = dds_get_matched_publication_data (rd[i][j], ih); + MPT_ASSERT (ep != NULL, "Failed to retrieve matched publication data for writer %zu %zu\n", i, j); + setqos (qos, i * NWR_PUB + j, false, false); + uint64_t delta = writer_qos_delta (qos, ep->qos); + if (delta) + { + struct ddsrt_log_cfg logcfg; + dds_log_cfg_init (&logcfg, 0, DDS_LC_ERROR, stderr, stderr); + DDS_CLOG (DDS_LC_ERROR, &logcfg, "matched writer: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, &logcfg, qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + nn_log_xqos (DDS_LC_ERROR, &logcfg, ep->qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + } + MPT_ASSERT (delta == 0, "reader %zu %zu matched writer QoS mismatch\n", i, j); + dds_delete_qos (ep->qos); + dds_free (ep->topic_name); + dds_free (ep->type_name); + dds_free (ep); + chk[i][j] = true; + nchk++; + } + } + } + dds_sleepfor (DDS_MSECS (100)); + } + + printf ("wait for publisher to have completed its checks\n"); + wait_for_done (pprd, UD_QMPUBDONE); + + dds_delete_qos (qos); + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Subscriber(%d)] Done\n", id); +} diff --git a/src/mpt/tests/qos/procs/rw.h b/src/mpt/tests/qos/procs/rw.h new file mode 100644 index 0000000..bfd5b69 --- /dev/null +++ b/src/mpt/tests/qos/procs/rw.h @@ -0,0 +1,41 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef MPT_QOSMATCH_PROCS_RW_H +#define MPT_QOSMATCH_PROCS_RW_H + +#include +#include + +#include "dds/dds.h" +#include "mpt/mpt.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +void rw_init (void); +void rw_fini (void); + +MPT_ProcessEntry (rw_publisher, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)); + +MPT_ProcessEntry (rw_subscriber, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)); + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/mpt/tests/qos/procs/rwdata.idl b/src/mpt/tests/qos/procs/rwdata.idl new file mode 100644 index 0000000..3e821a1 --- /dev/null +++ b/src/mpt/tests/qos/procs/rwdata.idl @@ -0,0 +1,19 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +module RWData +{ + struct Msg + { + long k; + }; + #pragma keylist Msg k +}; diff --git a/src/mpt/tests/qos/qosmatch.c b/src/mpt/tests/qos/qosmatch.c new file mode 100644 index 0000000..c6b0c5a --- /dev/null +++ b/src/mpt/tests/qos/qosmatch.c @@ -0,0 +1,21 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "mpt/mpt.h" +#include "procs/rw.h" + +#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_qosmatch") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_qosmatch") +MPT_TestProcess(qos, qosmatch, pub, rw_publisher, TEST_PUB_ARGS); +MPT_TestProcess(qos, qosmatch, sub, rw_subscriber, TEST_SUB_ARGS); +MPT_Test(qos, qosmatch, .init=rw_init, .fini=rw_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS diff --git a/src/scripts/cmake/vdds_install_examples.in b/src/scripts/cmake/vdds_install_examples.in deleted file mode 100755 index 88d3210..0000000 --- a/src/scripts/cmake/vdds_install_examples.in +++ /dev/null @@ -1,199 +0,0 @@ -#!/bin/sh -# -# 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 -# - -OUTPUT_DIR= -SCRIPT_DIR= -EXAMPLES_DIR= -EXPLICIT_YES=false -HELP_SHOWN=false - - -show_help() { -# Show help only once. -if [ $HELP_SHOWN = false ]; then -cat << EOF -Usage: ${0##*/} [-h] [-y] [-d OUTDIR] - -The @CMAKE_PROJECT_NAME@ examples are probably installed in a read-only location. -By executing this script, the examples can be (re)installed to a writable -location. That could be helpful when trying to experiment with the examples. - - -d|--dir OUTDIR Install the examples in OUTDIR. - This directory should not be a sub-directory of the - examples location. - If not set, an output dir will be asked for. When asking - for an output dir, the current directory is used as - suggestion. - -h|--help This text. - -y|--yes Use 'yes' for every question. -EOF -HELP_SHOWN=true -fi -} - - -# -# Parse command line arguments. -# -if [ -z "$1" ]; then - show_help - printf '\n' -else - while :; do - case $1 in - -h|-\?|--help) - show_help - exit - ;; - -d|--dir) - if [ "$2" ]; then - OUTPUT_DIR=$2 - shift - else - show_help - printf '\nERROR: "-d|--dir" requires a non-empty option argument.\n' "$1" >&2 - exit 1 - fi - ;; - -y|--yes) - EXPLICIT_YES=true - ;; - -?*) - printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2 - ;; - *) - break - esac - shift - done -fi - - -# -# Get the location of the script. -# -SCRIPT=`readlink -f "$0"` -SCRIPT_DIR=`dirname "$SCRIPT"` - - -# -# Try a few locations where the examples probably are. -# -EXAMPLES_DIR_DEFAULT="/usr/share/@CMAKE_PROJECT_NAME@/examples" -EXAMPLES_DIR_RELATIVE="$SCRIPT_DIR/../share/@CMAKE_PROJECT_NAME@/examples" -EXAMPLES_DIR_CURRENT=`pwd` - -if [ -d "$EXAMPLES_DIR_DEFAULT" ]; then - EXAMPLES_DIR="$EXAMPLES_DIR_DEFAULT" -elif [ -d "$EXAMPLES_DIR_RELATIVE" ]; then - EXAMPLES_DIR="$EXAMPLES_DIR_RELATIVE" -elif [ -d "$EXAMPLES_DIR_CURRENT" ]; then - case "$EXAMPLES_DIR_CURRENT" in - *@CMAKE_PROJECT_NAME@/examples) EXAMPLES_DIR="$EXAMPLES_DIR_CURRENT" - esac -fi - -if [ -z "$EXAMPLES_DIR" ]; then - show_help - printf '\nERROR: Could not find the @CMAKE_PROJECT_NAME@ examples at any of these locations:\n' >&2 - printf ' - [Default ] - %s\n' "$EXAMPLES_DIR_DEFAULT" >&2 - printf ' - [Relative] - %s\n' "$EXAMPLES_DIR_RELATIVE" >&2 - printf ' - [Current ] - %s\n' "$EXAMPLES_DIR_CURRENT" >&2 - exit 1 -fi - - -# -# Only get the output dir ourselves when it wasn't already set by the -# command line arguments. -# -if [ -z "$OUTPUT_DIR" ]; then - # Assume the examples should be installed in the current directory. - OUTPUT_DIR=`pwd` - - # When explicit 'yes' is provided as a command line argument, then - # don't ask if the assumption is correct. - if [ $EXPLICIT_YES = false ]; then - - # Keep pestering the user until we have a proper answer. - while true; do - YNC= - if [ "$OUTPUT_DIR" = "$EXAMPLES_DIR" ]; then - YNC="N" - elif [ ! -w "$OUTPUT_DIR" ]; then - YNC="N" - else - read -p "Do you wish to install the @CMAKE_PROJECT_NAME@ examples in \"$OUTPUT_DIR\"? [Yes|No|Cancel] " YNC - fi - case $YNC in - [Yy]* ) break;; - [Nn]* ) read -p "New examples install directory> " OUTPUT_DIR; break;; - [Cc]* ) exit;; - * ) echo "Please answer yes, no or cancel.";; - esac - done - elif [ "$OUTPUT_DIR" = "$EXAMPLES_DIR" ]; then - show_help - printf '\nERROR: Destination is same as source.\n' - exit 1 - fi -fi - - -# -# Check if the output dir is valid. -# -if [ ! -d "$OUTPUT_DIR" ]; then - # Only ask for permission if an explicit yes wasn't part of - # the command line arguments. - if [ $EXPLICIT_YES = false ]; then - while true; do - read -p "Do you wish to create directory \"$OUTPUT_DIR\"? [Yes|No] " YN - case $YN in - [Yy]* ) break;; - [Nn]* ) exit;; - * ) echo "Please answer yes or no.";; - esac - done - fi - mkdir -p "$OUTPUT_DIR" - if [ $? -ne 0 ]; then - printf 'ERROR: Could not create directory "%s"\n' "$OUTPUT_DIR" - exit 1 - fi -fi -# If the directory still doesn't exist, exit. -if [ ! -d "$OUTPUT_DIR" ]; then - show_help - printf '\nERROR: Directory "%s" does not exist.\n' "$OUTPUT_DIR" >&2 - exit 1 -fi -# If the directory isn't writable, exit. -if [ ! -w "$OUTPUT_DIR" ]; then - show_help - printf '\nERROR: Directory "%s" does not have write permission.\n' "$OUTPUT_DIR" >&2 - exit 1 -fi - - -# -# Copy the examples. -# -cp -Rf "$EXAMPLES_DIR" "$OUTPUT_DIR" -if [ $? -ne 0 ]; then - printf 'ERROR: Could not install examples\n' - exit 1 -else - printf 'Installed @CMAKE_PROJECT_NAME@ examples into "%s"\n' "$OUTPUT_DIR" -fi - diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 9c2d51c..27801bf 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0 which is available at @@ -11,15 +11,10 @@ # set(CMAKE_INSTALL_TOOLSDIR "${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/tools") add_subdirectory(pubsub) -add_subdirectory(config) +if(BUILD_CONFTOOL) + add_subdirectory(config) +endif() add_subdirectory(ddsls) -add_subdirectory(ddsperf) - -# VxWorks build machines use OpenJDK 8, which lack jfxrt.jar. Do not build launcher on that platform. -# -# TODO Instead of making inclusion dependent on platform name, the condition should instead be on the -# jdk vendor (Oracle JDK, not OpenJDK). Find a way to make CMake aware of jdk vendor. -#option(BUILD_LAUNCHER "Enable building of launcher." ON) -#if(NOT CMAKE_SYSTEM_NAME STREQUAL "VxWorks" AND BUILD_LAUNCHER) -# add_subdirectory(launcher) -#endif() +if(BUILD_IDLC) + add_subdirectory(ddsperf) +endif() diff --git a/src/tools/config/CMakeLists.txt b/src/tools/config/CMakeLists.txt index 3f7bded..139a46b 100644 --- a/src/tools/config/CMakeLists.txt +++ b/src/tools/config/CMakeLists.txt @@ -15,14 +15,10 @@ set(CONFJAR_TARGET "${CMAKE_PROJECT_NAME_SMALL}conf") #set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8" -Xlint:deprecation) -# Oddly enough, add_jar can't deal with a resource having an absolute path (experienced on Windows), so -# generate into the list-dir. -configure_file("metaconfig.xml.in" "${CMAKE_CURRENT_LIST_DIR}/metaconfig.xml" @ONLY) - file(GLOB_RECURSE JAVA_SOURCES LIST_DIRECTORIES true *.java) -set(RESOURCES metaconfig.xml metaconfig.xsd resources/ptlogoc16.png resources/ptlogoc24.png resources/ptlogoc32.png resources/ptlogoc48.png) -add_jar(${CONFJAR_TARGET} ${JAVA_SOURCES} ${RESOURCES} ENTRY_POINT org.eclipse.cyclonedds.config.SpliceConfig) +set(RESOURCES metaconfig.xml metaconfig.xsd ) +add_jar(${CONFJAR_TARGET} ${JAVA_SOURCES} ${RESOURCES} ENTRY_POINT org.eclipse.cyclonedds.config.CycloneConfig) #add_test(NAME TestHelloWorld COMMAND ${Java_JAVA_EXECUTABLE} -cp ${_jarFile} HelloWorld) diff --git a/src/tools/config/excx.pl b/src/tools/config/excx.pl new file mode 100644 index 0000000..a528b7b --- /dev/null +++ b/src/tools/config/excx.pl @@ -0,0 +1,471 @@ +: # -*- perl -*- +eval 'exec perl -w -S $0 "$@"' +if 0; + +use strict; + +# NOTES: +# - very fragile - and very sensitive to input formatting +# - default value may not contain a semicolon +# +# UGLINESSES: +# - knowledge of conversion functions in here +# - hard definitions of enums in here +# - negated_boolean is A BIT WEIRD and special-cased +# - some other hard-coded knowledge of the top level nodes +# - some hard-coded overrides for defaults +$|=1; + +my %typehint2xmltype = ("____" => "____", + "networkAddress" => "String", + "partitionAddress" => "String", + "networkAddresses" => "String", + "ipv4" => "String", + "boolean" => "Boolean", + "negated_boolean" => "Boolean", + "boolean_default" => "Enum", + "string" => "String", + "tracingOutputFileName" => "String", + "verbosity" => "Enum", + "tracemask" => "String", + "peer" => "String", + "float" => "Float", + "int" => "Int", + "int32" => "Int", + "uint" => "Int", + "uint32" => "Int", + "natint" => "Int", + "natint_255" => "Int", + "domainId" => "String", + "participantIndex" => "String", + "port" => "Int", + "dyn_port" => "Int", + "duration_inf" => "String", + "duration_ms_1hr" => "String", + "duration_ms_1s" => "String", + "duration_100ms_1hr" => "String", + "duration_us_1s" => "String", + "memsize" => "String", + "bandwidth" => "String", + "standards_conformance" => "Enum", + "locators" => "Enum", + "service_name" => "String", + "sched_class" => "Enum", + "cipher" => "Enum", + "besmode" => "Enum", + "retransmit_merging" => "Enum", + "sched_prio_class" => "Enum", + "sched_class" => "Enum", + "maybe_int32" => "String", + "maybe_memsize" => "String", + "maybe_duration_inf" => "String", + "allow_multicast" => "String", + "transport_selector" => "String", + "many_sockets_mode" => "Enum", + "xcheck" => "String", + "min_tls_version" => "String"); + +my %typehint2unit = ("duration_inf" => "duration_inf", + "duration_ms_1hr" => "duration", + "duration_100ms_1hr" => "duration", + "duration_ms_1s" => "duration", + "duration_us_1s" => "duration", + "bandwidth" => "bandwidth", + "memsize" => "memsize", + "maybe_memsize" => "memsize", + "maybe_duration_inf" => "duration_inf"); + +my %enum_values = ("locators" => "local;none", + "standards_conformance" => "lax;strict;pedantic", + "verbosity" => "finest;finer;fine;config;info;warning;severe;none", + "besmode" => "full;writers;minimal", + "retransmit_merging" => "never;adaptive;always", + "sched_prio_class" => "relative;absolute", + "sched_class" => "realtime;timeshare;default", + "cipher" => "null;blowfish;aes128;aes192;aes256", + "boolean_default" => "false;true;default", + "many_sockets_mode" => "false;true;single;none;many"); + +my %range = ("port" => "1;65535", + "dyn_port" => "-1;65535", + "general_cfgelems/startupmodeduration" => "0;60000", + "natint_255" => "0;255", + "duration_ms_1hr" => "0;1hr", + "duration_100ms_1hr" => "100ms;1hr", + "duration_ms_1s" => "0;1s", + "duration_us_1s" => "0;1s"); + +my %unit_blurb = ("bandwidth" => "\n

    The unit must be specified explicitly. Recognised units: Xb/s, Xbps for bits/s or XB/s, XBps for bytes/s; where X is an optional prefix: k for 103, Ki for 210, M for 106, Mi for 220, G for 109, Gi for 230.

    ", + "memsize" => "\n

    The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

    ", + "duration" => "\n

    The unit must be specified explicitly. Recognised units: ns, us, ms, s, min, hr, day.

    ", + "duration_inf" => "\n

    Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.

    "); + +while (my ($k, $v) = each %typehint2xmltype) { + die "script error: values of enum type $k unknown\n" if $v eq "Enum" && $enum_values{$k} eq ""; +} + +# Configurator can't handle UINT32_MAX ... instead of fixing it, just use a different +# default for the rare ones that have a problem (that works as long as there is no +# practical difference between the two) +my %default_overrides = ("multiple_recv_threads_attrs/maxretries" => 2000000000); + +my ($name, $table, $kind, $subtable, $multiplicity, $defaultvalue, $typehint, $description); + +my %tab2elems; +my %elem; +my %desc; +my %typehint_seen; +my $gobbling_description; +my $skip_lite; +my $in_table; +my $rest; +my $deprecated; + +############################ + +sub clean_description { + my ($desc) = @_; + $desc =~ s/^\s*BLURB\s*\(\s*//s; + $desc =~ s/^\s*"//s; + $desc =~ s/\s*"(\s*\))? *(\}\s*,\s*$)?$//s; + $desc =~ s/\\"/"/g; + $desc =~ s/\\n\s*\\/\n/g; + $desc =~ s/\\\\/\\/g; + $desc =~ s/\n\n/\n/g; + # should fix the source ... + $desc =~ s/DDSI2E?/Cyclone DDS/g; + return $desc; +} + +sub store_entry { + $name =~ s/\|.*//; # aliases are not visible in osplconf + my $ltable = lc $table; + my $lname = lc $name; + if (not exists $tab2elems{$ltable}) { + $tab2elems{$ltable} = $name; + } else { + $tab2elems{$ltable} .= ";$name"; + } + $elem{"$ltable/$lname"} = "$kind;$subtable;$multiplicity;$defaultvalue;$typehint"; + my $ub = exists $typehint2unit{$typehint} && exists $unit_blurb{$typehint2unit{$typehint}} ? $unit_blurb{$typehint2unit{$typehint}} : ""; + $desc{"$ltable/$lname"} = clean_description($description).$ub; + die "error: no mapping defined for type $typehint\n" if $typehint2xmltype{$typehint} eq ""; + $typehint_seen{$typehint} = 1; + #printf "%s - $s\n", "$ltable/$lname", $elem{"$ltable/lname"}; + #$typehint = ""; +} + +sub print_description { + my ($desc, $indent) = @_; + print "$indent \n"; +} + +sub kind_to_kstr { + my ($kind, $typehint, $table, $name, $isroot) = @_; + if ($isroot) { + die unless $kind eq "GROUP"; + return "rootElement"; + } elsif ($kind eq "GROUP" || $kind eq "MGROUP") { + return "element"; + } elsif ($kind eq "ATTR") { + return "attribute$typehint2xmltype{$typehint}"; + } elsif ($kind eq "LEAF") { + return "leaf$typehint2xmltype{$typehint}"; + } else { + die "error: $kind unrecognized kind ($table/$name)\n"; + } +} + +sub transform_default { + my (@fs) = @_; + (my $tmp = $fs[3]) =~ s/^"(.*)"$/$1/; + if ($fs[4] ne "negated_boolean") { + return $tmp; + } else { + my %map = ("true" => "false", "false" => "true"); + return $map{lc $tmp}; + } +} + +sub conv_to_xml { + my ($table, $name, $indent, $prefix, $isroot, $force_min_occ_1) = @_; + #, fs,vs,vsn,kstr,ts,tsi,tsn,i,min_occ,max_occ,rr,req) { # fs,vs,kstr,... are locals + my $lctn = lc "$table/$name"; + my @fs = split /;/, $elem{$lctn}; + #print "$table/$name - \n"; for (my $i = 0; $i < @fs; $i++) { print " - $i $fs[$i]\n" } + my $kstr = kind_to_kstr($fs[0], $fs[4], $table, $name, $isroot); + my ($min_occ, $max_occ); + if ($fs[2] =~ /MAX/) { + $min_occ = $max_occ = 0; + } elsif ($fs[2] == 0 || $fs[2] == 1) { + # multiplicity = 0 => special case, treat as-if 1 + # multiplicity = 1 => required if no default + # force_min_occ_1 so we can mark "Domain" as required and have it + # show up in the config editor when creating a new file + if ($force_min_occ_1) { + $min_occ = 1; + } elsif ($fs[0] eq "GROUP" || $fs[0] eq "MGROUP") { + $min_occ = 0; + } elsif ($fs[3] eq "" || $fs[3] eq "NULL") { + $min_occ = 1; + } else { + $min_occ = 0; + } + $max_occ = 1; + } else { + $min_occ = 0; $max_occ = $fs[2]; + } + if ($fs[0] eq "ATTR") { + my $req = ($min_occ == 0) ? "false" : "true"; + print "$indent<$kstr name=\"$name\" required=\"$req\">\n"; + } else { + print "$indent<$kstr name=\"$name\" minOccurrences=\"$min_occ\" maxOccurrences=\"$max_occ\">\n"; + } + print_description ("$prefix$desc{$lctn}", $indent); + # enum, int ranges + if (exists $enum_values{$fs[4]}) { + my @vs = split /;/, $enum_values{$fs[4]}; + print "$indent $_\n" for @vs; + } + my $rr = exists $range{$lctn} ? $range{$lctn} : ""; + if ($rr eq "" && exists $range{$fs[4]}) { $rr = $range{$fs[4]}; } + if ($rr ne "") { + my @vs = split /;/, $rr; + print "$indent $vs[0]\n"; + print "$indent $vs[1]\n"; + } + # remarkably, osplconf can't deal with strings for which no maximum + # length is specified, even though it accepts unlimited length + # strings ... + if ($typehint2xmltype{$fs[4]} eq "String") { + print "$indent 0\n"; + } + # default not applicable to GROUPs + if ($fs[0] ne "GROUP" && $fs[0] ne "MGROUP") { + my $defover = exists $default_overrides{$lctn} ? $default_overrides{$lctn} : ""; + if ($defover ne "") { + print "$indent $defover\n"; + } elsif ($fs[3] eq "" || $fs[3] eq "NULL") { + print "$indent \n"; + } else { + print "$indent ".transform_default(@fs)."\n"; + } + } + # recurse into subtables if any (except when it is the root: rootElement needs + # special treatment + if (!$isroot && $fs[1] ne "") { + my @ts = sort (split /,/, $fs[1]); + conv_table_to_xml($_, "$indent ", $prefix, 0, 0) for @ts; + } + print "$indent\n"; +} + +sub conv_table_to_xml { + my ($table, $indent, $prefix, $isroot, $force_min_occ_1) = @_; + return unless exists $tab2elems{$table}; + my @ns = sort (split /;/, $tab2elems{$table}); + conv_to_xml($table, $_, $indent, ($table eq "unsupp_cfgelems") ? "Internal" : $prefix, $isroot, $force_min_occ_1) for @ns; +} + +while (<>) { + if ($gobbling_description) { + $description .= $_; + #print " .. $_\n"; + } + + if ($gobbling_description && /(^|")(\s*\)) *\} *, *$/) { + $gobbling_description = 0; + store_entry() unless $deprecated; + next; + } + + if ($gobbling_description) { + next; + } + + if (/^[ \t]*(#[ \t]*(if|ifdef|ifndef|else|endif).*)?$/) { # skip empty lines, preproc + next; + } + + if (/^ *END_MARKER *$/) { + if (!$in_table) { + warn "END_MARKER seen while not in a table"; + } + $in_table = 0; + #print "END_MARKER $table\n"; + next; + } + + if (/^static +const +struct +cfgelem +([A-Za-z_0-9]+)\s*\[/) { + $in_table = 1; + $table = $1; + #print "TABLE $table\n"; + next; + } + + if ($in_table && /^ *WILDCARD *, *$|^ *\{ *(MOVED) *\(/) { + next; + } + + # Recognise all "normal" entries: attributes, groups, leaves and + # leaves with attributes. This doesn't recognise the ones used for the + # root groups: those are dealt with by the next pattern + if ($in_table && /^ *\{ *((?:DEPRECATED_)?(?:ATTR|GROUP|GROUP_W_ATTRS|MGROUP|LEAF|LEAF_W_ATTRS)) *\(/) { + $rest = $_; + # extract kind + $rest =~ s/^ *\{ *((?:DEPRECATED_)?(?:ATTR|GROUP|GROUP_W_ATTRS|MGROUP|LEAF|LEAF_W_ATTRS)) *\( *(.*)/$2/; + $kind = $1; + $deprecated = ($kind =~ s/^DEPRECATED_//); + # extract name + reference to subtable + $rest =~ s/\"([A-Za-z_0-9|]+)\" *(.*)/$2/; + $name = $1; + my ($subelems, $subattrs) = ("", ""); + if ($kind eq "GROUP" || $kind eq "GROUP_W_ATTRS" || $kind eq "MGROUP") { + $rest =~ s/, *([A-Za-z_0-9]+) *(.*)/$2/; + $subelems = $1; + } + if ($kind eq "LEAF_W_ATTRS" || $kind eq "GROUP_W_ATTRS" || $kind eq "MGROUP") { + $rest =~ s/, *([A-Za-z_0-9]+) *(.*)/$2/; + $subattrs = $1; + } + $subtable = ""; + if ($subelems ne "") { $subtable = $subelems; } + if ($subattrs ne "") { + if ($subtable ne "") { $subtable = "$subtable,$subattrs"; } + else { $subtable = $subattrs; } + } + $rest =~ s/ *\) *, *//; + #print " kind $kind name $name subtable $subtable -- $rest\n"; + + # don't care about the distinction between GROUP/LEAF and + # GROUP/LEAF_W_ATTRS in the remainer of the code: we simply + # rely on subtable. + $kind =~ s/_W_ATTRS//; + } + + # Root groups: use a special trick, which allows them to do groups + # with attributes. Which the DDSI2 proper doesn't use, but which the + # service configuration stuff does rely on. + if ($in_table && /^ *\{ *"([A-Za-z_0-9|]+)" *, */) { + $rest = $_; + # root elements are all groups, formatted as: , , + # , NODATA, description. They're therefore pretty easy to + # parse. + $kind = "GROUP"; + $rest =~ s/^ *\{ *\"([A-Za-z_0-9|]+)\" *, *(.*)/$2/; + $name = $1; + # then follow the sub-elements and the attributes + $rest =~ s/([A-Za-z_0-9]+) *, *(.*)/$2/; + my $subelems = $1; + $rest =~ s/([A-Za-z_0-9]+) *, *(.*)/$2/; + my $subattrs = $1; + # then we require NODATA (could do this in the pattern also) + die "error: NODATA expected" unless $rest =~ /^NODATA *,/; + # multiplicity is hard coded: we want to allow multiple ddsi2 services + $multiplicity = 0; + $subtable = ""; + if ($subelems ne "NULL") { $subtable = $subelems; } + if ($subattrs ne "NULL") { + if ($subtable ne "") { $subtable = "$subtable,$subattrs"; } + else { $subtable = $subattrs; } + } + $rest =~ s/([A-Za-z_0-9]+) *, *(.*)/$2/; + } + + # Extract stuff specific to ATTRs, LEAFs and MGROUPs + if ($in_table && ($kind eq "ATTR" || $kind eq "LEAF" || $kind eq "MGROUP")) { + # extract multiplicity + $rest =~ s/([0-9]+|U?INT(?:16|32|64)?_MAX) *, *(.*)/$2/; + $multiplicity = $1; + # extract default value + $rest =~ s/(\"(?:[^\"]*)\"|NULL|0) *, *(.*)/$2/; + $defaultvalue = $1; + if ($defaultvalue eq "0") { $defaultvalue = "NULL"; } + # skip reference to internal name (either ABSOFF(field), + # RELOFF(field,field) or , (the latter being used by + # "verbosity") + $rest =~ s/(ABSOFF *\( *[A-Za-z_0-9.]+ *\)|RELOFF *\( *[A-Za-z_0-9.]+ *, *[A-Za-z_0-9]+ *\)|[0-9]+ *, *[0-9]+) *, *//; + # skip init function + $rest =~ s/([A-Za-z_0-9]+|0) *, *//; + # type hint from conversion function + $rest =~ s/(uf_(?:[A-Za-z_0-9]+)|NULL|0) *, *(.*)/$2/; + $typehint = $1; + $typehint =~ s/^uf_//; + # accept typehint = NULL for a LEAF_WITH_ATTRS: there is no defined + # "syntax" for groups that have only attributes, pretending it is a + # group because that causes us to emit an "element" and not a + # "leaf". + if ($typehint eq "0" || $typehint eq "NULL") { + $kind = "GROUP"; + $typehint = "____"; + } + # skip free, print functions + $rest =~ s/([A-Za-z_0-9]+|0) *, *([A-Za-z_0-9]+|0) *, *//; + #print " .. multiplicity $multiplicity default $defaultvalue typehint $typehint\n"; + } + + # Extract description (or NULL, if not to be included in the configurator XML) + if ($in_table) { + #print " .. $rest\n"; + # description or NULL + if ($rest =~ /NULL *\} *, *$/) { + # no description - discard this one/simply continue with next one + } elsif ($rest =~ /(?:BLURB\s*\(\s*)?(".*")(?:\s*\))? *\} *, *$/) { + # description ending on same line + $description = $1; + store_entry() unless $deprecated; + } else { + # strip the quotes &c. once the full text has been gathered + $description = $rest; + $gobbling_description = 1; + } + #print " .. gobbling $gobbling_description"; + next; + } +} + +#print "$tab2elems{cyclonedds_root_cfgelems}\n"; +my @rootnames = split /;/, $tab2elems{cyclonedds_root_cfgelems}; +die "error: cyclonedds_root_cfgelems has no or multiple entries\n" if @rootnames != 1; +die "error: root_cfgelems doesn't exist\n" unless exists $tab2elems{root_cfgelems}; + +# Override the type for ControlTopic/Deaf, .../Mute so that an empty +# string is allowed by the configuration validation in spliced +# (easier than adding a boolean_or_empty to DDSI2 for a quick hack) +#if (elem["control_topic_cfgelems/deaf"] == "" || elem["control_topic_cfgelems/mute"] == "") { +# print FILENAME": error: control_topic_cfgelems/{deaf,mute} missing" > "/dev/stderr"; +# exit 1; +#} +#elem["control_topic_cfgelems/deaf"] = "LEAF;;1;\"false\";string"; +#elem["control_topic_cfgelems/mute"] = "LEAF;;1;\"false\";string"; + +print << 'EOT'; + + + + +EOT +conv_table_to_xml("cyclonedds_root_cfgelems", " ", "", 1, 0); +conv_table_to_xml("root_cfgelems", " ", "", 0, 1); +print << 'EOT'; + +EOT + +while (my ($k, $v) = each %typehint_seen) { + warn "script warning: type mapping defined for $k but not used" if $v == 0; +} diff --git a/src/tools/config/metaconfig.xml.in b/src/tools/config/metaconfig.xml similarity index 74% rename from src/tools/config/metaconfig.xml.in rename to src/tools/config/metaconfig.xml index 15c2ffd..1b421ce 100644 --- a/src/tools/config/metaconfig.xml.in +++ b/src/tools/config/metaconfig.xml @@ -9,47 +9,36 @@ http://www.eclipse.org/org/documents/edl-v10.php. SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + + === + generated from src/core/ddsi/src/q_config.c using excx.pl --> - + @CMAKE_PROJECT_NAME@ is highly configurable, allowing many configuration parameters - to be chosen by the user at deployment time by means of easily maintainable XML-file(s).

    - ]]>
    +CycloneDDS configuration + ]]> + 0
    The Domain identifies the scope of communication.

    - ]]>
    - - - - - 0 - any - -
    - - - - DDSI2 settings ...

    +

    The General element specifying Domain related settings.

    ]]>
    - CDR_CLIENT + 0 + + Domain id this configuration applies to, or "any" if it applies to all domain ids.

    + ]]>
    + 0 + any +
    This element is used to group a set of channels. The channels are independent data paths through DDSI2E and by using separate threads and setting their priorities appropriately, chanenls can be used to map transport priorities to operating system scheduler priorities, ensuring system-wide end-to-end priority preservation.

    +

    This element is used to group a set of channels. The channels are independent data paths through Cyclone DDS and by using separate threads and setting their priorities appropriately, chanenls can be used to map transport priorities to operating system scheduler priorities, ensuring system-wide end-to-end priority preservation.

    ]]>
    - + 0 + This element defines a channel.

    ]]>
    @@ -68,7 +57,7 @@ This element specifies the maximum transmit rate of auxiliary traffic on this channel (e.g. retransmits, heartbeats, etc). Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means DDSI2E imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    +

    This element specifies the maximum transmit rate of auxiliary traffic on this channel (e.g. retransmits, heartbeats, etc). Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means Cyclone DDS imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    The unit must be specified explicitly. Recognised units: Xb/s, Xbps for bits/s or XB/s, XBps for bytes/s; where X is an optional prefix: k for 103, Ki for 210, M for 106, Mi for 220, G for 109, Gi for 230.

    ]]>
    0 @@ -76,7 +65,7 @@
    This element specifies the maximum transmit rate of new samples and directly related data, for this channel. Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means DDSI2E imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    +

    This element specifies the maximum transmit rate of new samples and directly related data, for this channel. Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means Cyclone DDS imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    The unit must be specified explicitly. Recognised units: Xb/s, Xbps for bits/s or XB/s, XBps for bytes/s; where X is an optional prefix: k for 103, Ki for 210, M for 106, Mi for 220, G for 109, Gi for 230.

    ]]>
    0 @@ -101,19 +90,7 @@ When an application is run without Administrative priveleges then only the diffs The Compatibility elements allows specifying various settings related to compatability with standards and with other DDSI implementations.

    ]]>
    - - This element governs the representation of an acknowledgement message that does not also negatively-acknowledge some samples. If set to 0, the generated acknowledgements have an invalid form and will be reject by the strict and pedantic conformance modes, but several other implementation require this setting for smooth interoperation.

    -

    If set to 1, all acknowledgements sent by DDSI2E adhere the form of acknowledgement messages allowed by the standard, but this causes problems when interoperating with these other implementations. The strict and pedantic standards conformance modes always overrule an AckNackNumbitsEmptySet=0 to prevent the transmitting of invalid messages.

    - ]]>
    - 0 -
    - - When set to true, arrival of a message from a peer asserts liveliness of that peer. When set to false, only SPDP and explicit lease renewals have this effect.

    - ]]>
    - true -
    + 0 This option assumes ParticipantMessageData endpoints required by the liveliness protocol are present in RTI participants even when not properly advertised by the participant discovery protocol.

    @@ -130,7 +107,7 @@ When an application is run without Administrative priveleges then only the diffs This option specifies whether a network socket will be created for each domain participant on a host. The specification seems to assume that each participant has a unique address, and setting this option will ensure this to be the case. This is not the defeault.

    -

    Disabling it slightly improves performance and reduces network traffic somewhat. It also causes the set of port numbers needed by DDSI2E to become predictable, which may be useful for firewall and NAT configuration.

    +

    Disabling it slightly improves performance and reduces network traffic somewhat. It also causes the set of port numbers needed by Cyclone DDS to become predictable, which may be useful for firewall and NAT configuration.

    ]]>
    false true @@ -139,16 +116,9 @@ When an application is run without Administrative priveleges then only the diffs many single
    - - This element allows a closer mimicking of the behaviour of some other DDSI implementations, albeit at the cost of generating even more invalid messages. Setting it to true ensures a Heartbeat can be sent at any time when a remote node requests one, setting it to false delays it until a valid one can be sent.

    -

    The latter is fully compliant with the specification, and no adverse effects have been observed. It is the default.

    - ]]>
    - false -
    This element sets the level of standards conformance of this instance of the DDSI2E Service. Stricter conformance typically means less interoperability with other implementations. Currently three modes are defined:

    +

    This element sets the level of standards conformance of this instance of the Cyclone DDS Service. Stricter conformance typically means less interoperability with other implementations. Currently three modes are defined:

    • pedantic: very strictly conform to the specification, ultimately for compliancy testing, but currently of little value because it adheres even to what will most likely turn out to be editing errors in the DDSI standard. Arguably, as long as no errata have been published it is the current text that is in effect, and that is what pedantic currently does.
    • strict: a slightly less strict view of the standard than does pedantic: it follows the established behaviour where the standard is obviously in error.
    • lax: attempt to provide the smoothest possible interoperability, anticipating future revisions of elements in the standard in areas that other implementations do not adhere to, even though there is no good reason not to.
    @@ -164,12 +134,7 @@ When an application is run without Administrative priveleges then only the diffs The Discovery element allows specifying various parameters related to the discovery of peers.

    ]]>
    - - This element controls whether or not DDSI2E advertises writers for the built-in topics from its discovery for backwards compatibility with older OpenSplice versions.

    - ]]>
    - true -
    + 0 This setting controls for how long endpoints discovered via a Cloud discovery service will survive after the discovery service disappeared, allowing reconnect without loss of data when the discovery service restarts (or another instance takes over).

    @@ -193,13 +158,13 @@ When an application is run without Administrative priveleges then only the diffs
    This element specifies the maximum DDSI participant index selected by this instance of the DDSI2E service if the Discovery/ParticipantIndex is "auto".

    +

    This element specifies the maximum DDSI participant index selected by this instance of the Cyclone DDS service if the Discovery/ParticipantIndex is "auto".

    ]]>
    9
    This element specifies the DDSI participant index used by this instance of the DDSI2E service for discovery purposes. Only one such participant id is used, independent of the number of actual DomainParticipants on the node. It is either:

    +

    This element specifies the DDSI participant index used by this instance of the Cyclone DDS service for discovery purposes. Only one such participant id is used, independent of the number of actual DomainParticipants on the node. It is either:

    • auto: which will attempt to automatically determine an available participant index (see also Discovery/MaxAutoParticipantIndex), or
    • a non-negative integer less than 120, or
    • none:, which causes it to use arbitrary port numbers for unicast sockets which entirely removes the constraints on the participant index but makes unicast discovery impossible.
    @@ -313,21 +278,23 @@ When an application is run without Administrative priveleges then only the diffs
    The General element specifies overall DDSI2E service settings.

    +

    The General element specifies overall Cyclone DDS service settings.

    ]]>
    + 0 This element controls whether DDSI2E uses multicasts for data traffic.

    -

    It is a comma-separated list of some of the following keywords: "spdp", "asm", "ssm", or either of "false" or "true".

    +

    This element controls whether Cyclone DDS uses multicasts for data traffic.

    +

    It is a comma-separated list of some of the following keywords: "spdp", "asm", "ssm", or either of "false" or "true", or "default".

      -
    • spdp: enables the use of ASM (any-source multicast) for participant discovery
    • -
    • asm: enables the use of ASM for all traffic (including SPDP)
    • +
    • spdp: enables the use of ASM (any-source multicast) for participant discovery, joining the multicast group on the discovery socket, transmitting SPDP messages to this group, but never advertising nor using any multicast address in any discovery message, thus forcing unicast communications for all endpoint discovery and user data.
    • +
    • asm: enables the use of ASM for all traffic, including receiving SPDP but not transmitting SPDP messages via multicast
    • ssm: enables the use of SSM (source-specific multicast) for all non-SPDP traffic (if supported)

    When set to "false" all multicasting is disabled. The default, "true" enables full use of multicasts. Listening for multicasts can be controlled by General/MulticastRecvNetworkInterfaceAddresses.

    +

    "default" maps on spdp if the network is a WiFi network, on true if it is a wired network

    ]]>
    0 - true + default
    false - - This element specifies whether DDSI packets are visible to all DDSI participants in the same process. It must be "true" for intra-process communications, i.e. a reader and writer communicating in the same address space. If enabled and using multicast then EnableMulticastLoopback must also be enabled.

    - ]]>
    - false -
    This element specifies whether DDSI2E allows IP multicast packets to be visible to all DDSI participants in the same node, including itself. It must be "true" for intra-node multicast communications, but if a node runs only a single DDSI2E service and does not host any other DDSI-capable programs, it should be set to "false" for improved performance.

    +

    This element specifies whether Cyclone DDS allows IP multicast packets to be visible to all DDSI participants in the same node, including itself. It must be "true" for intra-node multicast communications, but if a node runs only a single Cyclone DDS service and does not host any other DDSI-capable programs, it should be set to "false" for improved performance.

    ]]>
    true
    This element allows explicitly overruling the network address DDSI2E advertises in the discovery protocol, which by default is the address of the preferred network interface (General/NetworkInterfaceAddress), to allow DDSI2E to communicate across a Network Address Translation (NAT) device.

    +

    This element allows explicitly overruling the network address Cyclone DDS advertises in the discovery protocol, which by default is the address of the preferred network interface (General/NetworkInterfaceAddress), to allow Cyclone DDS to communicate across a Network Address Translation (NAT) device.

    ]]>
    0 auto @@ -364,7 +324,7 @@ When an application is run without Administrative priveleges then only the diffs
    This element specifies the size of DDSI sample fragments generated by DDSI2E. Samples larger than FragmentSize are fragmented into fragments of FragmentSize bytes each, except the last one, which may be smaller. The DDSI spec mandates a minimum fragment size of 1025 bytes, but DDSI2E will do whatever size is requested, accepting fragments of which the size is at least the minimum of 1025 and FragmentSize.

    +

    This element specifies the size of DDSI sample fragments generated by Cyclone DDS. Samples larger than FragmentSize are fragmented into fragments of FragmentSize bytes each, except the last one, which may be smaller. The DDSI spec mandates a minimum fragment size of 1025 bytes, but Cyclone DDS will do whatever size is requested, accepting fragments of which the size is at least the minimum of 1025 and FragmentSize.

    The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

    ]]>
    0 @@ -372,7 +332,7 @@ When an application is run without Administrative priveleges then only the diffs
    This element specifies the maximum size of the UDP payload that DDSI2E will generate. DDSI2E will try to maintain this limit within the bounds of the DDSI specification, which means that in some cases (especially for very low values of MaxMessageSize) larger payloads may sporadically be observed (currently up to 1192 B).

    +

    This element specifies the maximum size of the UDP payload that Cyclone DDS will generate. Cyclone DDS will try to maintain this limit within the bounds of the DDSI specification, which means that in some cases (especially for very low values of MaxMessageSize) larger payloads may sporadically be observed (currently up to 1192 B).

    On some networks it may be necessary to set this item to keep the packetsize below the MTU to prevent IP fragmentation. In those cases, it is generally advisable to also consider reducing Internal/FragmentSize.

    The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

    ]]>
    @@ -381,15 +341,15 @@ When an application is run without Administrative priveleges then only the diffs
    This element specifies on which network interfaces DDSI2E listens to multicasts. The following options are available:

    +

    This element specifies on which network interfaces Cyclone DDS listens to multicasts. The following options are available:

    • all: listen for multicasts on all multicast-capable interfaces; or
    • any: listen for multicasts on the operating system default interface; or
    • preferred: listen for multicasts on the preferred interface (General/NetworkInterfaceAddress); or
    • none: does not listen for multicasts on any interface; or
    • -
    • a comma-separated list of network addresses: configures DDSI2E to listen for multicasts on all of the listed addresses.
    • +
    • a comma-separated list of network addresses: configures Cyclone DDS to listen for multicasts on all of the listed addresses.
    -

    If DDSI2E is in IPv6 mode and the address of the preferred network interface is a link-local address, "all" is treated as a synonym for "preferred" and a comma-separated list is treated as "preferred" if it contains the preferred interface and as "none" if not.

    +

    If Cyclone DDS is in IPv6 mode and the address of the preferred network interface is a link-local address, "all" is treated as a synonym for "preferred" and a comma-separated list is treated as "preferred" if it contains the preferred interface and as "none" if not.

    ]]>
    0 preferred @@ -404,29 +364,17 @@ When an application is run without Administrative priveleges then only the diffs This element specifies the preferred network interface for use by DDSI2E. The preferred network interface determines the IP address that DDSI2E advertises in the discovery protocol (but see also General/ExternalNetworkAddress), and is also the only interface over which multicasts are transmitted. The interface can be identified by its IP address, network interface name or network portion of the address. If the value "auto" is entered here, DDSI2E will select what it considers the most suitable interface.

    +

    This element specifies the preferred network interface for use by Cyclone DDS. The preferred network interface determines the IP address that Cyclone DDS advertises in the discovery protocol (but see also General/ExternalNetworkAddress), and is also the only interface over which multicasts are transmitted. The interface can be identified by its IP address, network interface name or network portion of the address. If the value "auto" is entered here, Cyclone DDS will select what it considers the most suitable interface.

    ]]>
    0 auto
    - + This element configures whether startup-mode should also cover transient and persistent data, for configurations where the durability service does not take care of it. Configurations without defined merge policies best leave this enabled.

    +

    When false (default) Cyclone DDS uses unicast for data whenever there a single unicast suffices. Setting this to true makes it prefer multicasting data, falling back to unicast only when no multicast address is available.

    ]]>
    - true + false
    - - This element specifies how long the DDSI2E remains in its "startup" mode. While in "startup" mode all volatile reliable data published on the local node is retained as-if it were transient-local data, allowing existing readers on remote nodes to obtain the data even though discovering them takes some time. Best-effort data by definition need not arrive, and transient and persistent data are covered by the durability service.

    -

    Once the system is stable, DDSI2E keeps track of the existence of remote readers whether or not matching writers exist locally, avoiding this discovery delay and ensuring this is merely a node startup issue.

    -

    Setting General/StartupModeDuration to 0s will disable it.

    -

    The unit must be specified explicitly. Recognised units: ns, us, ms, s, min, hr, day.

    - ]]>
    - 0 - 60000 - 0 - 2 s -
    This element allows selecting the transport to be used (udp, udp6, tcp, tcp6, raweth)

    @@ -448,18 +396,13 @@ When an application is run without Administrative priveleges then only the diffs The Internal elements deal with a variety of settings that evolving and that are not necessarily fully supported. For the vast majority of the Internal settings, the functionality per-se is supported, but the right to change the way the options control the functionality is reserved. This includes renaming or moving options.

    ]]>
    + 0 Internal

    Proxy readers that are assumed to sill be retrieving historical data get this many samples retransmitted when they NACK something, even if some of these samples have sequence numbers outside the set covered by the NACK.

    ]]>
    0
    - - Internal

    This element controls whether to drop a reliable sample from a DDSI2E WHC before all readers have acknowledged it as soon as a later sample becomes available. It only affects DCPS data writers with a history QoS setting of KEEP_LAST with depth 1. The default setting, false, mimics the behaviour of the OpenSplice RT networking and is necessary to make the behaviour of wait_for_acknowledgements() consistent across the networking services.

    - ]]>
    - true -
    Internal

    This element controls which network interfaces are assumed to be capable of multicasting even when the interface flags returned by the operating system state it is not (this provides a workaround for some platforms). It is a comma-separated lists of patterns (with ? and * wildcards) against which the interface names are matched.

    @@ -477,7 +420,7 @@ When an application is run without Administrative priveleges then only the diffs
    Internal

    This element specifies the maximum transmit rate of auxiliary traffic not bound to a specific channel, such as discovery traffic, as well as auxiliary traffic related to a certain channel if that channel has elected to share this global AuxiliaryBandwidthLimit. Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means DDSI2E imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    +Internal

    This element specifies the maximum transmit rate of auxiliary traffic not bound to a specific channel, such as discovery traffic, as well as auxiliary traffic related to a certain channel if that channel has elected to share this global AuxiliaryBandwidthLimit. Bandwidth limiting uses a leaky bucket scheme. The default value "inf" means Cyclone DDS imposes no limitation, the underlying operating system and hardware will likely limit the maimum transmit rate.

    The unit must be specified explicitly. Recognised units: Xb/s, Xbps for bits/s or XB/s, XBps for bytes/s; where X is an optional prefix: k for 103, Ki for 210, M for 106, Mi for 220, G for 109, Gi for 230.

    ]]>
    0 @@ -496,53 +439,10 @@ When an application is run without Administrative priveleges then only the diffs minimal writers - - Internal

    This element forces all DDSI2E built-in discovery-related readers to request all historical data, instead of just one for each "topic". There is no indication that any of the current DDSI implementations requires changing of this setting, but it is conceivable that an implementation might track which participants have been informed of the existence of endpoints and which have not been, refusing communication with those that have "can't" know.

    -

    Should it be necessary to hide DDSI2E's shared discovery behaviour, set this to true and Internal/BuiltinEndpointSet to full.

    - ]]>
    - false -
    Internal

    The ControlTopic element allows configured whether DDSI2E provides a special control interface via a predefined topic or not.

    +Internal

    The ControlTopic element allows configured whether Cyclone DDS provides a special control interface via a predefined topic or not.

    ]]> - - Internal[DEPRECATED] - "

    This element controls whether DDSI2E should create a topic to control DDSI2E's behaviour dynamically.

    " - }, - - ]]> - false - - - Internal[DEPRECATED] - "

    This element controls after how much time an initial deaf/mute state will automatically reset.

    " - }, - -

    Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.

    - ]]>
    - 0 - inf - - - Internal[DEPRECATED] - "

    This element controls whether DDSI2E defaults to deaf mode or to normal mode. This controls both the initial behaviour and what behaviour it auto-reverts to.

    - ]]>
    - 0 - false -
    - - Internal[DEPRECATED] - "

    This element controls whether DDSI2E defaults to mute mode or to normal mode. This controls both the initial behaviour and what behaviour it auto-reverts to.

    - ]]>
    - 0 - false -
    256 - + Internal

    Forward all messages from a writer, rather than trying to forward each sample only once. The default of trying to forward each sample only once filters out duplicates for writers in multiple partitions under nearly all circumstances, but may still publish the odd duplicate. Note: the current implementation also can lose in contrived test cases, that publish more than 2**32 samples using a single data writer in conjunction with carefully controlled management of the writer history via cooperating local readers.

    +Internal

    This element enables expensive checks in builds with assertions enabled and is ignored otherwise. Recognised categories are:

    +
    • whc: writer history cache checking
    • +
    • rhc: reader history cache checking
    • +

      In addition, there is the keyword all that enables all checks.

      ]]> - false - + 0 + + Internal

      When true, include keyhashes in outgoing data for topics with keys.

      @@ -628,27 +532,31 @@ When an application is run without Administrative priveleges then only the diffs 0 10 s - - Internal

      This option enables a backwards-compatible, non-compliant setting and interpretation of the control flags in fragmented data messages. To be enabled only when requiring interoperability between compliant and non-compliant versions of DDSI2E for large messages.

      - ]]>
      - false -
      Internal

      This element controls whether or not implementation should internally monitor its own liveliness. If liveliness monitoring is enabled, stack traces can be dumped automatically when some thread appears to have stopped making progress.

      ]]>
      false + + Internal

      This element controls the interval at which to check whether threads have been making progress.

      +

      The unit must be specified explicitly. Recognised units: ns, us, ms, s, min, hr, day.

      + ]]>
      + 100ms + 1hr + 0 + 1s +
      Internal

      This element controls whether or not to write stack traces to the DDSI2 trace when a thread fails to make progress (on select platforms only).

      +Internal

      This element controls whether or not to write stack traces to the Cyclone DDS trace when a thread fails to make progress (on select platforms only).

      ]]>
      true
      Internal

      This elements configures the maximum number of DCPS domain participants this DDSI2E instance is willing to service. 0 is unlimited.

      +Internal

      This elements configures the maximum number of DCPS domain participants this Cyclone DDS instance is willing to service. 0 is unlimited.

      ]]>
      0
      @@ -668,7 +576,7 @@ When an application is run without Administrative priveleges then only the diffs Internal

      This setting controls the maximum (CDR) serialised size of samples that DDSI2E will forward in either direction. Samples larger than this are discarded with a warning.

      +Internal

      This setting controls the maximum (CDR) serialised size of samples that Cyclone DDS will forward in either direction. Samples larger than this are discarded with a warning.

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      0 @@ -676,14 +584,14 @@ When an application is run without Administrative priveleges then only the diffs
      Internal

      This element enables heartbeat-to-ack latency among DDSI2E services by prepending timestamps to Heartbeat and AckNack messages and calculating round trip times. This is non-standard behaviour. The measured latencies are quite noisy and are currently not used anywhere.

      +Internal

      This element enables heartbeat-to-ack latency among Cyclone DDS services by prepending timestamps to Heartbeat and AckNack messages and calculating round trip times. This is non-standard behaviour. The measured latencies are quite noisy and are currently not used anywhere.

      ]]>
      false
      Internal

      This setting controls the minimum size of socket receive buffers. The operating system provides some size receive buffer upon creation of the socket, this option can be used to increase the size of the buffer beyond that initially provided by the operating system. If the buffer size cannot be increased to the specified size, an error is reported.

      -

      The default setting is the word "default", which means DDSI2E will attempt to increase the buffer size to 1MB, but will silently accept a smaller buffer should that attempt fail.

      +

      The default setting is the word "default", which means Cyclone DDS will attempt to increase the buffer size to 1MB, but will silently accept a smaller buffer should that attempt fail.

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      0 @@ -708,13 +616,12 @@ When an application is run without Administrative priveleges then only the diffs Internal

      This element controls whether all traffic is handled by a single receive thread or whether multiple receive threads may be used to improve latency. Currently multiple receive threads are only used for connectionless transport (e.g., UDP) and ManySocketsMode not set to single (the default).

      ]]>
      true - + Internal

      Receive threads dedicated to a single socket can only be triggered for termination by sending a packet. Reception of any packet will do, so termination failure due to packet loss is exceedingly unlikely, but to eliminate all risks, it will retry as many times as specified by this attribute before aborting.

      ]]>
      - 0 - 4294967295 -
      + 2000000000 +
      Internal

      This element sets the maximum size in samples of a primary re-order administration. Each proxy writer has one primary re-order administration to buffer the packet flow in case some packets arrive out of order. Old samples are forwarded to secondary re-order administrations associated with readers in need of historical data.

      ]]>
      - 64 + 128 Internal

      This element controls for how long a remote participant that was previously deleted will remain on a blacklist to prevent rediscovery, giving the software on a node time to perform any cleanup actions it needs to do. To some extent this delay is required internally by DDSI2E, but in the default configuration with the 'enforce' attribute set to false, DDSI2E will reallow rediscovery as soon as it has cleared its internal administration. Setting it to too small a value may result in the entry being pruned from the blacklist before DDSI2E is ready, it is therefore recommended to set it to at least several seconds.

      +Internal

      This element controls for how long a remote participant that was previously deleted will remain on a blacklist to prevent rediscovery, giving the software on a node time to perform any cleanup actions it needs to do. To some extent this delay is required internally by Cyclone DDS, but in the default configuration with the 'enforce' attribute set to false, Cyclone DDS will reallow rediscovery as soon as it has cleared its internal administration. Setting it to too small a value may result in the entry being pruned from the blacklist before Cyclone DDS is ready, it is therefore recommended to set it to at least several seconds.

      Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.

      ]]>
      0 10s Internal

      This attribute controls whether the configured time during which recently deleted participants will not be rediscovered (i.e., "black listed") is enforced and following complete removal of the participant in DDSI2E, or whether it can be rediscovered earlier provided all traces of that participant have been removed already.

      +Internal

      This attribute controls whether the configured time during which recently deleted participants will not be rediscovered (i.e., "black listed") is enforced and following complete removal of the participant in Cyclone DDS, or whether it can be rediscovered earlier provided all traces of that participant have been removed already.

      ]]>
      false
      @@ -768,12 +675,12 @@ When an application is run without Administrative priveleges then only the diffs
      • never: retransmit only to the NACK-ing reader;
      • adaptive: attempt to combine retransmits needed for reliability, but send historical (transient-local) data to the requesting reader only;
      • always: do not distinguish between different causes, always try to merge.
      -

      The default is adaptive. See also Internal/RetransmitMergingPeriod.

      +

      The default is never. See also Internal/RetransmitMergingPeriod.

      ]]>
      never adaptive always - adaptive + never Internal

      This element sets the maximum size in samples of a secondary re-order administration. The secondary re-order administration is per reader in need of historical data.

      ]]>
      - 16 + 128 Internal

      This element controls whether DDSI2E advertises all the domain participants it serves in DDSI (when set to false), or rather only one domain participant (the one corresponding to the DDSI2E process; when set to true). In the latter case DDSI2E becomes the virtual owner of all readers and writers of all domain participants, dramatically reducing discovery traffic (a similar effect can be obtained by setting Internal/BuiltinEndpointSet to "minimal" but with less loss of information).

      - ]]>
      - false -
      - - Internal

      The element controls whether the mandatory multicasting of the participant discovery packets occurs. Completely disabling multicasting requires this element be set to true, and generally requires explicitly listing peers to ping for unicast discovery.

      -

      See also General/AllowMulticast.

      +Internal

      This element controls whether Cyclone DDS advertises all the domain participants it serves in DDSI (when set to false), or rather only one domain participant (the one corresponding to the Cyclone DDS process; when set to true). In the latter case Cyclone DDS becomes the virtual owner of all readers and writers of all domain participants, dramatically reducing discovery traffic (a similar effect can be obtained by setting Internal/BuiltinEndpointSet to "minimal" but with less loss of information).

      ]]>
      false
      @@ -880,13 +780,13 @@ When an application is run without Administrative priveleges then only the diffs ]]>
      Internal

      This element controls whether DDSI2E will adapt the high-water mark to current traffic conditions, based on retransmit requests and transmit pressure.

      +Internal

      This element controls whether Cyclone DDS will adapt the high-water mark to current traffic conditions, based on retransmit requests and transmit pressure.

      ]]>
      true
      Internal

      This element sets the maximum allowed high-water mark for the DDSI2E WHCs, expressed in bytes. A writer is suspended when the WHC reaches this size.

      +Internal

      This element sets the maximum allowed high-water mark for the Cyclone DDS WHCs, expressed in bytes. A writer is suspended when the WHC reaches this size.

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      0 @@ -894,7 +794,7 @@ When an application is run without Administrative priveleges then only the diffs
      Internal

      This element sets the initial level of the high-water mark for the DDSI2E WHCs, expressed in bytes.

      +Internal

      This element sets the initial level of the high-water mark for the Cyclone DDS WHCs, expressed in bytes.

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      0 @@ -902,7 +802,7 @@ When an application is run without Administrative priveleges then only the diffs
      Internal

      This element sets the low-water mark for the DDSI2E WHCs, expressed in bytes. A suspended writer resumes transmitting when its DDSI2E WHC shrinks to this size.

      +Internal

      This element sets the low-water mark for the Cyclone DDS WHCs, expressed in bytes. A suspended writer resumes transmitting when its Cyclone DDS WHC shrinks to this size.

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      0 @@ -928,19 +828,20 @@ When an application is run without Administrative priveleges then only the diffs The Partitioning element specifies DDSI2E network partitions and how DCPS partition/topic combinations are mapped onto the network partitions.

      +

      The Partitioning element specifies Cyclone DDS network partitions and how DCPS partition/topic combinations are mapped onto the network partitions.

      ]]>
      + 0 The IgnoredPartitions element specifies DCPS partition/topic combinations that are not distributed over the network.

      ]]>
      This element can be used to prevent certain combinations of DCPS partition and topic from being transmitted over the network. DDSI2E will complete ignore readers and writers for which all DCPS partitions as well as their topic is ignored, not even creating DDSI readers and writers to mirror the DCPS ones.

      +

      This element can be used to prevent certain combinations of DCPS partition and topic from being transmitted over the network. Cyclone DDS will complete ignore readers and writers for which all DCPS partitions as well as their topic is ignored, not even creating DDSI readers and writers to mirror the DCPS ones.

      ]]>
      This attribute specifies a partition and a topic expression, separated by a single '.', that are used to determine if a given partition and topic will be ignored or not. The expressions may use the usual wildcards '*' and '?'. DDSI2E will consider an wildcard DCPS partition to match an expression iff there exists a string that satisfies both expressions.

      +

      This attribute specifies a partition and a topic expression, separated by a single '.', that are used to determine if a given partition and topic will be ignored or not. The expressions may use the usual wildcards '*' and '?'. Cyclone DDS will consider an wildcard DCPS partition to match an expression iff there exists a string that satisfies both expressions.

      ]]>
      0 @@ -949,11 +850,11 @@ When an application is run without Administrative priveleges then only the diffs
      The NetworkPartitions element specifies the DDSI2E network partitions.

      +

      The NetworkPartitions element specifies the Cyclone DDS network partitions.

      ]]>
      This element defines a DDSI2E network partition.

      +

      This element defines a Cyclone DDS network partition.

      ]]>
      This attribute specifies the name of this DDSI2E network partition. Two network partitions cannot have the same name.

      +

      This attribute specifies the name of this Cyclone DDS network partition. Two network partitions cannot have the same name.

      ]]>
      0
      This attribute selects the DDSI2E security profile for encrypting the traffic mapped to this DDSI2E network partition. The default "null" means the network partition is unsecured; any other name refers to a security profile defined using the Security/SecurityProfile elements.

      +

      This attribute selects the Cyclone DDS security profile for encrypting the traffic mapped to this Cyclone DDS network partition. The default "null" means the network partition is unsecured; any other name refers to a security profile defined using the Security/SecurityProfile elements.

      ]]>
      0 null @@ -986,22 +887,22 @@ When an application is run without Administrative priveleges then only the diffs
      The PartitionMappings element specifies the mapping from DCPS partition/topic combinations to DDSI2E network partitions.

      +

      The PartitionMappings element specifies the mapping from DCPS partition/topic combinations to Cyclone DDS network partitions.

      ]]>
      This element defines a mapping from a DCPS partition/topic combination to a DDSI2E network partition. This allows partitioning data flows by using special multicast addresses for part of the data and possibly also encrypting the data flow.

      +

      This element defines a mapping from a DCPS partition/topic combination to a Cyclone DDS network partition. This allows partitioning data flows by using special multicast addresses for part of the data and possibly also encrypting the data flow.

      ]]>
      This attribute specifies a partition and a topic expression, separated by a single '.', that are used to determine if a given partition and topic maps to the DDSI2E network partition named by the NetworkPartition attribute in this PartitionMapping element. The expressions may use the usual wildcards '*' and '?'. DDSI2E will consider a wildcard DCPS partition to match an expression if there exists a string that satisfies both expressions.

      +

      This attribute specifies a partition and a topic expression, separated by a single '.', that are used to determine if a given partition and topic maps to the Cyclone DDS network partition named by the NetworkPartition attribute in this PartitionMapping element. The expressions may use the usual wildcards '*' and '?'. Cyclone DDS will consider a wildcard DCPS partition to match an expression if there exists a string that satisfies both expressions.

      ]]>
      0
      This attribute specifies which DDSI2E network partition is to be used for DCPS partition/topic combinations matching the DCPSPartitionTopic attribute within this PartitionMapping element.

      +

      This attribute specifies which Cyclone DDS network partition is to be used for DCPS partition/topic combinations matching the DCPSPartitionTopic attribute within this PartitionMapping element.

      ]]>
      0 @@ -1013,6 +914,7 @@ When an application is run without Administrative priveleges then only the diffs The SSL element allows specifying various parameters related to using SSL/TLS for DDSI over TCP.

      ]]>
      + 0 If disabled this allows SSL connections to occur even if an X509 certificate fails verification.

      @@ -1053,14 +955,13 @@ When an application is run without Administrative priveleges then only the diffs 0 keystore
      - + The minimum TLS version that may be negotiated, valid values are 1.2 and 1.3.

      ]]>
      - 1.2 - 1.3 + 0 1.3 -
      +
      This enables the use of self signed X509 certificates.

      @@ -1076,11 +977,12 @@ When an application is run without Administrative priveleges then only the diffs The Security element specifies DDSI2E security profiles that can be used to encrypt traffic mapped to DDSI2E network partitions.

      +

      The Security element specifies Cyclone DDS security profiles that can be used to encrypt traffic mapped to Cyclone DDS network partitions.

      ]]>
      + 0 This element defines a DDSI2E security profile.

      +

      This element defines a Cyclone DDS security profile.

      ]]>
      This attribute specifies the name of this DDSI2E security profile. Two security profiles cannot have the same name.

      +

      This attribute specifies the name of this Cyclone DDS security profile. Two security profiles cannot have the same name.

      ]]>
      0 @@ -1122,6 +1024,7 @@ When an application is run without Administrative priveleges then only the diffs The Sizing element specifies a variety of configuration settings dealing with expected system sizes, buffer sizes, &c.

      ]]>
      + 0 This element specifies the size of one allocation unit in the receive buffer. Must be greater than the maximum packet size by a modest amount (too large packets are dropped). Each allocation is shrunk immediately after processing a message, or freed straightaway.

      @@ -1130,48 +1033,20 @@ When an application is run without Administrative priveleges then only the diffs 0 128 KiB
      - + This element sets the size of a single receive buffer. Many receive buffers may be needed. Their size must be greater than ReceiveBufferChunkSize by a modest amount.

      +

      This element sets the size of a single receive buffer. Many receive buffers may be needed. The minimum workable size a little bit larger than Sizing/ReceiveBufferChunkSize, and the value used is taken as the configured value and the actual minimum workable size.

      +

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      ]]>
      - - This element controls whether DDSI2E will adapt the high-water mark to current traffic conditions, based on retransmit requests and transmit pressure.

      - ]]>
      - true -
      - - This element sets the maximum allowed high-water mark for the DDSI2E WHCs, expressed in bytes. A writer is suspended when the WHC reaches this size.

      -

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      - ]]>
      - 0 - 100 kB -
      - - This element sets the initial level of the high-water mark for the DDSI2E WHCs, expressed in bytes.

      -

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      - ]]>
      - 0 - 30 kB -
      - - This element sets the low-water mark for the DDSI2E WHCs, expressed in bytes. A suspended writer resumes transmitting when its DDSI2E WHC shrinks to this size.

      -

      The unit must be specified explicitly. Recognised units: B (bytes), kB & KiB (210 bytes), MB & MiB (220 bytes), GB & GiB (230 bytes).

      - ]]>
      - 0 - 1 kB -
      -
      + 0 + 1 MiB +
      The TCP element allows specifying various parameters related to running DDSI over TCP.

      ]]>
      + 0 Setting this to true means the unicast addresses in SPDP packets will be ignored and the peer address from the TCP connection will be used instead. This may help work around incorrectly advertised addresses when using TCP.

      @@ -1195,7 +1070,7 @@ When an application is run without Administrative priveleges then only the diffs
      This element specifies the TCP port number on which DDSI2E accepts connections. If the port is set it is used in entity locators, published with DDSI discovery. Dynamically allocated if zero. Disabled if -1 or not configured. If disabled other DDSI services will not be able to establish connections with the service, the service can only communicate by establishing connections to other services.

      +

      This element specifies the TCP port number on which Cyclone DDS accepts connections. If the port is set it is used in entity locators, published with DDSI discovery. Dynamically allocated if zero. Disabled if -1 or not configured. If disabled other DDSI services will not be able to establish connections with the service, the service can only communicate by establishing connections to other services.

      ]]>
      -1 65535 @@ -1226,6 +1101,7 @@ When an application is run without Administrative priveleges then only the diffs The ThreadPool element allows specifying various parameters related to using a thread pool to send DDSI messages to multiple unicast addresses (TCP or UDP).

      ]]>
      + 0 This element enables the optional thread pool.

      @@ -1249,7 +1125,8 @@ When an application is run without Administrative priveleges then only the diffs This element is used to set thread properties.

      ]]>
      - + 0 + This element is used to set thread properties.

      ]]>
      @@ -1304,6 +1181,7 @@ When an application is run without Administrative priveleges then only the diffs The Tracing element controls the amount and type of information that is written into the tracing log by the DDSI service. This is useful to track the DDSI service during application development.

      ]]>
      + 0 This option specifies whether the output is to be appended to an existing log file. The default is to create a new log file each time, which is generally the best option if a detailed log is generated.

      @@ -1338,7 +1216,7 @@ When an application is run without Administrative priveleges then only the diffs

      This option specifies where the logging is printed to. Note that stdout and stderr are treated as special values, representing "standard out" and "standard error" respectively. No file is created unless logging categories are enabled using the Tracing/Verbosity or Tracing/EnabledCategory settings.

      ]]>
      0 - .log + cyclonedds.log 0 - - This option has no effect.

      - ]]>
      - true - - This option has no effect

      - ]]>
      - true -
      -
      This element enables standard groups of categories, based on a desired verbosity level. This is in addition to the categories enabled by the Tracing/EnableCategory setting. Recognised verbosity levels and the categories they map to are:

      -
      • none: no DDSI2E log
      • +
        • none: no Cyclone DDS log
        • severe: error and fatal
        • warning: severe + warning
        • info: warning + info
        • @@ -1370,7 +1236,7 @@ When an application is run without Administrative priveleges then only the diffs
        • fine: config + discovery
        • finer: fine + traffic and timing
        • finest: finer + trace
        -

        While none prevents any message from being written to a DDSI2 log file.

        +

        While none prevents any message from being written to a Cyclone DDS log file.

        The categorisation of tracing output is incomplete and hence most of the verbosity levels and categories are not of much use in the current release. This is an ongoing process and here we describe the target situation rather than the current situation. Currently, the most useful verbosity levels are config, fine and finest.

        ]]> finest @@ -1384,40 +1250,5 @@ When an application is run without Administrative priveleges then only the diffs none - - This element specifies the type of OS scheduling class will be used by the thread that announces its liveliness periodically.

        - ]]>
        - - This element specifies the type of OS scheduling class will be used by the thread that announces its liveliness periodically.

        - ]]>
        - - This element specifies the thread scheduling class that will be used by the watchdog thread. The user may need the appropriate privileges from the underlying operating system to be able to assign some of the privileged scheduling classes.

        - ]]>
        - realtime - timeshare - default - default -
        - - This element specifies the thread priority. Only priorities that are supported by the underlying operating system can be assigned to this element. The user may need special privileges from the underlying operating system to be able to assign some of the privileged priorities.

        - ]]>
        - 0 - - This attribute specifies whether the specified Priority is a relative or absolute priority.

        - ]]>
        - relative - absolute - relative -
        -
        -
        -
        - - diff --git a/src/tools/config/org/eclipse/cyclonedds/config/SpliceConfig.java b/src/tools/config/org/eclipse/cyclonedds/config/CycloneConfig.java similarity index 88% rename from src/tools/config/org/eclipse/cyclonedds/config/SpliceConfig.java rename to src/tools/config/org/eclipse/cyclonedds/config/CycloneConfig.java index 71a3d0d..091a93c 100644 --- a/src/tools/config/org/eclipse/cyclonedds/config/SpliceConfig.java +++ b/src/tools/config/org/eclipse/cyclonedds/config/CycloneConfig.java @@ -15,17 +15,16 @@ import org.eclipse.cyclonedds.common.util.Initializer; import org.eclipse.cyclonedds.common.util.Report; import org.eclipse.cyclonedds.config.swing.ConfigWindow; -public class SpliceConfig extends Initializer { +public class CycloneConfig extends Initializer { /** - * Starts Splice Tuner. This function is the main class of Splice Tuner; - * - It checks for the right version of the JVM, this must be 1.5.0. + * Starts configuration. This function is the main class. + * * - It passes on the commandline arguments. Arguments that are supported * are: * -# * - * @param args These are passed on to the initialize function of the - * SpliceTuner object. + * @param args These are passed on to the initialize function */ public static void main(String[] args) { boolean redirect = true; @@ -33,7 +32,7 @@ public class SpliceConfig extends Initializer { String[] args2; String uri = null; - SpliceConfig t = new SpliceConfig(); + CycloneConfig t = new CycloneConfig(); for (int i = 0; i < args.length; i++) { if ("-noredirect".equals(args[i])) { diff --git a/src/tools/config/org/eclipse/cyclonedds/config/swing/ConfigWindow.java b/src/tools/config/org/eclipse/cyclonedds/config/swing/ConfigWindow.java index 26dc2ed..7e6d8ea 100644 --- a/src/tools/config/org/eclipse/cyclonedds/config/swing/ConfigWindow.java +++ b/src/tools/config/org/eclipse/cyclonedds/config/swing/ConfigWindow.java @@ -614,14 +614,8 @@ public class ConfigWindow extends MainWindow implements DataConfigurationListene try { List imgUrls = new ArrayList(4); // Expected location of the icons in tuner jar - URL url = getClass().getResource("/resources/ptlogoc16.png"); - imgUrls.add(url != null ? url : getClass().getResource("/ptlogoc16.png")); - url = getClass().getResource("/resources/ptlogoc24.png"); - imgUrls.add(url != null ? url : getClass().getResource("/ptlogoc24.png")); - url = getClass().getResource("/resources/ptlogoc32.png"); - imgUrls.add(url != null ? url : getClass().getResource("/ptlogoc32.png")); - url = getClass().getResource("/resources/ptlogoc48.png"); - imgUrls.add(url != null ? url : getClass().getResource("/ptlogoc48.png")); + //URL url = getClass().getResource("/resources/LOGO.png"); + //imgUrls.add(url != null ? url : getClass().getResource("/ptlogoc16.png")); appLogos = new ArrayList(4); for (URL imgUrl : imgUrls) { diff --git a/src/tools/config/resources/ptlogoc16.png b/src/tools/config/resources/ptlogoc16.png deleted file mode 100755 index dcabcd2..0000000 Binary files a/src/tools/config/resources/ptlogoc16.png and /dev/null differ diff --git a/src/tools/config/resources/ptlogoc24.png b/src/tools/config/resources/ptlogoc24.png deleted file mode 100755 index 3ddc6d1..0000000 Binary files a/src/tools/config/resources/ptlogoc24.png and /dev/null differ diff --git a/src/tools/config/resources/ptlogoc32.png b/src/tools/config/resources/ptlogoc32.png deleted file mode 100755 index d4957ae..0000000 Binary files a/src/tools/config/resources/ptlogoc32.png and /dev/null differ diff --git a/src/tools/config/resources/ptlogoc48.png b/src/tools/config/resources/ptlogoc48.png deleted file mode 100755 index 533131b..0000000 Binary files a/src/tools/config/resources/ptlogoc48.png and /dev/null differ diff --git a/src/tools/ddsls/ddsls.c b/src/tools/ddsls/ddsls.c index fed04c4..216cff6 100644 --- a/src/tools/ddsls/ddsls.c +++ b/src/tools/ddsls/ddsls.c @@ -24,7 +24,7 @@ #define MAX_SAMPLES 10 #define MAX_DURATION_BUFSZ 21 -char *qp_duration_str (char *buf, size_t bufsz, dds_duration_t d) +static char *qp_duration_str (char *buf, size_t bufsz, dds_duration_t d) { if (d == DDS_INFINITY) snprintf (buf, bufsz, "infinite"); @@ -33,7 +33,7 @@ char *qp_duration_str (char *buf, size_t bufsz, dds_duration_t d) return buf; } -size_t printable_seq_length (const unsigned char *as, size_t n) +static size_t printable_seq_length (const unsigned char *as, size_t n) { size_t i; for (i = 0; i < n; i++) { @@ -43,7 +43,7 @@ size_t printable_seq_length (const unsigned char *as, size_t n) return i; } -void print_octetseq (const unsigned char *v, size_t sz, FILE *fp) +static void print_octetseq (const unsigned char *v, size_t sz, FILE *fp) { size_t i, n; fprintf (fp, "%zu<", sz); @@ -69,7 +69,7 @@ void print_octetseq (const unsigned char *v, size_t sz, FILE *fp) fprintf (fp, ">"); } -void qp_user_data (const dds_qos_t *q, FILE *fp) +static void qp_user_data (const dds_qos_t *q, FILE *fp) { void *ud; size_t udsz; @@ -82,7 +82,7 @@ void qp_user_data (const dds_qos_t *q, FILE *fp) } } -void qp_topic_data (const dds_qos_t *q, FILE *fp) +static void qp_topic_data (const dds_qos_t *q, FILE *fp) { void *ud; size_t udsz; @@ -95,7 +95,7 @@ void qp_topic_data (const dds_qos_t *q, FILE *fp) } } -void qp_group_data (const dds_qos_t *q, FILE *fp) +static void qp_group_data (const dds_qos_t *q, FILE *fp) { void *ud; size_t udsz; @@ -108,7 +108,7 @@ void qp_group_data (const dds_qos_t *q, FILE *fp) } } -void qp_durability (const dds_qos_t *q, FILE *fp) +static void qp_durability (const dds_qos_t *q, FILE *fp) { dds_durability_kind_t kind; if (dds_qget_durability (q, &kind)) @@ -125,7 +125,7 @@ void qp_durability (const dds_qos_t *q, FILE *fp) } } -void qp_history (const dds_qos_t *q, FILE *fp) +static void qp_history (const dds_qos_t *q, FILE *fp) { dds_history_kind_t kind; int32_t depth; @@ -144,7 +144,7 @@ void qp_history (const dds_qos_t *q, FILE *fp) } } -void qp_resource_limits_1 (FILE *fp, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance, int indent) +static void qp_resource_limits_1 (FILE *fp, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance, int indent) { fprintf (fp, "%*.*sresource_limits: max_samples = ", indent, indent, ""); if (max_samples == DDS_LENGTH_UNLIMITED) @@ -163,14 +163,14 @@ void qp_resource_limits_1 (FILE *fp, int32_t max_samples, int32_t max_instances, fprintf (fp, "%"PRId32"\n", max_samples_per_instance); } -void qp_resource_limits (const dds_qos_t *q, FILE *fp) +static void qp_resource_limits (const dds_qos_t *q, FILE *fp) { int32_t max_samples, max_instances, max_samples_per_instance; if (dds_qget_resource_limits (q, &max_samples, &max_instances, &max_samples_per_instance)) qp_resource_limits_1 (fp, max_samples, max_instances, max_samples_per_instance, 2); } -void qp_presentation (const dds_qos_t *q, FILE *fp) +static void qp_presentation (const dds_qos_t *q, FILE *fp) { dds_presentation_access_scope_kind_t access_scope; bool coherent_access, ordered_access; @@ -187,7 +187,7 @@ void qp_presentation (const dds_qos_t *q, FILE *fp) } } -void qp_duration_qos (const dds_qos_t *q, FILE *fp, const char *what, bool (*qget) (const dds_qos_t * __restrict qos, dds_duration_t *d)) +static void qp_duration_qos (const dds_qos_t *q, FILE *fp, const char *what, bool (*qget) (const dds_qos_t * __restrict qos, dds_duration_t *d)) { dds_duration_t d; char buf[MAX_DURATION_BUFSZ]; @@ -195,27 +195,27 @@ void qp_duration_qos (const dds_qos_t *q, FILE *fp, const char *what, bool (*qge fprintf (fp, " %s = %s\n", what, qp_duration_str (buf, sizeof (buf), d)); } -void qp_lifespan (const dds_qos_t *q, FILE *fp) +static void qp_lifespan (const dds_qos_t *q, FILE *fp) { qp_duration_qos (q, fp, "lifespan: duration", dds_qget_lifespan); } -void qp_deadline (const dds_qos_t *q, FILE *fp) +static void qp_deadline (const dds_qos_t *q, FILE *fp) { qp_duration_qos (q, fp, "deadline: period", dds_qget_deadline); } -void qp_latency_budget (const dds_qos_t *q, FILE *fp) +static void qp_latency_budget (const dds_qos_t *q, FILE *fp) { qp_duration_qos (q, fp, "latency_budget: duration", dds_qget_latency_budget); } -void qp_time_based_filter (const dds_qos_t *q, FILE *fp) +static void qp_time_based_filter (const dds_qos_t *q, FILE *fp) { qp_duration_qos (q, fp, "time_based_filter: minimum_separation", dds_qget_time_based_filter); } -void qp_ownership (const dds_qos_t *q, FILE *fp) +static void qp_ownership (const dds_qos_t *q, FILE *fp) { dds_ownership_kind_t kind; char *s = "?"; @@ -230,14 +230,14 @@ void qp_ownership (const dds_qos_t *q, FILE *fp) } } -void qp_ownership_strength (const dds_qos_t *q, FILE *fp) +static void qp_ownership_strength (const dds_qos_t *q, FILE *fp) { int32_t value; if (dds_qget_ownership_strength (q, &value)) fprintf (fp, " ownership_strength: value = %"PRId32"\n", value); } -void qp_liveliness (const dds_qos_t *q, FILE *fp) +static void qp_liveliness (const dds_qos_t *q, FILE *fp) { dds_liveliness_kind_t kind; dds_duration_t lease_duration; @@ -255,7 +255,7 @@ void qp_liveliness (const dds_qos_t *q, FILE *fp) } } -void qp_reliability (const dds_qos_t *q, FILE *fp) +static void qp_reliability (const dds_qos_t *q, FILE *fp) { dds_reliability_kind_t kind; dds_duration_t max_blocking_time; @@ -272,14 +272,14 @@ void qp_reliability (const dds_qos_t *q, FILE *fp) } } -void qp_transport_priority (const dds_qos_t *q, FILE *fp) +static void qp_transport_priority (const dds_qos_t *q, FILE *fp) { int32_t value; if (dds_qget_transport_priority (q, &value)) fprintf (fp, " transport_priority: priority = %"PRId32"\n", value); } -void qp_destination_order (const dds_qos_t *q, FILE *fp) +static void qp_destination_order (const dds_qos_t *q, FILE *fp) { dds_destination_order_kind_t kind; if (dds_qget_destination_order (q, &kind)) @@ -294,14 +294,14 @@ void qp_destination_order (const dds_qos_t *q, FILE *fp) } } -void qp_writer_data_lifecycle (const dds_qos_t *q, FILE *fp) +static void qp_writer_data_lifecycle (const dds_qos_t *q, FILE *fp) { bool value; if (dds_qget_writer_data_lifecycle (q, &value)) fprintf (fp, " writer_data_lifecycle: autodispose_unregistered_instances = %s\n", value ? "true" : "false"); } -void qp_reader_data_lifecycle (const dds_qos_t *q, FILE *fp) +static void qp_reader_data_lifecycle (const dds_qos_t *q, FILE *fp) { dds_duration_t autopurge_nowriter_samples_delay, autopurge_disposed_samples_delay; if (dds_qget_reader_data_lifecycle (q, &autopurge_nowriter_samples_delay, &autopurge_disposed_samples_delay)) @@ -311,7 +311,7 @@ void qp_reader_data_lifecycle (const dds_qos_t *q, FILE *fp) } } -void qp_durability_service (const dds_qos_t *q, FILE *fp) +static void qp_durability_service (const dds_qos_t *q, FILE *fp) { dds_duration_t service_cleanup_delay; dds_history_kind_t history_kind; @@ -335,7 +335,7 @@ void qp_durability_service (const dds_qos_t *q, FILE *fp) } } -void qp_partition (const dds_qos_t *q, FILE *fp) +static void qp_partition (const dds_qos_t *q, FILE *fp) { uint32_t n; char **ps; @@ -360,7 +360,7 @@ void qp_partition (const dds_qos_t *q, FILE *fp) } } -void qp_qos (const dds_qos_t *q, FILE *fp) +static void qp_qos (const dds_qos_t *q, FILE *fp) { qp_reliability (q, fp); qp_durability (q, fp); @@ -385,7 +385,7 @@ void qp_qos (const dds_qos_t *q, FILE *fp) qp_group_data (q, fp); } -void print_key(FILE *fp, const char *label, const dds_builtintopic_guid_t *key) +static void print_key(FILE *fp, const char *label, const dds_builtintopic_guid_t *key) { fprintf(fp, "%s", label); for(size_t j = 0; j < sizeof (key->v); j++) { @@ -422,7 +422,7 @@ void print_dcps_topic (FILE *fp, dds_entity_t pp) } #endif -void print_dcps_participant (FILE *fp, dds_entity_t pp) +static void print_dcps_participant (FILE *fp, dds_entity_t pp) { dds_entity_t rd = dds_create_reader (pp, DDS_BUILTIN_TOPIC_DCPSPARTICIPANT, NULL, NULL); (void)dds_reader_wait_for_historical_data (rd, DDS_SECS (5)); @@ -448,7 +448,7 @@ void print_dcps_participant (FILE *fp, dds_entity_t pp) dds_delete (rd); } -void print_dcps_endpoint (FILE *fp, dds_entity_t pp, const char *type, dds_entity_t topic) +static void print_dcps_endpoint (FILE *fp, dds_entity_t pp, const char *type, dds_entity_t topic) { dds_entity_t rd = dds_create_reader (pp, topic, NULL, NULL); (void)dds_reader_wait_for_historical_data (rd, DDS_SECS (5)); @@ -477,12 +477,12 @@ void print_dcps_endpoint (FILE *fp, dds_entity_t pp, const char *type, dds_entit dds_delete (rd); } -void print_dcps_subscription (FILE *fp, dds_entity_t pp) +static void print_dcps_subscription (FILE *fp, dds_entity_t pp) { print_dcps_endpoint (fp, pp, "SUBSCRIPTION", DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION); } -void print_dcps_publication (FILE *fp, dds_entity_t pp) +static void print_dcps_publication (FILE *fp, dds_entity_t pp) { print_dcps_endpoint (fp, pp, "PUBLICATION", DDS_BUILTIN_TOPIC_DCPSPUBLICATION); } @@ -504,7 +504,7 @@ static struct topictab { }; #define TOPICTAB_SIZE (sizeof(topictab)/sizeof(struct topictab)) -void usage (void) +static void usage (void) { fprintf (stderr, "Usage: ddsls [OPTIONS] TOPIC... for specified topics\n\n"); fprintf (stderr, " or: ddsls [OPTIONS] -a for all topics\n"); diff --git a/src/tools/ddsperf/CMakeLists.txt b/src/tools/ddsperf/CMakeLists.txt index c1c12e0..25374b3 100644 --- a/src/tools/ddsperf/CMakeLists.txt +++ b/src/tools/ddsperf/CMakeLists.txt @@ -9,9 +9,11 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # + idlc_generate(ddsperf_types ddsperf_types.idl) -add_executable(ddsperf ddsperf.c) +add_executable(ddsperf ddsperf.c cputime.c cputime.h netload.c netload.h) target_link_libraries(ddsperf ddsperf_types ddsc) + if(WIN32) target_compile_definitions(ddsperf PRIVATE _CRT_SECURE_NO_WARNINGS) endif() diff --git a/src/tools/ddsperf/cputime.c b/src/tools/ddsperf/cputime.c new file mode 100644 index 0000000..591720d --- /dev/null +++ b/src/tools/ddsperf/cputime.c @@ -0,0 +1,264 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#define _ISOC99_SOURCE +#include +#include +#include +#include + +#include "dds/dds.h" + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/rusage.h" + +#include "cputime.h" +#include "ddsperf_types.h" + +static void print_one (char *line, size_t sz, size_t *pos, const char *name, double du, double ds) +{ + if (*pos < sz) + *pos += (size_t) snprintf (line + *pos, sz - *pos, " %s:%.0f%%+%.0f%%", name, 100.0 * du, 100.0 * ds); +} + +bool print_cputime (const struct CPUStats *s, const char *prefix, bool print_host, bool is_fresh) +{ + if (!s->some_above) + return false; + else + { + char line[512]; + size_t pos = 0; + assert (is_fresh || !print_host); + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, "%s", prefix); + if (!is_fresh) + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, " (stale)"); + if (print_host) + { + int n = (int) strlen (s->hostname); + if (n > 100) n = 100; + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, " @%*.*s:%"PRIu32, n, n, s->hostname, s->pid); + } + if (s->maxrss > 1048576) + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, " rss:%.1fMB", s->maxrss / 1048576.0); + else if (s->maxrss > 1024) + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, " rss:%.0fkB", s->maxrss / 1024.0); + else { + /* non-sensical value -- presumably maxrss is not available */ + } + pos += (size_t) snprintf (line + pos, sizeof (line) - pos, " vcsw:%"PRIu32" ivcsw:%"PRIu32, s->vcsw, s->ivcsw); + const size_t init_pos = pos; + for (uint32_t i = 0; i < s->cpu._length; i++) + { + struct CPUStatThread * const thr = &s->cpu._buffer[i]; + print_one (line, sizeof (line), &pos, thr->name, thr->u_pct / 100.0, thr->s_pct / 100.0); + } + if (pos > init_pos) + puts (line); + return true; + } +} + +#if DDSRT_HAVE_RUSAGE && DDSRT_HAVE_THREAD_LIST + +struct record_cputime_state_thr { + ddsrt_thread_list_id_t tid; + char name[32]; + double ut, st; +}; + +struct record_cputime_state { + bool supported; + dds_time_t tprev; + uint32_t vcswprev; + uint32_t ivcswprev; + size_t nthreads; + struct record_cputime_state_thr *threads; + dds_entity_t wr; + struct CPUStats s; +}; + +static void update (double *ut_old, double *st_old, double dt, double ut_new, double st_new, double *du, double *ds) +{ + *du = (ut_new - *ut_old) / dt; + *ds = (st_new - *st_old) / dt; + *ut_old = ut_new; + *st_old = st_new; +} + +static bool above_threshold (double *max, double *du_skip, double *ds_skip, double du, double ds) +{ + if (*max < du) *max = du; + if (*max < ds) *max = ds; + if (du >= 0.005 || ds >= 0.005) + return true; + else if (du_skip == NULL || ds_skip == NULL) + return false; + else + { + *du_skip += du; + *ds_skip += ds; + return false; + } +} + +bool record_cputime (struct record_cputime_state *state, const char *prefix, dds_time_t tnow) +{ + if (state == NULL) + return false; + + ddsrt_rusage_t usage; + if (ddsrt_getrusage (DDSRT_RUSAGE_SELF, &usage) < 0) + { + usage.maxrss = 0; + usage.nvcsw = usage.nivcsw = 0; + } + double max = 0; + double du_skip = 0.0, ds_skip = 0.0; + const double dt = (double) (tnow - state->tprev) / 1e9; + bool some_above = false; + + state->s.maxrss = (double) usage.maxrss; + state->s.vcsw = (uint32_t) ((double) (usage.nvcsw - state->vcswprev) / dt + 0.5); + state->s.ivcsw = (uint32_t) ((double) (usage.nivcsw - state->ivcswprev) / dt + 0.5); + state->vcswprev = (uint32_t) usage.nvcsw; + state->ivcswprev = (uint32_t) usage.nivcsw; + state->s.cpu._length = 0; + for (size_t i = 0; i < state->nthreads; i++) + { + struct record_cputime_state_thr * const thr = &state->threads[i]; + if (ddsrt_getrusage_anythread (thr->tid, &usage) < 0) + continue; + + const double ut = (double) usage.utime / 1e9; + const double st = (double) usage.stime / 1e9; + double du, ds; + update (&thr->ut, &thr->st, dt, ut, st, &du, &ds); + if (above_threshold (&max, &du_skip, &ds_skip, du, ds)) + { + some_above = true; + /* Thread names are often set by thread itself immediately after creation, + and so it depends on the scheduling whether there is still a default + name or the name we are interested in. Lazily retrieving the name the + first time the thread pops up in the CPU usage works around the timing + problem. */ + if (thr->name[0] == 0) + { + if (ddsrt_thread_getname_anythread (thr->tid, thr->name, sizeof (thr->name)) < 0) + { + du_skip += du; + ds_skip += ds; + continue; + } + } + + struct CPUStatThread * const x = &state->s.cpu._buffer[state->s.cpu._length++]; + x->name = thr->name; + x->u_pct = (int) (100.0 * du + 0.5); + x->s_pct = (int) (100.0 * ds + 0.5); + } + } + if (above_threshold (&max, NULL, NULL, du_skip, ds_skip)) + { + struct CPUStatThread * const x = &state->s.cpu._buffer[state->s.cpu._length++]; + some_above = true; + x->name = "others"; + x->u_pct = (int) (100.0 * du_skip + 0.5); + x->s_pct = (int) (100.0 * ds_skip + 0.5); + } + state->tprev = tnow; + state->s.some_above = some_above; + dds_write (state->wr, &state->s); + return print_cputime (&state->s, prefix, false, true); +} + +struct record_cputime_state *record_cputime_new (dds_entity_t wr) +{ + ddsrt_thread_list_id_t tids[100]; + dds_return_t n; + if ((n = ddsrt_thread_list (tids, sizeof (tids) / sizeof (tids[0]))) <= 0) + return NULL; + else if (n > (dds_return_t) (sizeof (tids) / sizeof (tids[0]))) + { + fprintf (stderr, "way more threads than expected\n"); + return NULL; + } + + struct record_cputime_state *state = malloc (sizeof (*state)); + ddsrt_rusage_t usage; + if (ddsrt_getrusage (DDSRT_RUSAGE_SELF, &usage) < 0) + usage.nvcsw = usage.nivcsw = 0; + state->tprev = dds_time (); + state->wr = wr; + state->vcswprev = (uint32_t) usage.nvcsw; + state->ivcswprev = (uint32_t) usage.nivcsw; + state->threads = malloc ((size_t) n * sizeof (*state->threads)); + state->nthreads = 0; + for (int32_t i = 0; i < n; i++) + { + struct record_cputime_state_thr * const thr = &state->threads[state->nthreads]; + if (ddsrt_getrusage_anythread (tids[i], &usage) < 0) + continue; + thr->tid = tids[i]; + thr->name[0] = 0; + thr->ut = (double) usage.utime / 1e9; + thr->st = (double) usage.stime / 1e9; + state->nthreads++; + } + + char hostname[128]; + if (ddsrt_gethostname (hostname, sizeof (hostname)) != DDS_RETCODE_OK) + strcpy (hostname, "?"); + state->s.hostname = ddsrt_strdup (hostname); + state->s.pid = (uint32_t) ddsrt_getpid (); + state->s.cpu._length = 0; + state->s.cpu._maximum = (uint32_t) state->nthreads; + state->s.cpu._buffer = malloc (state->s.cpu._maximum * sizeof (*state->s.cpu._buffer)); + state->s.cpu._release = false; + return state; +} + +void record_cputime_free (struct record_cputime_state *state) +{ + if (state) + { + free (state->threads); + ddsrt_free (state->s.hostname); + /* we alias thread names in state->s->cpu._buffer, so no need to free */ + free (state->s.cpu._buffer); + free (state); + } +} + +#else + +bool record_cputime (struct record_cputime_state *state, const char *prefix, dds_time_t tnow) +{ + (void) state; + (void) prefix; + (void) tnow; +} + +struct record_cputime_state *record_cputime_new (dds_entity_t wr) +{ + (void) wr; +} + +void record_cputime_free (struct record_cputime_state *state) +{ + (void) state; +} + +#endif diff --git a/src/tools/ddsperf/cputime.h b/src/tools/ddsperf/cputime.h new file mode 100644 index 0000000..3216692 --- /dev/null +++ b/src/tools/ddsperf/cputime.h @@ -0,0 +1,24 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CPUTIME_H +#define CPUTIME_H + +#include "ddsperf_types.h" + +struct record_cputime_state; + +struct record_cputime_state *record_cputime_new (dds_entity_t wr); +void record_cputime_free (struct record_cputime_state *state); +bool record_cputime (struct record_cputime_state *state, const char *prefix, dds_time_t tnow); +bool print_cputime (const struct CPUStats *s, const char *prefix, bool print_host, bool is_fresh); + +#endif diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c index cef4870..d0eeb89 100644 --- a/src/tools/ddsperf/ddsperf.c +++ b/src/tools/ddsperf/ddsperf.c @@ -10,6 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #define _ISOC99_SOURCE +#define _POSIX_PTHREAD_SEMANTICS #include #include #include @@ -19,10 +20,9 @@ #include #include #include -#ifndef _WIN32 -#include -#endif +#if _WIN32 #include +#endif #include "dds/dds.h" #include "ddsperf_types.h" @@ -35,6 +35,14 @@ #include "dds/ddsrt/random.h" #include "dds/ddsrt/avl.h" #include "dds/ddsrt/fibheap.h" +#include "dds/ddsrt/atomics.h" + +#include "cputime.h" +#include "netload.h" + +#if !defined(_WIN32) && !defined(LWIP_SOCKET) +#include +#endif #define UDATA_MAGIC "DDSPerf:" #define UDATA_MAGIC_SIZE (sizeof (UDATA_MAGIC) - 1) @@ -56,7 +64,7 @@ enum submode { }; static const char *argv0; -static volatile sig_atomic_t termflag = 0; +static ddsrt_atomic_uint32_t termflag = DDSRT_ATOMIC_UINT32_INIT (0); /* Domain participant, guard condition for termination, domain id */ static dds_entity_t dp; @@ -69,22 +77,22 @@ static dds_entity_t rd_participants, rd_subscriptions, rd_publications; /* Topics, readers, writers (except for pong writers: there are many of those) */ -static dds_entity_t tp_data, tp_ping, tp_pong; +static dds_entity_t tp_data, tp_ping, tp_pong, tp_stat; static char tpname_data[32], tpname_ping[32], tpname_pong[32]; -static dds_entity_t sub, pub, wr_data, wr_ping, rd_data, rd_ping, rd_pong; +static dds_entity_t sub, pub, wr_data, wr_ping, wr_stat, rd_data, rd_ping, rd_pong, rd_stat; /* Number of different key values to use (must be 1 for OU type) */ static unsigned nkeyvals = 1; /* Topic type to use */ -static enum topicsel topicsel = OU; +static enum topicsel topicsel = KS; /* Data and ping/pong subscriber triggering modes */ static enum submode submode = SM_LISTENER; static enum submode pingpongmode = SM_LISTENER; /* Size of the sequence in KeyedSeq type in bytes */ -static unsigned baggagesize = 0; +static uint32_t baggagesize = 0; /* Whether or not to register instances prior to writing */ static bool register_instances = true; @@ -110,7 +118,7 @@ static uint32_t matchcount = 0; static uint32_t matchtimeout = 0; /* Data is published in bursts of this many samples */ -static unsigned burstsize = 1; +static uint32_t burstsize = 1; /* Whether to use reliable or best-effort readers/writers */ static bool reliable = true; @@ -122,7 +130,7 @@ static int32_t histdepth = 0; /* Publishing rate in Hz, HUGE_VAL means as fast as possible, 0 means no throughput data is published at all */ -static double rate; +static double pub_rate; /* Fraction of throughput data samples that double as a ping message */ @@ -137,6 +145,10 @@ static dds_ignorelocal_kind_t ignorelocal = DDS_IGNORELOCAL_PARTICIPANT; possible, DDS_INFINITY means never */ static dds_duration_t ping_intv; +/* Number of times a new ping was sent before all expected + pongs had been received */ +static uint32_t ping_timeouts = 0; + static ddsrt_mutex_t disc_lock; /* Publisher statistics and lock protecting it */ @@ -481,7 +493,7 @@ static void hist_print (const char *prefix, struct hist *h, dds_time_t dt, int r hist_reset (h); } -static void *make_baggage (dds_sequence_t *b, unsigned cnt) +static void *make_baggage (dds_sequence_t *b, uint32_t cnt) { b->_maximum = b->_length = cnt; if (cnt == 0) @@ -549,8 +561,8 @@ static uint32_t pubthread (void *varg) tfirst0 = tfirst = dds_time(); - unsigned bi = 0; - while (!termflag) + uint32_t bi = 0; + while (!ddsrt_atomic_ld32 (&termflag)) { /* lsb of timestamp is abused to signal whether the sample is a ping requiring a response or not */ bool reqresp = (ping_frac == 0) ? 0 : (ping_frac == UINT32_MAX) ? 1 : (ddsrt_random () <= ping_frac); @@ -559,7 +571,7 @@ static uint32_t pubthread (void *varg) { printf ("write error: %d\n", result); fflush (stdout); - if (dds_err_nr (result) != DDS_RETCODE_TIMEOUT) + if (result != DDS_RETCODE_TIMEOUT) exit (2); timeouts++; /* retry with original timestamp, it really is just a way of reporting @@ -581,12 +593,12 @@ static uint32_t pubthread (void *varg) data.seq_keyval.keyval = (data.seq_keyval.keyval + 1) % (int32_t) nkeyvals; data.seq++; - if (rate < HUGE_VAL) + if (pub_rate < HUGE_VAL) { if (++bi == burstsize) { /* FIXME: should average rate over a short-ish period, rather than over the entire run */ - while (((double) (ntot / burstsize) / ((double) (t - tfirst0) / 1e9 + 5e-3)) > rate && !termflag) + while (((double) (ntot / burstsize) / ((double) (t - tfirst0) / 1e9 + 5e-3)) > pub_rate && !ddsrt_atomic_ld32 (&termflag)) { /* FIXME: flushing manually because batching is not yet implemented properly */ dds_write_flush (wr_data); @@ -690,9 +702,15 @@ static bool update_roundtrip (dds_instance_handle_t pubhandle, uint64_t tdelta, bool allseen; ddsrt_mutex_lock (&pongstat_lock); if (isping && seq == cur_ping_seq) + { + ddsrt_mutex_lock (&pongwr_lock); allseen = (++n_pong_seen == n_pong_expected); + ddsrt_mutex_unlock (&pongwr_lock); + } else + { allseen = false; + } for (uint32_t i = 0; i < npongstat; i++) if (pongstat[i].pubhandle == pubhandle) { @@ -741,7 +759,6 @@ static dds_entity_t get_pong_writer_locked (dds_instance_handle_t pubhandle) if (pongwr[i].pubhandle == 0) { pongwr[i].pubhandle = pubhandle; - ddsrt_mutex_unlock (&pongwr_lock); return wr_pong; } else @@ -751,7 +768,6 @@ static dds_entity_t get_pong_writer_locked (dds_instance_handle_t pubhandle) pongwr[npongwr].pphandle = pphandle; pongwr[npongwr].wr_pong = wr_pong; npongwr++; - ddsrt_mutex_unlock (&pongwr_lock); return wr_pong; } } @@ -770,6 +786,19 @@ static dds_entity_t get_pong_writer (dds_instance_handle_t pubhandle) return wr_pong; } +static uint32_t topic_payload_size (enum topicsel tp, uint32_t bgsize) +{ + uint32_t size = 0; + switch (tp) + { + case KS: size = 12 + bgsize; break; + case K32: size = 32; break; + case K256: size = 256; break; + case OU: size = 4; break; + } + return size; +} + static bool process_data (dds_entity_t rd, struct subthread_arg *arg) { uint32_t max_samples = arg->max_samples; @@ -785,10 +814,13 @@ static bool process_data (dds_entity_t rd, struct subthread_arg *arg) uint32_t seq = 0, keyval = 0, size = 0; switch (topicsel) { - case KS: { KeyedSeq *d = (KeyedSeq *) mseq[i]; keyval = d->keyval; seq = d->seq; size = 12 + d->baggage._length; } break; - case K32: { Keyed32 *d = (Keyed32 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = 32; } break; - case K256: { Keyed256 *d = (Keyed256 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = 256; } break; - case OU: { OneULong *d = (OneULong *) mseq[i]; keyval = 0; seq = d->seq; size = 4; } break; + case KS: { + KeyedSeq *d = (KeyedSeq *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, d->baggage._length); + break; + } + case K32: { Keyed32 *d = (Keyed32 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break; + case K256: { Keyed256 *d = (Keyed256 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break; + case OU: { OneULong *d = (OneULong *) mseq[i]; keyval = 0; seq = d->seq; size = topic_payload_size (topicsel, 0); } break; } (void) check_eseq (&eseq_admin, seq, keyval, size, iseq[i].publication_handle); if (iseq[i].source_timestamp & 1) @@ -797,7 +829,7 @@ static bool process_data (dds_entity_t rd, struct subthread_arg *arg) if ((wr_pong = get_pong_writer (iseq[i].publication_handle)) != 0) { dds_return_t rc; - if ((rc = dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp - 1)) < 0 && dds_err_nr(rc) != DDS_RETCODE_TIMEOUT) + if ((rc = dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp - 1)) < 0 && rc != DDS_RETCODE_TIMEOUT) error2 ("dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp): %d\n", (int) rc); dds_write_flush (wr_pong); } @@ -825,7 +857,7 @@ static bool process_ping (dds_entity_t rd, struct subthread_arg *arg) if ((wr_pong = get_pong_writer (iseq[i].publication_handle)) != 0) { dds_return_t rc; - if ((rc = dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp | 1)) < 0 && dds_err_nr(rc) != DDS_RETCODE_TIMEOUT) + if ((rc = dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp | 1)) < 0 && rc != DDS_RETCODE_TIMEOUT) error2 ("dds_write_ts (wr_pong, mseq[i], iseq[i].source_timestamp): %d\n", (int) rc); dds_write_flush (wr_pong); } @@ -860,7 +892,7 @@ static bool process_pong (dds_entity_t rd, struct subthread_arg *arg) cur_ping_time = dds_time (); cur_ping_seq = ++(*seq); ddsrt_mutex_unlock (&pongwr_lock); - if ((rc = dds_write_ts (wr_ping, mseq[i], dds_time () | 1)) < 0 && dds_err_nr(rc) != DDS_RETCODE_TIMEOUT) + if ((rc = dds_write_ts (wr_ping, mseq[i], dds_time () | 1)) < 0 && rc != DDS_RETCODE_TIMEOUT) error2 ("dds_write (wr_ping, mseq[i]): %d\n", (int) rc); dds_write_flush (wr_ping); } @@ -884,23 +916,36 @@ static void maybe_send_new_ping (dds_time_t tnow, dds_time_t *tnextping) } else { - if (tnow > twarn_ping_timeout) + if (n_pong_seen < n_pong_expected) { - printf ("[%"PRIdPID"] ping timed out ... sending new ping\n", ddsrt_getpid ()); - fflush (stdout); + ping_timeouts++; + if (tnow > twarn_ping_timeout) + { + printf ("[%"PRIdPID"] ping timed out (total %"PRIu32" times) ... sending new ping\n", ddsrt_getpid (), ping_timeouts); + twarn_ping_timeout = tnow + DDS_SECS (1); + fflush (stdout); + } } n_pong_seen = 0; - cur_ping_time = tnow; - if (ping_intv > 0) + if (ping_intv == 0) + { + *tnextping = tnow + DDS_SECS (1); + cur_ping_time = tnow; + } + else + { + /* tnow should be ~ cur_ping_time + ping_intv, but it won't be if the + wakeup was delayed significantly, the machine was suspended in the + meantime, so slow down if we can't keep up */ + cur_ping_time += ping_intv; + if (cur_ping_time < tnow - ping_intv / 2) + cur_ping_time = tnow; *tnextping = cur_ping_time + ping_intv; - else if (ping_intv == 0) - *tnextping = cur_ping_time + DDS_SECS (1); - if (ping_intv > 0 && *tnextping > twarn_ping_timeout) - twarn_ping_timeout = *tnextping + ping_intv / 2; + } cur_ping_seq++; baggage = init_sample (&data, cur_ping_seq); ddsrt_mutex_unlock (&pongwr_lock); - if ((rc = dds_write_ts (wr_ping, &data, dds_time () | 1)) < 0 && dds_err_nr (rc) != DDS_RETCODE_TIMEOUT) + if ((rc = dds_write_ts (wr_ping, &data, dds_time () | 1)) < 0 && rc != DDS_RETCODE_TIMEOUT) error2 ("send_new_ping: dds_write (wr_ping, &data): %d\n", (int) rc); dds_write_flush (wr_ping); if (baggage) @@ -920,7 +965,7 @@ static uint32_t subthread_waitset (void *varg) error2 ("dds_set_status_mask (rd_data, DDS_DATA_AVAILABLE_STATUS): %d\n", (int) rc); if ((rc = dds_waitset_attach (ws, rd_data, 1)) < 0) error2 ("dds_waitset_attach (ws, rd_data, 1): %d\n", (int) rc); - while (!termflag) + while (!ddsrt_atomic_ld32 (&termflag)) { if (!process_data (rd_data, arg)) { @@ -946,7 +991,7 @@ static uint32_t subpingthread_waitset (void *varg) error2 ("dds_set_status_mask (rd_ping, DDS_DATA_AVAILABLE_STATUS): %d\n", (int) rc); if ((rc = dds_waitset_attach (ws, rd_ping, 1)) < 0) error2 ("dds_waitset_attach (ws, rd_ping, 1): %d\n", (int) rc); - while (!termflag) + while (!ddsrt_atomic_ld32 (&termflag)) { int32_t nxs; if ((nxs = dds_waitset_wait (ws, NULL, 0, DDS_INFINITY)) < 0) @@ -968,7 +1013,7 @@ static uint32_t subpongthread_waitset (void *varg) error2 ("dds_set_status_mask (rd_pong, DDS_DATA_AVAILABLE_STATUS): %d\n", (int) rc); if ((rc = dds_waitset_attach (ws, rd_pong, 1)) < 0) error2 ("dds_waitset_attach (ws, rd_pong, 1): %d\n", (int) rc); - while (!termflag) + while (!ddsrt_atomic_ld32 (&termflag)) { int32_t nxs; if ((nxs = dds_waitset_wait (ws, NULL, 0, DDS_INFINITY)) < 0) @@ -981,7 +1026,7 @@ static uint32_t subpongthread_waitset (void *varg) static uint32_t subthread_polling (void *varg) { struct subthread_arg * const arg = varg; - while (!termflag) + while (!ddsrt_atomic_ld32 (&termflag)) { if (!process_data (rd_data, arg)) dds_sleepfor (DDS_MSECS (1)); @@ -1052,7 +1097,7 @@ static void delete_pong_writer (dds_instance_handle_t pphandle) else { assert (wr_pong == 0 || wr_pong == pongwr[i].wr_pong); - memmove (&pongwr[i], &pongwr[i+1], (npongwr - i) * sizeof (pongwr[0])); + memmove (&pongwr[i], &pongwr[i+1], (npongwr - i - 1) * sizeof (pongwr[0])); npongwr--; } } @@ -1061,6 +1106,13 @@ static void delete_pong_writer (dds_instance_handle_t pphandle) dds_delete (wr_pong); } +static void free_ppant (void *vpp) +{ + struct ppant *pp = vpp; + free (pp->hostname); + free (pp); +} + static void participant_data_listener (dds_entity_t rd, void *arg) { dds_sample_info_t info; @@ -1090,7 +1142,7 @@ static void participant_data_listener (dds_entity_t rd, void *arg) ddsrt_avl_delete_dpath (&ppants_td, &ppants, pp, &dpath); if (pp->tdeadline != DDS_NEVER) ddsrt_fibheap_delete (&ppants_to_match_fhd, &ppants_to_match, pp); - free (pp); + free_ppant (pp); } ddsrt_mutex_unlock (&disc_lock); } @@ -1151,14 +1203,14 @@ static void participant_data_listener (dds_entity_t rd, void *arg) if (n_pong_expected_delta) { - ddsrt_mutex_lock (&pongstat_lock); + ddsrt_mutex_lock (&pongwr_lock); n_pong_expected += n_pong_expected_delta; /* potential initial packet loss & lazy writer creation conspire against receiving the expected number of responses, so allow for a few attempts before starting to warn about timeouts */ twarn_ping_timeout = dds_time () + DDS_MSECS (3333); //printf ("[%"PRIdPID"] n_pong_expected = %u\n", ddsrt_getpid (), n_pong_expected); - ddsrt_mutex_unlock (&pongstat_lock); + ddsrt_mutex_unlock (&pongwr_lock); } } @@ -1281,29 +1333,32 @@ static int cmp_uint64 (const void *va, const void *vb) return (*a == *b) ? 0 : (*a < *b) ? -1 : 1; } -static void print_stats (dds_time_t tstart, dds_time_t tnow, dds_time_t tprev) +static void print_stats (dds_time_t tref, dds_time_t tnow, dds_time_t tprev, struct record_cputime_state *cputime_state, struct record_netload_state *netload_state) { char prefix[128]; - const double ts = (double) (tnow - tstart) / 1e9; + const double ts = (double) (tnow - tref) / 1e9; + bool output = false; snprintf (prefix, sizeof (prefix), "[%"PRIdPID"] %.3f ", ddsrt_getpid (), ts); - if (rate > 0) + if (pub_rate > 0) { ddsrt_mutex_lock (&pubstat_lock); hist_print (prefix, pubstat_hist, tnow - tprev, 1); ddsrt_mutex_unlock (&pubstat_lock); + output = true; } if (submode != SM_NONE) { struct eseq_admin * const ea = &eseq_admin; - uint64_t tot_nrecv = 0, nrecv = 0, nrecv_bytes = 0, nlost = 0; + uint64_t tot_nrecv = 0, tot_nlost = 0, nrecv = 0, nrecv_bytes = 0, nlost = 0; uint32_t last_size = 0; ddsrt_mutex_lock (&ea->lock); for (uint32_t i = 0; i < ea->nph; i++) { struct eseq_stat * const x = &ea->stats[i]; tot_nrecv += x->nrecv; + tot_nlost += x->nlost; nrecv += x->nrecv - x->nrecv_ref; nlost += x->nlost - x->nlost_ref; nrecv_bytes += x->nrecv_bytes - x->nrecv_bytes_ref; @@ -1316,8 +1371,11 @@ static void print_stats (dds_time_t tstart, dds_time_t tnow, dds_time_t tprev) if (nrecv > 0) { - printf ("%s size %"PRIu32" ntot %"PRIu64" delta: %"PRIu64" lost %"PRIu64" rate %.2f Mb/s\n", - prefix, last_size, tot_nrecv, nrecv, nlost, (double) nrecv_bytes * 8 * 1e3 / (double) (tnow - tprev)); + const double dt = (double) (tnow - tprev); + printf ("%s size %"PRIu32" total %"PRIu64" lost %"PRIu64" delta %"PRIu64" lost %"PRIu64" rate %.2f kS/s %.2f Mb/s\n", + prefix, last_size, tot_nrecv, tot_nlost, nrecv, nlost, + (double) nrecv * 1e6 / dt, (double) nrecv_bytes * 8 * 1e3 / dt); + output = true; } } @@ -1347,8 +1405,8 @@ static void print_stats (dds_time_t tstart, dds_time_t tnow, dds_time_t tprev) ddsrt_mutex_unlock (&disc_lock); qsort (y.raw, rawcnt, sizeof (*y.raw), cmp_uint64); - printf ("%s %s mean %.3fus min %.3fus 50%% %.3fus 90%% %.3fus 99%% %.3fus max %.3fus cnt %"PRIu32"\n", - prefix, ppinfo, + printf ("%s %s size %"PRIu32" mean %.3fus min %.3fus 50%% %.3fus 90%% %.3fus 99%% %.3fus max %.3fus cnt %"PRIu32"\n", + prefix, ppinfo, topic_payload_size (topicsel, baggagesize), (double) y.sum / (double) y.cnt / 1e3, (double) y.min / 1e3, (double) y.raw[rawcnt - (rawcnt + 1) / 2] / 1e3, @@ -1356,6 +1414,7 @@ static void print_stats (dds_time_t tstart, dds_time_t tnow, dds_time_t tprev) (double) y.raw[rawcnt - (rawcnt + 99) / 100] / 1e3, (double) y.max / 1e3, y.cnt); + output = true; } newraw = y.raw; @@ -1363,6 +1422,42 @@ static void print_stats (dds_time_t tstart, dds_time_t tnow, dds_time_t tprev) } ddsrt_mutex_unlock (&pongstat_lock); free (newraw); + + if (record_cputime (cputime_state, prefix, tnow)) + output = true; + + if (rd_stat) + { +#define MAXS 40 /* 40 participants is enough for everyone! */ + void *raw[MAXS]; + dds_sample_info_t si[MAXS]; + int32_t n; + /* Read everything using a keep-last-1 reader: effectively latching the + most recent value. While not entirely correct, the nature of the process + is such that things should be stable, and this allows printing the stats + always in the same way despite the absence of synchronization. */ + raw[0] = NULL; + if ((n = dds_take_mask (rd_stat, raw, si, MAXS, MAXS, DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE | DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE)) > 0) + { + for (int32_t i = 0; i < n; i++) + if (si[i].valid_data && si[i].sample_state == DDS_SST_NOT_READ) + if (print_cputime (raw[i], prefix, true, true)) + output = true; + dds_return_loan (rd_stat, raw, n); + } + if ((n = dds_read (rd_stat, raw, si, MAXS, MAXS)) > 0) + { + for (int32_t i = 0; i < n; i++) + if (si[i].valid_data) + if (print_cputime (raw[i], prefix, true, si[i].sample_state == DDS_SST_NOT_READ)) + output = true; + dds_return_loan (rd_stat, raw, n); + } +#undef MAXS + } + + if (output) + record_netload (netload_state, prefix, tnow); fflush (stdout); } @@ -1383,14 +1478,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; + ddsrt_atomic_st32 (&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; @@ -1401,6 +1498,23 @@ static uint32_t sigthread (void *varg) error2 ("sigwait failed: %d\n", errno); return 0; } + +#if defined __APPLE__ || defined __linux +static void sigxfsz_handler (int sig __attribute__ ((unused))) +{ + static const char msg[] = "file size limit reached\n"; + static ddsrt_atomic_uint32_t seen = DDSRT_ATOMIC_UINT32_INIT (0); + if (!ddsrt_atomic_or32_ov (&seen, 1)) + { + dds_time_t tnow = dds_time (); + if (write (2, msg, sizeof (msg) - 1) < 0) { + /* may not ignore return value according to Linux/gcc */ + } + print_stats (0, tnow, tnow - DDS_SECS (1), NULL, NULL); + kill (getpid (), 9); + } +} +#endif #endif /******************** @@ -1410,29 +1524,37 @@ static uint32_t sigthread (void *varg) static void usage (void) { printf ("\ -%s help\n\ +%s help (this text)\n\ +%s sanity (ping 1Hz)\n\ %s [OPTIONS] MODE...\n\ \n\ OPTIONS:\n\ - -T KS|K32|K256|OU topic:\n\ + -L allow matching with endpoints in the same process\n\ + to get throughput/latency in the same ddsperf process\n\ + -T KS|K32|K256|OU topic (KS is default):\n\ KS seq num, key value, sequence-of-octets\n\ K32 seq num, key value, array of 24 octets\n\ K256 seq num, key value, array of 248 octets\n\ OU seq num\n\ - -L allow matching with local endpoints\n\ + -n N number of key values to use for data (only for\n\ + topics with a key value)\n\ -u best-effort instead of reliable\n\ -k all|N keep-all or keep-last-N for data (ping/pong is\n\ always keep-last-1)\n\ - -n N number of key values to use for data (only for\n\ - topics with a key value)\n\ + -c subscribe to CPU stats from peers and show them\n\ + -d DEV:BW report network load for device DEV with nominal\n\ + bandwidth BW in bits/s (e.g., eth0:1e9)\n\ -D DUR run for at most DUR seconds\n\ -N COUNT require at least COUNT matching participants\n\ -M DUR require those participants to match within DUR seconds\n\ + -R TREF timestamps in the output relative to TREF instead of\n\ + process start\n\ + -i ID use domain ID instead of the default domain\n\ \n\ MODE... is zero or more of:\n\ - ping [R[Hz]] [waitset|listener]\n\ + ping [R[Hz]] [size S] [waitset|listener]\n\ Send a ping upon receiving all expected pongs, or send a ping at\n\ - rate R (optionally suffixed with Hz). The triggering mode is either\n\ + rate R (optionally suffixed with Hz/kHz). The triggering mode is either\n\ a listener (default, unless -L has been specified) or a waitset.\n\ pong [waitset|listener]\n\ A \"dummy\" mode that serves two purposes: configuring the triggering.\n\ @@ -1441,17 +1563,38 @@ MODE... is zero or more of:\n\ sub [waitset|listener|polling]\n\ Subscribe to data, with calls to take occurring either in a listener\n\ (default), when a waitset is triggered, or by polling at 1kHz.\n\ - pub [R[Hz]] [burst N] [[ping] X%%]\n\ - Publish bursts of data at rate R, optionally suffixed with Hz. If\n\ + pub [R[Hz]] [size S] [burst N] [[ping] X%%]\n\ + Publish bursts of data at rate R, optionally suffixed with Hz/kHz. If\n\ no rate is given or R is \"inf\", data is published as fast as\n\ possible. Each burst is a single sample by default, but can be set\n\ - to larger value using \"burst N\".\n\ + to larger value using \"burst N\". Sample size is controlled using\n\ + \"size S\", S may be suffixed with k/M/kB/MB/KiB/MiB.\n\ If desired, a fraction of the samples can be treated as if it were a\n\ ping, for this, specify a percentage either as \"ping X%%\" (the\n\ \"ping\" keyword is optional, the %% sign is not).\n\ \n\ -If no MODE specified, it defaults to a 1Hz ping + responding to any pings.\n\ -", argv0, argv0); + Payload size (including fixed part of topic) may be set as part of a\n\ + \"ping\" or \"pub\" specification for topic KS (there is only size,\n\ + the last one given determines it for all) and should be either 0 (minimal,\n\ + equivalent to 12) or >= 12.\n\ +\n\ +EXIT STATUS:\n\ +\n\ + 0 all is well\n\ + 1 not enough peers discovered, other matching issues, unexpected sample\n\ + loss detected\n\ + 2 unexpected failure of some DDS operation\n\ + 3 incorrect arguments\n\ +\n\ +EXAMPLES:\n\ + ddsperf pub size 1k & ddsperf sub\n\ + basic throughput test with 1024-bytes large samples\n\ + ddsperf ping & ddsperf pong\n\ + basic latency test\n\ + ddsperf -L -TOU -D10 pub sub\n\ + basic throughput test within the process with tiny, keyless samples,\n\ + running for 10s\n\ +", argv0, argv0, argv0); fflush (stdout); exit (3); } @@ -1481,7 +1624,7 @@ static int exact_string_int_map_lookup (const struct string_int_map_elem *elems, if (strcmp (elems[i].name, str) == 0) return elems[i].value; if (notfound_error) - error3 ("%s: undefined %s", str, label); + error3 ("%s: undefined %s\n", str, label); return -1; } @@ -1503,30 +1646,92 @@ static int string_int_map_lookup (const struct string_int_map_elem *elems, const } } if (ambiguous) - error3 ("%s: ambiguous %sspecification", str, label); + error3 ("%s: ambiguous %sspecification\n", str, label); if (match == SIZE_MAX && notfound_error) - error3 ("%s: undefined %s", str, label); + error3 ("%s: undefined %s\n", str, label); return (match == SIZE_MAX) ? -1 : elems[match].value; } +struct multiplier { + const char *suffix; + int mult; +}; + +static const struct multiplier frequency_units[] = { + { "Hz", 1 }, + { "kHz", 1024 }, + { NULL, 0 } +}; + +static const struct multiplier size_units[] = { + { "B", 1 }, + { "k", 1024 }, + { "M", 1048576 }, + { "kB", 1024 }, + { "KiB", 1024 }, + { "MB", 1048576 }, + { "MiB", 1048576 }, + { NULL, 0 } +}; + +static int lookup_multiplier (const struct multiplier *units, const char *suffix) +{ + while (*suffix == ' ') + suffix++; + if (*suffix == 0) + return 1; + else if (units == NULL) + return 0; + else + { + for (size_t i = 0; units[i].suffix; i++) + if (strcmp (units[i].suffix, suffix) == 0) + return units[i].mult; + return 0; + } +} + +static bool set_simple_uint32 (int *xoptind, int xargc, char * const xargv[], const char *token, const struct multiplier *units, uint32_t *val) +{ + if (strcmp (xargv[*xoptind], token) != 0) + return false; + else + { + unsigned x; + int pos, mult; + if (++(*xoptind) == xargc) + error3 ("argument missing in %s specification\n", token); + if (sscanf (xargv[*xoptind], "%u%n", &x, &pos) == 1 && (mult = lookup_multiplier (units, xargv[*xoptind] + pos)) > 0) + *val = x * (unsigned) mult; + else + error3 ("%s: invalid %s specification\n", xargv[*xoptind], token); + return true; + } +} + static void set_mode_ping (int *xoptind, int xargc, char * const xargv[]) { ping_intv = 0; pingpongmode = SM_LISTENER; while (*xoptind < xargc && exact_string_int_map_lookup (modestrings, "mode string", xargv[*xoptind], false) == -1) { - int pos; - double r; - if (strcmp (xargv[*xoptind], "inf") == 0) + int pos = 0, mult = 1; + double ping_rate; + if (strcmp (xargv[*xoptind], "inf") == 0 && lookup_multiplier (frequency_units, xargv[*xoptind] + 3) > 0) { ping_intv = 0; } - else if (sscanf (xargv[*xoptind], "%lf%n", &r, &pos) == 1 && (xargv[*xoptind][pos] == 0 || strcmp (xargv[*xoptind] + pos, "Hz") == 0)) + else if (sscanf (xargv[*xoptind], "%lf%n", &ping_rate, &pos) == 1 && (mult = lookup_multiplier (frequency_units, xargv[*xoptind] + pos)) > 0) { - if (r == 0) ping_intv = DDS_INFINITY; - else if (r > 0) ping_intv = (dds_duration_t) (1e9 / rate + 0.5); + ping_rate *= mult; + if (ping_rate == 0) ping_intv = DDS_INFINITY; + else if (ping_rate > 0) ping_intv = (dds_duration_t) (1e9 / ping_rate + 0.5); else error3 ("%s: invalid ping rate\n", xargv[*xoptind]); } + else if (set_simple_uint32 (xoptind, xargc, xargv, "size", size_units, &baggagesize)) + { + /* no further work needed */ + } else { pingpongmode = (enum submode) string_int_map_lookup (pingpongmodes, "ping mode", xargv[*xoptind], true); @@ -1563,38 +1768,36 @@ static void set_mode_sub (int *xoptind, int xargc, char * const xargv[]) static void set_mode_pub (int *xoptind, int xargc, char * const xargv[]) { - rate = HUGE_VAL; + pub_rate = HUGE_VAL; burstsize = 1; ping_frac = 0; while (*xoptind < xargc && exact_string_int_map_lookup (modestrings, "mode string", xargv[*xoptind], false) == -1) { - int pos = 0; + int pos = 0, mult = 1; double r; - if (strcmp (xargv[*xoptind], "inf") == 0 || strcmp (xargv[*xoptind], "infHz") == 0) + if (strncmp (xargv[*xoptind], "inf", 3) == 0 && lookup_multiplier (frequency_units, xargv[*xoptind] + 3) > 0) { - rate = HUGE_VAL; + pub_rate = HUGE_VAL; } - else if (sscanf (xargv[*xoptind], "%lf%n", &r, &pos) == 1 && (xargv[*xoptind][pos] == 0 || strcmp (xargv[*xoptind] + pos, "Hz") == 0)) + else if (sscanf (xargv[*xoptind], "%lf%n", &r, &pos) == 1 && (mult = lookup_multiplier (frequency_units, xargv[*xoptind] + pos)) > 0) { if (r < 0) error3 ("%s: invalid publish rate\n", xargv[*xoptind]); - rate = r; + pub_rate = r * mult; } - else if (strcmp (xargv[*xoptind], "burst") == 0) + else if (set_simple_uint32 (xoptind, xargc, xargv, "burst", NULL, &burstsize)) { - unsigned b; - if (++(*xoptind) == xargc) - error3 ("argument missing in burst size specification\n"); - if (sscanf (xargv[*xoptind], "%u%n", &b, &pos) == 1 && xargv[*xoptind][pos] == 0) - burstsize = b; - else - error3 ("%s: invalid burst size specification\n", xargv[*xoptind]); + /* no further work needed */ + } + else if (set_simple_uint32 (xoptind, xargc, xargv, "size", size_units, &baggagesize)) + { + /* no further work needed */ } else if (sscanf (xargv[*xoptind], "%lf%n", &r, &pos) == 1 && strcmp (xargv[*xoptind] + pos, "%") == 0) { if (r < 0 || r > 100) error3 ("%s: ping fraction out of range\n", xargv[*xoptind]); ping_frac = (uint32_t) (UINT32_MAX * (r / 100.0) + 0.5); } - else if (strcmp (xargv[*xoptind], "ping") == 0 && *xoptind + 1 < xargc && sscanf (xargv[*xoptind + 1], "%lf%%%n", &rate, &pos) == 1 && xargv[*xoptind + 1][pos] == 0) + else if (strcmp (xargv[*xoptind], "ping") == 0 && *xoptind + 1 < xargc && sscanf (xargv[*xoptind + 1], "%lf%%%n", &pub_rate, &pos) == 1 && xargv[*xoptind + 1][pos] == 0) { ++(*xoptind); if (r < 0 || r > 100) error3 ("%s: ping fraction out of range\n", xargv[*xoptind]); @@ -1611,10 +1814,10 @@ static void set_mode_pub (int *xoptind, int xargc, char * const xargv[]) static void set_mode (int xoptind, int xargc, char * const xargv[]) { int code; - rate = 0.0; + pub_rate = 0.0; submode = SM_NONE; pingpongmode = SM_LISTENER; - ping_intv = (xoptind == xargc) ? DDS_SECS (1) : DDS_INFINITY; + ping_intv = DDS_INFINITY; ping_frac = 0; while (xoptind < xargc && (code = exact_string_int_map_lookup (modestrings, "mode string", xargv[xoptind], true)) != -1) { @@ -1640,28 +1843,42 @@ int main (int argc, char *argv[]) dds_qos_t *qos; dds_listener_t *listener; int opt; + bool collect_stats = false; + dds_time_t tref = DDS_INFINITY; 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 + char netload_if[256]; + double netload_bw = 0; ddsrt_threadattr_init (&attr); argv0 = argv[0]; - if (argc == 2 && strcmp (argv[1], "help") == 0) - usage (); - while ((opt = getopt (argc, argv, "D:n:z:k:uLT:M:N:h")) != EOF) + while ((opt = getopt (argc, argv, "cd:D:i:n:k:uLK:T:M:N:R:h")) != EOF) { switch (opt) { + case 'c': collect_stats = true; break; + case 'd': { + char *col; + int pos; + ddsrt_strlcpy (netload_if, optarg, sizeof (netload_if)); + if ((col = strrchr (netload_if, ':')) == NULL || col == netload_if || + (sscanf (col+1, "%lf%n", &netload_bw, &pos) != 1 || (col+1)[pos] != 0)) + error3 ("-d%s: expected DEVICE:BANDWIDTH\n", optarg); + *col = 0; + break; + } case 'D': dur = atof (optarg); if (dur <= 0) dur = HUGE_VAL; break; + case 'i': did = (dds_domainid_t) atoi (optarg); break; case 'n': nkeyvals = (unsigned) atoi (optarg); break; case 'u': reliable = false; break; case 'k': histdepth = atoi (optarg); if (histdepth < 0) histdepth = 0; break; case 'L': ignorelocal = DDS_IGNORELOCAL_NONE; break; - case 'T': + case 'T': case 'K': /* 'K' because of my muscle memory with pubsub ... */ if (strcmp (optarg, "KS") == 0) topicsel = KS; else if (strcmp (optarg, "K32") == 0) topicsel = K32; else if (strcmp (optarg, "K256") == 0) topicsel = K256; @@ -1670,24 +1887,41 @@ int main (int argc, char *argv[]) break; case 'M': maxwait = atof (optarg); if (maxwait <= 0) maxwait = HUGE_VAL; break; case 'N': minmatch = (unsigned) atoi (optarg); break; - case 'z': baggagesize = (unsigned) atoi (optarg); break; + case 'R': tref = 0; sscanf (optarg, "%"SCNd64, &tref); break; case 'h': usage (); break; default: error3 ("-%c: unknown option\n", opt); break; } } - set_mode (optind, argc, argv); + + if (optind == argc || (optind + 1 == argc && strcmp (argv[optind], "help") == 0)) + usage (); + else if (optind + 1 == argc && strcmp (argv[optind], "sanity") == 0) + { + char * const sanity[] = { "ping", "1Hz" }; + set_mode (0, 2, sanity); + } + else + { + set_mode (optind, argc, argv); + } if (nkeyvals == 0) nkeyvals = 1; if (topicsel == OU && nkeyvals != 1) error3 ("-n%u invalid: topic OU has no key\n", nkeyvals); if (topicsel != KS && baggagesize != 0) - error3 ("-z%u invalid: only topic KS has a sequence\n", baggagesize); + error3 ("size %"PRIu32" invalid: only topic KS has a sequence\n", baggagesize); if (baggagesize != 0 && baggagesize < 12) - error3 ("-z%u invalid: too small to allow for overhead\n", baggagesize); + error3 ("size %"PRIu32" invalid: too small to allow for overhead\n", baggagesize); else if (baggagesize > 0) baggagesize -= 12; + struct record_netload_state *netload_state; + if (netload_bw <= 0) + netload_state = NULL; + else if ((netload_state = record_netload_new (netload_if, netload_bw)) == NULL) + error3 ("can't get network utilization information for device %s\n", netload_if); + ddsrt_avl_init (&ppants_td, &ppants); ddsrt_fibheap_init (&ppants_to_match_fhd, &ppants_to_match); @@ -1700,7 +1934,7 @@ int main (int argc, char *argv[]) qos = dds_create_qos (); /* set user data: magic cookie, whether we have a reader for the Data topic - (all other endpoints always exist), and our hostname */ + (all other endpoints always exist), pid and hostname */ { unsigned pos; char udata[256]; @@ -1725,6 +1959,12 @@ int main (int argc, char *argv[]) error2 ("dds_create_publisher failed: %d\n", (int) dp); dds_delete_qos (qos); + qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_MSECS (100)); + if ((tp_stat = dds_create_topic (dp, &CPUStats_desc, "DDSPerfCPUStats", qos, NULL)) < 0) + error2 ("dds_create_topic(%s) failed: %d\n", "DDSPerfCPUStats", (int) tp_stat); + dds_delete_qos (qos); + { const char *tp_suf = ""; const dds_topic_descriptor_t *tp_desc = NULL; @@ -1762,6 +2002,19 @@ int main (int argc, char *argv[]) if ((rd_publications = dds_create_reader (dp, DDS_BUILTIN_TOPIC_DCPSPUBLICATION, NULL, NULL)) < 0) error2 ("dds_create_reader(publications) failed: %d\n", (int) rd_publications); + /* stats writer always exists, reader only when we were requested to collect & print stats */ + qos = dds_create_qos (); + dds_qset_history (qos, DDS_HISTORY_KEEP_LAST, 1); + dds_qset_ignorelocal (qos, DDS_IGNORELOCAL_PARTICIPANT); + if ((wr_stat = dds_create_writer (pub, tp_stat, qos, NULL)) < 0) + error2 ("dds_create_writer(statistics) failed: %d\n", (int) wr_stat); + if (collect_stats) + { + if ((rd_stat = dds_create_reader (sub, tp_stat, qos, NULL)) < 0) + error2 ("dds_create_reader(statistics) failed: %d\n", (int) rd_stat); + } + dds_delete_qos (qos); + /* ping reader/writer uses keep-last-1 history; not checking matching on these (yet) */ qos = dds_create_qos (); dds_qset_history (qos, DDS_HISTORY_KEEP_LAST, 1); @@ -1841,12 +2094,15 @@ 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); sigprocmask (SIG_BLOCK, &sigset, &osigset); ddsrt_thread_create (&sigtid, "sigthread", &attr, sigthread, &sigset); +#if defined __APPLE__ || defined __linux + signal (SIGXFSZ, sigxfsz_handler); +#endif #endif /* Make publisher & subscriber thread arguments and start the threads we @@ -1854,7 +2110,7 @@ int main (int argc, char *argv[]) have a reader or will never really be receiving data) */ struct subthread_arg subarg_data, subarg_ping, subarg_pong; init_eseq_admin (&eseq_admin, nkeyvals); - subthread_arg_init (&subarg_data, rd_data, 100); + subthread_arg_init (&subarg_data, rd_data, 1000); subthread_arg_init (&subarg_ping, rd_ping, 100); subthread_arg_init (&subarg_pong, rd_pong, 100); uint32_t (*subthread_func) (void *arg) = 0; @@ -1869,7 +2125,7 @@ int main (int argc, char *argv[]) memset (&subtid, 0, sizeof (subtid)); memset (&subpingtid, 0, sizeof (subpingtid)); memset (&subpongtid, 0, sizeof (subpongtid)); - if (rate > 0) + if (pub_rate > 0) ddsrt_thread_create (&pubtid, "pub", &attr, pubthread, NULL); if (subthread_func != 0) ddsrt_thread_create (&subtid, "sub", &attr, subthread_func, &subarg_data); @@ -1885,8 +2141,8 @@ int main (int argc, char *argv[]) const bool pingpong_waitset = (ping_intv != DDS_NEVER && ignorelocal == DDS_IGNORELOCAL_NONE) || pingpongmode == SM_WAITSET; if (pingpong_waitset) { - ddsrt_thread_create (&subpingtid, "sub", &attr, subpingthread_waitset, &subarg_pong); - ddsrt_thread_create (&subpongtid, "sub", &attr, subpongthread_waitset, &subarg_pong); + ddsrt_thread_create (&subpingtid, "ping", &attr, subpingthread_waitset, &subarg_pong); + ddsrt_thread_create (&subpongtid, "pong", &attr, subpongthread_waitset, &subarg_pong); } else { @@ -1894,16 +2150,22 @@ int main (int argc, char *argv[]) set_data_available_listener (rd_pong, "rd_pong", pong_available_listener, &subarg_pong); } + /* Have to do this after all threads have been created because it caches the list */ + struct record_cputime_state *cputime_state; + cputime_state = record_cputime_new (wr_stat); + /* Run until time limit reached or a signal received. (The time calculations ignore the possibility of overflow around the year 2260.) */ dds_time_t tnow = dds_time (); const dds_time_t tstart = tnow; + if (tref == DDS_INFINITY) + tref = tstart; dds_time_t tmatch = (maxwait == HUGE_VAL) ? DDS_NEVER : tstart + (int64_t) (maxwait * 1e9 + 0.5); const dds_time_t tstop = (dur == HUGE_VAL) ? DDS_NEVER : tstart + (int64_t) (dur * 1e9 + 0.5); dds_time_t tnext = tstart + DDS_SECS (1); dds_time_t tlast = tstart; dds_time_t tnextping = (ping_intv == DDS_INFINITY) ? DDS_NEVER : (ping_intv == 0) ? tstart + DDS_SECS (1) : tstart + ping_intv; - while (!termflag && tnow < tstop) + while (!ddsrt_atomic_ld32 (&termflag) && tnow < tstop) { dds_time_t twakeup = DDS_NEVER; int32_t nxs; @@ -1968,7 +2230,7 @@ int main (int argc, char *argv[]) tnow = dds_time (); if (tnext <= tnow) { - print_stats (tstart, tnow, tlast); + print_stats (tref, tnow, tlast, cputime_state, netload_state); tlast = tnow; if (tnow > tnext + DDS_MSECS (500)) tnext = tnow + DDS_SECS (1); @@ -1986,10 +2248,12 @@ int main (int argc, char *argv[]) maybe_send_new_ping (tnow, &tnextping); } } + record_netload_free (netload_state); + record_cputime_free (cputime_state); #if _WIN32 signal_handler (SIGINT); -#else +#elif !DDSRT_WITH_FREERTOS { /* get the attention of the signal handler thread */ void (*osigint) (int); @@ -2004,7 +2268,7 @@ int main (int argc, char *argv[]) } #endif - if (rate > 0) + if (pub_rate > 0) ddsrt_thread_join (pubtid, NULL); if (subthread_func != 0) ddsrt_thread_join (subtid, NULL); @@ -2051,6 +2315,10 @@ int main (int argc, char *argv[]) ddsrt_mutex_destroy (&pongstat_lock); ddsrt_mutex_destroy (&pubstat_lock); hist_free (pubstat_hist); + free (pongwr); + for (uint32_t i = 0; i < npongstat; i++) + free (pongstat[i].raw); + free (pongstat); bool ok = true; @@ -2065,6 +2333,9 @@ int main (int argc, char *argv[]) ok = false; } } + + ddsrt_avl_free (&ppants_td, &ppants, free_ppant); + if (matchcount < minmatch) { printf ("[%"PRIdPID"] error: too few matching participants (%"PRIu32" instead of %"PRIu32")\n", ddsrt_getpid (), matchcount, minmatch); diff --git a/src/tools/ddsperf/ddsperf_types.idl b/src/tools/ddsperf/ddsperf_types.idl index 806f30d..2a650f2 100644 --- a/src/tools/ddsperf/ddsperf_types.idl +++ b/src/tools/ddsperf/ddsperf_types.idl @@ -27,3 +27,22 @@ struct KeyedSeq sequence baggage; }; #pragma keylist KeyedSeq keyval + +struct CPUStatThread +{ + string name; + long u_pct; + long s_pct; +}; + +struct CPUStats +{ + string hostname; + unsigned long pid; + double maxrss; + unsigned long vcsw; + unsigned long ivcsw; + boolean some_above; + sequence cpu; +}; +#pragma keylist CPUStats hostname pid diff --git a/src/tools/ddsperf/netload.c b/src/tools/ddsperf/netload.c new file mode 100644 index 0000000..ae716a5 --- /dev/null +++ b/src/tools/ddsperf/netload.c @@ -0,0 +1,116 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/dds.h" + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/netstat.h" + +#include "netload.h" + +#if DDSRT_HAVE_NETSTAT + +struct record_netload_state { + struct ddsrt_netstat_control *ctrl; + char *name; + double bw; + bool errored; + bool data_valid; + dds_time_t tprev; + uint64_t ibytes; + uint64_t obytes; +}; + +void record_netload (struct record_netload_state *st, const char *prefix, dds_time_t tnow) +{ + if (st && !st->errored) + { + struct ddsrt_netstat x; + dds_return_t ret = ddsrt_netstat_get (st->ctrl, &x); + st->errored = (ret == DDS_RETCODE_ERROR); + if (ret == DDS_RETCODE_OK) + { + if (st->data_valid) + { + /* interface speeds are in bits/s, so convert bytes to bits */ + const double dx = 8 * (double) (x.obytes - st->obytes); + const double dr = 8 * (double) (x.ibytes - st->ibytes); + const double dt = (double) (tnow - st->tprev) / 1e9; + const double dxpct = 100.0 * dx / dt / st->bw; + const double drpct = 100.0 * dr / dt / st->bw; + if (dxpct >= 0.5 || drpct >= 0.5) + { + printf ("%s %s: xmit %.0f%% recv %.0f%% [%"PRIu64" %"PRIu64"]\n", + prefix, st->name, dxpct, drpct, x.obytes, x.ibytes); + } + } + st->obytes = x.obytes; + st->ibytes = x.ibytes; + st->tprev = tnow; + st->data_valid = true; + } + } +} + +struct record_netload_state *record_netload_new (const char *dev, double bw) +{ + struct record_netload_state *st = ddsrt_malloc (sizeof (*st)); + if (ddsrt_netstat_new (&st->ctrl, dev) != DDS_RETCODE_OK) + { + ddsrt_free (st); + return NULL; + } + st->name = ddsrt_strdup (dev); + st->bw = bw; + st->data_valid = false; + st->errored = false; + record_netload (st, NULL, dds_time ()); + return st; +} + +void record_netload_free (struct record_netload_state *st) +{ + if (st) + { + ddsrt_netstat_free (st->ctrl); + ddsrt_free (st->name); + ddsrt_free (st); + } +} + +#else + +void record_netload (struct record_netload_state *st, const char *prefix, dds_time_t tnow) +{ + (void) st; + (void) prefix; + (void ) tnow; +} + +struct record_netload_state *record_netload_new (const char *dev, double bw) +{ + (void) dev; + (void) bw; + return NULL; +} + +void record_netload_free (struct record_netload_state *st) +{ + (void) st; +} + +#endif diff --git a/src/tools/ddsperf/netload.h b/src/tools/ddsperf/netload.h new file mode 100644 index 0000000..27a896d --- /dev/null +++ b/src/tools/ddsperf/netload.h @@ -0,0 +1,23 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef NETLOAD_H +#define NETLOAD_H + +#include + +struct record_netload_state; + +void record_netload (struct record_netload_state *st, const char *prefix, dds_time_t tnow); +struct record_netload_state *record_netload_new (const char *dev, double bw); +void record_netload_free (struct record_netload_state *st); + +#endif diff --git a/src/tools/pubsub/common.c b/src/tools/pubsub/common.c index be217cb..a9b5418 100644 --- a/src/tools/pubsub/common.c +++ b/src/tools/pubsub/common.c @@ -400,6 +400,7 @@ static void inapplicable_qos(dds_entity_kind_t qt, const char *n) { #define get_qos_W(qt, q, n) ((qt == DDS_KIND_WRITER) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) #define get_qos_TW(qt, q, n) ((qt == DDS_KIND_TOPIC) || (qt == DDS_KIND_WRITER) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) #define get_qos_RW(qt, q, n) ((qt == DDS_KIND_READER) || (qt == DDS_KIND_WRITER) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) +#define get_qos_MRW(qt, q, n) ((qt == DDS_KIND_READER) || (qt == DDS_KIND_WRITER) || (qt == DDS_KIND_PARTICIPANT) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) #define get_qos_PS(qt, q, n) ((qt == DDS_KIND_PUBLISHER) || (qt == DDS_KIND_SUBSCRIBER) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) #define get_qos_TRW(qt, q, n) ((qt == DDS_KIND_TOPIC) || (qt == DDS_KIND_READER) || (qt == DDS_KIND_WRITER) ? q : (inapplicable_qos((qt), n), (dds_qos_t*)0)) @@ -563,7 +564,7 @@ static void *unescape(const char *str, size_t *len) { } void qos_user_data(dds_entity_kind_t qt, dds_qos_t *q, const char *arg) { - dds_qos_t *qp = get_qos_RW(qt, q, "user_data"); + dds_qos_t *qp = get_qos_MRW(qt, q, "user_data"); size_t len; if (qp == NULL) return; @@ -943,7 +944,7 @@ void setqos_from_args(dds_entity_kind_t qt, dds_qos_t *q, int n, const char *arg #define DDS_ERR_MSG_MAX 128 -void dds_fail (const char * msg, const char * where) +static void dds_fail (const char * msg, const char * where) { fprintf (stderr, "Aborting Failure: %s %s\n", where, msg); abort (); diff --git a/src/tools/pubsub/common.h b/src/tools/pubsub/common.h index e4a0b5f..036e7b7 100644 --- a/src/tools/pubsub/common.h +++ b/src/tools/pubsub/common.h @@ -106,9 +106,11 @@ void qos_ownership(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_transport_priority(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_reliability(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_resource_limits(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); +void qos_durability_service(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_user_data(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_latency_budget(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_lifespan(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); +void qos_presentation(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void qos_autodispose_unregistered_instances(dds_entity_kind_t qt, dds_qos_t *q, const char *arg); void set_qosprovider(const char *arg); void setqos_from_args(dds_entity_kind_t qt, dds_qos_t *q, int n, const char *args[]); @@ -119,7 +121,7 @@ bool dds_err_check (dds_return_t err, unsigned flags, const char *where); #define DDS_CHECK_FAIL 0x02 #define DDS_CHECK_EXIT 0x04 -#define dds_err_str(x) (dds_strretcode(dds_err_nr(x))) +#define dds_err_str(x) (dds_strretcode(x)) #define DDS_TO_STRING(n) #n #define DDS_INT_TO_STRING(n) DDS_TO_STRING(n) diff --git a/src/tools/pubsub/pubsub.c b/src/tools/pubsub/pubsub.c index e775f10..b810d24 100644 --- a/src/tools/pubsub/pubsub.c +++ b/src/tools/pubsub/pubsub.c @@ -567,7 +567,7 @@ static int read_value(char *command, int *key, struct tstamp_t *tstamp, char **a return 1; } break; - case 'p': case 'S': case ':': { + case 'p': case 'S': case ':': case 'Q': { int i = 0; *command = (char) c; while ((c = getc(stdin)) != EOF && !isspace((unsigned char) c)) { @@ -1424,6 +1424,13 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) { dds_sleepfor(DDS_SECS(k)); } break; + case 'Q': { + dds_qos_t *qos = dds_create_qos (); + setqos_from_args (DDS_KIND_PARTICIPANT, qos, 1, (const char **) &arg); + dds_set_qos (dp, qos); + dds_delete_qos (qos); + break; + } case 'Y': case 'B': case 'E': case 'W': non_data_operation(command, spec->wr); break; @@ -2509,10 +2516,10 @@ int main(int argc, char *argv[]) { } break; case 'S': { - char *copy = dds_string_dup(optarg), *tok, *lasts; + char *copy = dds_string_dup(optarg), *tok, *cursor = copy; if (copy == NULL) abort(); - tok = ddsrt_strtok_r(copy, ",", &lasts); + tok = ddsrt_strsep(&cursor, ","); while (tok) { if (strcmp(tok, "pr") == 0 || strcmp(tok, "pre-read") == 0) spec[specidx].rd.print_match_pre_read = 1; @@ -2544,7 +2551,7 @@ int main(int argc, char *argv[]) { fprintf (stderr, "-S %s: invalid event\n", tok); exit(2); } - tok = ddsrt_strtok_r(NULL, ",", &lasts); + tok = ddsrt_strsep(&cursor, ","); } dds_free(copy); } @@ -2792,7 +2799,7 @@ int main(int argc, char *argv[]) { ddsrt_threadattr_t attr; ddsrt_threadattr_init(&attr); - dds_retcode_t osres; + dds_return_t osres; if (want_writer) { for (i = 0; i <= specidx; i++) { diff --git a/vdds-xcode/vdds-xcode.xcodeproj/project.pbxproj b/vdds-xcode/vdds-xcode.xcodeproj/project.pbxproj deleted file mode 100644 index 78c5dc7..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/project.pbxproj +++ /dev/null @@ -1,2310 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 0335203F1CEDD22A003E7429 /* rpc-ping.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF421CCE0DAB00D73982 /* rpc-ping.c */; }; - 033520401CEDD22A003E7429 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; - 033520481CEDD242003E7429 /* rpc-pong.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF431CCE0DAB00D73982 /* rpc-pong.c */; }; - 033520491CEDD244003E7429 /* rpc-pingpong.c in Sources */ = {isa = PBXBuildFile; fileRef = 0335203C1CEDD031003E7429 /* rpc-pingpong.c */; }; - 0335204A1CEDDC48003E7429 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 034CF9311DE2FDF300DD6073 /* q_freelist.c in Sources */ = {isa = PBXBuildFile; fileRef = 034CF92F1DE2FDF300DD6073 /* q_freelist.c */; }; - 034CF9321DE2FDF300DD6073 /* q_freelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 034CF9301DE2FDF300DD6073 /* q_freelist.h */; }; - 034CF9331DE3043A00DD6073 /* q_freelist.c in Sources */ = {isa = PBXBuildFile; fileRef = 034CF92F1DE2FDF300DD6073 /* q_freelist.c */; }; - 035877BB1DDB0F5B000F61E2 /* sysdeps.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF701CCE0DAB00D73982 /* sysdeps.c */; }; - 035877C61DDCA45B000F61E2 /* os_platform_errno.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BD1DDCA45B000F61E2 /* os_platform_errno.c */; }; - 035877C71DDCA45B000F61E2 /* os_platform_heap.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BE1DDCA45B000F61E2 /* os_platform_heap.c */; }; - 035877C81DDCA45B000F61E2 /* os_platform_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BF1DDCA45B000F61E2 /* os_platform_init.c */; }; - 035877C91DDCA45B000F61E2 /* os_platform_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C01DDCA45B000F61E2 /* os_platform_process.c */; }; - 035877CA1DDCA45B000F61E2 /* os_platform_socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C11DDCA45B000F61E2 /* os_platform_socket.c */; }; - 035877CB1DDCA45B000F61E2 /* os_platform_stdlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C21DDCA45B000F61E2 /* os_platform_stdlib.c */; }; - 035877CC1DDCA45B000F61E2 /* os_platform_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C31DDCA45B000F61E2 /* os_platform_sync.c */; }; - 035877CD1DDCA45B000F61E2 /* os_platform_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C41DDCA45B000F61E2 /* os_platform_thread.c */; }; - 035877CE1DDCA45B000F61E2 /* os_platform_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C51DDCA45B000F61E2 /* os_platform_time.c */; }; - 035877CF1DDCA477000F61E2 /* os_platform_errno.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BD1DDCA45B000F61E2 /* os_platform_errno.c */; }; - 035877D01DDCA477000F61E2 /* os_platform_heap.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BE1DDCA45B000F61E2 /* os_platform_heap.c */; }; - 035877D11DDCA477000F61E2 /* os_platform_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877BF1DDCA45B000F61E2 /* os_platform_init.c */; }; - 035877D21DDCA477000F61E2 /* os_platform_process.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C01DDCA45B000F61E2 /* os_platform_process.c */; }; - 035877D31DDCA477000F61E2 /* os_platform_socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C11DDCA45B000F61E2 /* os_platform_socket.c */; }; - 035877D41DDCA477000F61E2 /* os_platform_stdlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C21DDCA45B000F61E2 /* os_platform_stdlib.c */; }; - 035877D51DDCA477000F61E2 /* os_platform_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C31DDCA45B000F61E2 /* os_platform_sync.c */; }; - 035877D61DDCA477000F61E2 /* os_platform_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C41DDCA45B000F61E2 /* os_platform_thread.c */; }; - 035877D71DDCA477000F61E2 /* os_platform_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 035877C51DDCA45B000F61E2 /* os_platform_time.c */; }; - 035877E01DDCA54F000F61E2 /* os_platform_public.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877D91DDCA54F000F61E2 /* os_platform_public.h */; }; - 035877E11DDCA54F000F61E2 /* os_platform_socket.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877DA1DDCA54F000F61E2 /* os_platform_socket.h */; }; - 035877E21DDCA54F000F61E2 /* os_platform_stdlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877DB1DDCA54F000F61E2 /* os_platform_stdlib.h */; }; - 035877E31DDCA54F000F61E2 /* os_platform_sync.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877DC1DDCA54F000F61E2 /* os_platform_sync.h */; }; - 035877E41DDCA54F000F61E2 /* os_platform_thread.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877DD1DDCA54F000F61E2 /* os_platform_thread.h */; }; - 035877E51DDCA54F000F61E2 /* os_platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 035877DF1DDCA54F000F61E2 /* os_platform.h */; }; - 036D25861DF15EB9009A18C5 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; - 036D25881DF15EB9009A18C5 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 036D258E1DF15ECA009A18C5 /* ddpingpong.c in Sources */ = {isa = PBXBuildFile; fileRef = 036D25821DF15EAF009A18C5 /* ddpingpong.c */; }; - 03C96E9F1CCE5B8D0012F15D /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03C96EA51CCE5B9F0012F15D /* server2.c in Sources */ = {isa = PBXBuildFile; fileRef = 03C96E9A1CCE5B800012F15D /* server2.c */; }; - 03C96EA71CCE5CD20012F15D /* libevent_pthreads-2.0.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03C96EA61CCE5CD20012F15D /* libevent_pthreads-2.0.5.dylib */; }; - 03C96EA91CCF6D030012F15D /* libevent-2.0.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03C96EA81CCF6D030012F15D /* libevent-2.0.5.dylib */; }; - 03E6CFD01CCE0DD400D73982 /* ddsi_ser.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF481CCE0DAB00D73982 /* ddsi_ser.c */; }; - 03E6CFD11CCE0DD400D73982 /* ddsi_ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF491CCE0DAB00D73982 /* ddsi_ssl.c */; }; - 03E6CFD21CCE0DD400D73982 /* ddsi_tcp.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF4A1CCE0DAB00D73982 /* ddsi_tcp.c */; }; - 03E6CFD31CCE0DD400D73982 /* ddsi_tran.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF4B1CCE0DAB00D73982 /* ddsi_tran.c */; }; - 03E6CFD41CCE0DD400D73982 /* ddsi_udp.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF4C1CCE0DAB00D73982 /* ddsi_udp.c */; }; - 03E6CFD51CCE0DD400D73982 /* q_addrset.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF4D1CCE0DAB00D73982 /* q_addrset.c */; }; - 03E6CFD61CCE0DD400D73982 /* q_bitset_inlines.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF4E1CCE0DAB00D73982 /* q_bitset_inlines.c */; }; - 03E6CFD81CCE0DD400D73982 /* q_bswap.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF501CCE0DAB00D73982 /* q_bswap.c */; }; - 03E6CFD91CCE0DD400D73982 /* q_bswap_inlines.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF511CCE0DAB00D73982 /* q_bswap_inlines.c */; }; - 03E6CFDB1CCE0DD400D73982 /* q_config.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF531CCE0DAB00D73982 /* q_config.c */; }; - 03E6CFDC1CCE0DD400D73982 /* q_ddsi_discovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF541CCE0DAB00D73982 /* q_ddsi_discovery.c */; }; - 03E6CFDD1CCE0DD400D73982 /* q_debmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF551CCE0DAB00D73982 /* q_debmon.c */; }; - 03E6CFDE1CCE0DD400D73982 /* q_entity.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF561CCE0DAB00D73982 /* q_entity.c */; }; - 03E6CFDF1CCE0DD400D73982 /* q_ephash.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF571CCE0DAB00D73982 /* q_ephash.c */; }; - 03E6CFE01CCE0DD400D73982 /* q_gc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF581CCE0DAB00D73982 /* q_gc.c */; }; - 03E6CFE11CCE0DD400D73982 /* q_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF591CCE0DAB00D73982 /* q_init.c */; }; - 03E6CFE21CCE0DD400D73982 /* q_lat_estim.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5A1CCE0DAB00D73982 /* q_lat_estim.c */; }; - 03E6CFE31CCE0DD400D73982 /* q_lease.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5B1CCE0DAB00D73982 /* q_lease.c */; }; - 03E6CFE41CCE0DD400D73982 /* q_log.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5C1CCE0DAB00D73982 /* q_log.c */; }; - 03E6CFE51CCE0DD400D73982 /* q_md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5D1CCE0DAB00D73982 /* q_md5.c */; }; - 03E6CFE61CCE0DD400D73982 /* q_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5E1CCE0DAB00D73982 /* q_misc.c */; }; - 03E6CFE71CCE0DD400D73982 /* q_nwif.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5F1CCE0DAB00D73982 /* q_nwif.c */; }; - 03E6CFE81CCE0DD400D73982 /* q_pcap.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF601CCE0DAB00D73982 /* q_pcap.c */; }; - 03E6CFE91CCE0DD400D73982 /* q_plist.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF611CCE0DAB00D73982 /* q_plist.c */; }; - 03E6CFEA1CCE0DD400D73982 /* q_qosmatch.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF621CCE0DAB00D73982 /* q_qosmatch.c */; }; - 03E6CFEB1CCE0DD400D73982 /* q_radmin.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF631CCE0DAB00D73982 /* q_radmin.c */; }; - 03E6CFEC1CCE0DD400D73982 /* q_receive.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF641CCE0DAB00D73982 /* q_receive.c */; }; - 03E6CFED1CCE0DD400D73982 /* q_security.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF651CCE0DAB00D73982 /* q_security.c */; }; - 03E6CFEE1CCE0DD400D73982 /* q_servicelease.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF661CCE0DAB00D73982 /* q_servicelease.c */; }; - 03E6CFEF1CCE0DD400D73982 /* q_sockwaitset.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF671CCE0DAB00D73982 /* q_sockwaitset.c */; }; - 03E6CFF01CCE0DD400D73982 /* q_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF681CCE0DAB00D73982 /* q_thread.c */; }; - 03E6CFF11CCE0DD400D73982 /* q_thread_inlines.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF691CCE0DAB00D73982 /* q_thread_inlines.c */; }; - 03E6CFF31CCE0DD400D73982 /* q_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6B1CCE0DAB00D73982 /* q_time.c */; }; - 03E6CFF41CCE0DD400D73982 /* q_transmit.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6C1CCE0DAB00D73982 /* q_transmit.c */; }; - 03E6CFF51CCE0DD400D73982 /* q_whc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6D1CCE0DAB00D73982 /* q_whc.c */; }; - 03E6CFF61CCE0DD400D73982 /* q_xevent.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6E1CCE0DAB00D73982 /* q_xevent.c */; }; - 03E6CFF71CCE0DD400D73982 /* q_xmsg.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6F1CCE0DAB00D73982 /* q_xmsg.c */; }; - 03E6CFF81CCE0DD400D73982 /* sysdeps.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF701CCE0DAB00D73982 /* sysdeps.c */; }; - 03E6CFF91CCE0DE300D73982 /* dds_alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF721CCE0DAB00D73982 /* dds_alloc.c */; }; - 03E6CFFA1CCE0DE300D73982 /* dds_condition.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF731CCE0DAB00D73982 /* dds_condition.c */; }; - 03E6CFFB1CCE0DE300D73982 /* dds_domain.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF741CCE0DAB00D73982 /* dds_domain.c */; }; - 03E6CFFC1CCE0DE300D73982 /* dds_entity.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF751CCE0DAB00D73982 /* dds_entity.c */; }; - 03E6CFFD1CCE0DE300D73982 /* dds_err.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF761CCE0DAB00D73982 /* dds_err.c */; }; - 03E6CFFE1CCE0DE300D73982 /* dds_guardcond.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF771CCE0DAB00D73982 /* dds_guardcond.c */; }; - 03E6CFFF1CCE0DE300D73982 /* dds_iid.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF781CCE0DAB00D73982 /* dds_iid.c */; }; - 03E6D0001CCE0DE300D73982 /* dds_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF791CCE0DAB00D73982 /* dds_init.c */; }; - 03E6D0011CCE0DE300D73982 /* dds_instance.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7A1CCE0DAB00D73982 /* dds_instance.c */; }; - 03E6D0021CCE0DE300D73982 /* dds_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7B1CCE0DAB00D73982 /* dds_key.c */; }; - 03E6D0031CCE0DE300D73982 /* dds_listener.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7C1CCE0DAB00D73982 /* dds_listener.c */; }; - 03E6D0041CCE0DE300D73982 /* dds_log.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7D1CCE0DAB00D73982 /* dds_log.c */; }; - 03E6D0051CCE0DE300D73982 /* dds_participant.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7E1CCE0DAB00D73982 /* dds_participant.c */; }; - 03E6D0061CCE0DE300D73982 /* dds_publisher.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7F1CCE0DAB00D73982 /* dds_publisher.c */; }; - 03E6D0071CCE0DE300D73982 /* dds_qos.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF801CCE0DAB00D73982 /* dds_qos.c */; }; - 03E6D0081CCE0DE300D73982 /* dds_querycond.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF811CCE0DAB00D73982 /* dds_querycond.c */; }; - 03E6D0091CCE0DE300D73982 /* dds_read.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF821CCE0DAB00D73982 /* dds_read.c */; }; - 03E6D00A1CCE0DE300D73982 /* dds_readcond.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF831CCE0DAB00D73982 /* dds_readcond.c */; }; - 03E6D00B1CCE0DE300D73982 /* dds_reader.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF841CCE0DAB00D73982 /* dds_reader.c */; }; - 03E6D00C1CCE0DE300D73982 /* dds_rhc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF851CCE0DAB00D73982 /* dds_rhc.c */; }; - 03E6D00D1CCE0DE300D73982 /* dds_status.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF861CCE0DAB00D73982 /* dds_status.c */; }; - 03E6D00E1CCE0DE300D73982 /* dds_statuscond.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF871CCE0DAB00D73982 /* dds_statuscond.c */; }; - 03E6D00F1CCE0DE300D73982 /* dds_stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF881CCE0DAB00D73982 /* dds_stream.c */; }; - 03E6D0101CCE0DE300D73982 /* dds_subscriber.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF891CCE0DAB00D73982 /* dds_subscriber.c */; }; - 03E6D0111CCE0DE300D73982 /* dds_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8A1CCE0DAB00D73982 /* dds_thread.c */; }; - 03E6D0121CCE0DE300D73982 /* dds_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8B1CCE0DAB00D73982 /* dds_time.c */; }; - 03E6D0131CCE0DE300D73982 /* dds_tkmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8C1CCE0DAB00D73982 /* dds_tkmap.c */; }; - 03E6D0141CCE0DE300D73982 /* dds_topic.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8D1CCE0DAB00D73982 /* dds_topic.c */; }; - 03E6D0151CCE0DE300D73982 /* dds_waitset.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8E1CCE0DAB00D73982 /* dds_waitset.c */; }; - 03E6D0161CCE0DE300D73982 /* dds_write.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8F1CCE0DAB00D73982 /* dds_write.c */; }; - 03E6D0171CCE0DE300D73982 /* dds_writer.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF901CCE0DAB00D73982 /* dds_writer.c */; }; - 03E6D0181CCE0DE300D73982 /* q_osplser.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF911CCE0DAB00D73982 /* q_osplser.c */; }; - 03E6D0191CCE0DED00D73982 /* os_atomics.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF9E1CCE0DAB00D73982 /* os_atomics.c */; }; - 03E6D01A1CCE0DED00D73982 /* os_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF9F1CCE0DAB00D73982 /* os_init.c */; }; - 03E6D01B1CCE0DED00D73982 /* os_report.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA01CCE0DAB00D73982 /* os_report.c */; }; - 03E6D01C1CCE0DED00D73982 /* os_socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA11CCE0DAB00D73982 /* os_socket.c */; }; - 03E6D01D1CCE0DED00D73982 /* os_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA21CCE0DAB00D73982 /* os_sync.c */; }; - 03E6D01E1CCE0DED00D73982 /* os_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA31CCE0DAB00D73982 /* os_thread.c */; }; - 03E6D01F1CCE0DED00D73982 /* os_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA41CCE0DAB00D73982 /* os_time.c */; }; - 03E6D0291CCE0E0500D73982 /* ut_avl.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFC51CCE0DAB00D73982 /* ut_avl.c */; }; - 03E6D02A1CCE0E0500D73982 /* ut_crc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFC61CCE0DAB00D73982 /* ut_crc.c */; }; - 03E6D02B1CCE0E0500D73982 /* ut_expand_envvars.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFC71CCE0DAB00D73982 /* ut_expand_envvars.c */; }; - 03E6D02C1CCE0E0500D73982 /* ut_fibheap.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFC81CCE0DAB00D73982 /* ut_fibheap.c */; }; - 03E6D02D1CCE0E0500D73982 /* ut_hopscotch.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFC91CCE0DAB00D73982 /* ut_hopscotch.c */; }; - 03E6D02E1CCE0E0500D73982 /* ut_thread_pool.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFCA1CCE0DAB00D73982 /* ut_thread_pool.c */; }; - 03E6D02F1CCE0E0500D73982 /* ut_xmlparser.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFCB1CCE0DAB00D73982 /* ut_xmlparser.c */; }; - 03E6D0391CCE0E6200D73982 /* os_atomics.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF9E1CCE0DAB00D73982 /* os_atomics.c */; }; - 03E6D03A1CCE0E6200D73982 /* os_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF9F1CCE0DAB00D73982 /* os_init.c */; }; - 03E6D03B1CCE0E6200D73982 /* os_report.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA01CCE0DAB00D73982 /* os_report.c */; }; - 03E6D03C1CCE0E6200D73982 /* os_socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA11CCE0DAB00D73982 /* os_socket.c */; }; - 03E6D03D1CCE0E6200D73982 /* os_sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA21CCE0DAB00D73982 /* os_sync.c */; }; - 03E6D03E1CCE0E6200D73982 /* os_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA31CCE0DAB00D73982 /* os_thread.c */; }; - 03E6D03F1CCE0E6200D73982 /* os_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFA41CCE0DAB00D73982 /* os_time.c */; }; - 03E6D0401CCE0E7000D73982 /* vdds-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFCF1CCE0DAB00D73982 /* vdds-stubs.c */; }; - 03E6D0411CCE0EB700D73982 /* dds_alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF721CCE0DAB00D73982 /* dds_alloc.c */; }; - 03E6D0421CCE0EBD00D73982 /* dds_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF8B1CCE0DAB00D73982 /* dds_time.c */; }; - 03E6D0431CCE0EC000D73982 /* dds_stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF881CCE0DAB00D73982 /* dds_stream.c */; }; - 03E6D0441CCE0EC600D73982 /* dds_key.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF7B1CCE0DAB00D73982 /* dds_key.c */; }; - 03E6D0451CCE0ECB00D73982 /* dds_err.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF761CCE0DAB00D73982 /* dds_err.c */; }; - 03E6D0461CCE0ED000D73982 /* dds_qos.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF801CCE0DAB00D73982 /* dds_qos.c */; }; - 03E6D0471CCE0EDE00D73982 /* q_bswap.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF501CCE0DAB00D73982 /* q_bswap.c */; }; - 03E6D0481CCE0EE200D73982 /* q_bswap_inlines.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF511CCE0DAB00D73982 /* q_bswap_inlines.c */; }; - 03E6D0491CCE0EE800D73982 /* q_md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5D1CCE0DAB00D73982 /* q_md5.c */; }; - 03E6D04A1CCE0EEC00D73982 /* q_plist.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF611CCE0DAB00D73982 /* q_plist.c */; }; - 03E6D04B1CCE0EF100D73982 /* q_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF6B1CCE0DAB00D73982 /* q_time.c */; }; - 03E6D04C1CCE104600D73982 /* q_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF5E1CCE0DAB00D73982 /* q_misc.c */; }; - 03E6D04D1CCE104E00D73982 /* q_osplser.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF911CCE0DAB00D73982 /* q_osplser.c */; }; - 03E6D04E1CCE105600D73982 /* ddsi_ser.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF481CCE0DAB00D73982 /* ddsi_ser.c */; }; - 03E6D05A1CCE11D300D73982 /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CFCD1CCE0DAB00D73982 /* server.c */; }; - 03E6D05B1CCE11DA00D73982 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03E6D0B41CCE124D00D73982 /* libvdds-stubs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */; }; - 03E6D0B51CCE125100D73982 /* libvdds-stubs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */; }; - 03E6D0B61CCE125500D73982 /* libvdds-stubs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */; }; - 03E6D0B71CCE125800D73982 /* libvdds-stubs.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */; }; - 03E6D0B81CCE125C00D73982 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03E6D0B91CCE125F00D73982 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03E6D0BA1CCE126300D73982 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03E6D0BB1CCE126700D73982 /* libvdds.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; }; - 03E6D0BC1CCE127500D73982 /* publisher.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBF1CCE0DAB00D73982 /* publisher.c */; }; - 03E6D0BD1CCE127800D73982 /* Throughput.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */; }; - 03E6D0BE1CCE127C00D73982 /* subscriber.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEC01CCE0DAB00D73982 /* subscriber.c */; }; - 03E6D0BF1CCE127F00D73982 /* Throughput.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */; }; - 03E6D0C01CCE128500D73982 /* ping.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBD1CCE0DAB00D73982 /* ping.c */; }; - 03E6D0C11CCE128700D73982 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; - 03E6D0C21CCE128D00D73982 /* pong.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBE1CCE0DAB00D73982 /* pong.c */; }; - 03E6D0C31CCE128F00D73982 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; - 03E6D0C41CCE129C00D73982 /* rpc-publisher.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF441CCE0DAB00D73982 /* rpc-publisher.c */; }; - 03E6D0C51CCE129F00D73982 /* Throughput.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */; }; - 03E6D0C61CCE12A400D73982 /* rpc-subscriber.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF451CCE0DAB00D73982 /* rpc-subscriber.c */; }; - 03E6D0C71CCE12A600D73982 /* Throughput.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */; }; - 03E6D0C81CCE12AC00D73982 /* rpc-ping.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF421CCE0DAB00D73982 /* rpc-ping.c */; }; - 03E6D0C91CCE12AE00D73982 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; - 03E6D0CA1CCE12B400D73982 /* rpc-pong.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CF431CCE0DAB00D73982 /* rpc-pong.c */; }; - 03E6D0CB1CCE12B600D73982 /* RoundTrip.c in Sources */ = {isa = PBXBuildFile; fileRef = 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 033520431CEDD22A003E7429 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 036D25891DF15EB9009A18C5 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03C96EA01CCE5B8D0012F15D /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0511CCE116900D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D05E1CCE121300D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0691CCE121A00D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0741CCE121F00D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D07F1CCE122400D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D08A1CCE122A00D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0951CCE123000D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0A01CCE123500D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; - 03E6D0AB1CCE123A00D73982 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0335203C1CEDD031003E7429 /* rpc-pingpong.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "rpc-pingpong.c"; sourceTree = ""; }; - 033520471CEDD22A003E7429 /* rpc-pingpong */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rpc-pingpong"; sourceTree = BUILT_PRODUCTS_DIR; }; - 0335204B1CEF4B21003E7429 /* q_bitset_template.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_bitset_template.h; sourceTree = ""; }; - 0335204C1CEF4B21003E7429 /* q_bswap_template.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_bswap_template.h; sourceTree = ""; }; - 0335204D1CEF4B21003E7429 /* q_thread_template.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_thread_template.h; sourceTree = ""; }; - 034CF92F1DE2FDF300DD6073 /* q_freelist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = q_freelist.c; sourceTree = ""; }; - 034CF9301DE2FDF300DD6073 /* q_freelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = q_freelist.h; sourceTree = ""; }; - 035877B71DDB0A20000F61E2 /* lite.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = lite.xml; path = ../lite.xml; sourceTree = ""; }; - 035877B81DDB0A20000F61E2 /* config.mk */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; name = config.mk; path = ../config.mk; sourceTree = ""; }; - 035877B91DDB0A20000F61E2 /* guess-config */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = "guess-config"; path = "../guess-config"; sourceTree = ""; }; - 035877BA1DDB0A20000F61E2 /* makefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; name = makefile; path = ../makefile; sourceTree = ""; }; - 035877BD1DDCA45B000F61E2 /* os_platform_errno.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_errno.c; sourceTree = ""; }; - 035877BE1DDCA45B000F61E2 /* os_platform_heap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_heap.c; sourceTree = ""; }; - 035877BF1DDCA45B000F61E2 /* os_platform_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_init.c; sourceTree = ""; }; - 035877C01DDCA45B000F61E2 /* os_platform_process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_process.c; sourceTree = ""; }; - 035877C11DDCA45B000F61E2 /* os_platform_socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_socket.c; sourceTree = ""; }; - 035877C21DDCA45B000F61E2 /* os_platform_stdlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_stdlib.c; sourceTree = ""; }; - 035877C31DDCA45B000F61E2 /* os_platform_sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_sync.c; sourceTree = ""; }; - 035877C41DDCA45B000F61E2 /* os_platform_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_thread.c; sourceTree = ""; }; - 035877C51DDCA45B000F61E2 /* os_platform_time.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = os_platform_time.c; sourceTree = ""; }; - 035877D91DDCA54F000F61E2 /* os_platform_public.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform_public.h; sourceTree = ""; }; - 035877DA1DDCA54F000F61E2 /* os_platform_socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform_socket.h; sourceTree = ""; }; - 035877DB1DDCA54F000F61E2 /* os_platform_stdlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform_stdlib.h; sourceTree = ""; }; - 035877DC1DDCA54F000F61E2 /* os_platform_sync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform_sync.h; sourceTree = ""; }; - 035877DD1DDCA54F000F61E2 /* os_platform_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform_thread.h; sourceTree = ""; }; - 035877DF1DDCA54F000F61E2 /* os_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = os_platform.h; sourceTree = ""; }; - 036D25821DF15EAF009A18C5 /* ddpingpong.c */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = ddpingpong.c; sourceTree = ""; }; - 036D258D1DF15EBA009A18C5 /* ddpingpong */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddpingpong; sourceTree = BUILT_PRODUCTS_DIR; }; - 037D2E711CD2455A004434B2 /* os_platform_heap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_heap.c; sourceTree = ""; }; - 037D2E721CD2455A004434B2 /* os_platform_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_init.c; sourceTree = ""; }; - 037D2E731CD2455A004434B2 /* os_platform_socket.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_socket.c; sourceTree = ""; }; - 037D2E741CD2455A004434B2 /* os_platform_sync.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_sync.c; sourceTree = ""; }; - 037D2E751CD2455A004434B2 /* os_platform_thread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_thread.c; sourceTree = ""; }; - 037D2E761CD2455A004434B2 /* os_platform_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_platform_time.c; sourceTree = ""; }; - 037D2E771CD24576004434B2 /* os_atomics_win32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_atomics_win32.h; sourceTree = ""; }; - 037D2E801CD245BB004434B2 /* os_platform_public.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_public.h; sourceTree = ""; }; - 037D2E811CD245BB004434B2 /* os_platform_socket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_socket.h; sourceTree = ""; }; - 037D2E821CD245BB004434B2 /* os_platform_stdlib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_stdlib.h; sourceTree = ""; }; - 037D2E831CD245BB004434B2 /* os_platform_sync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_sync.h; sourceTree = ""; }; - 037D2E841CD245BB004434B2 /* os_platform_thread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_thread.h; sourceTree = ""; }; - 037D2E851CD245BB004434B2 /* os_platform_time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform_time.h; sourceTree = ""; }; - 037D2E861CD245BB004434B2 /* os_platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform.h; sourceTree = ""; }; - 03C96E9A1CCE5B800012F15D /* server2.c */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = server2.c; sourceTree = ""; }; - 03C96EA41CCE5B8D0012F15D /* vdds-server2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "vdds-server2"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03C96EA61CCE5CD20012F15D /* libevent_pthreads-2.0.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libevent_pthreads-2.0.5.dylib"; path = "../../../../../usr/local/Cellar/libevent/2.0.22/lib/libevent_pthreads-2.0.5.dylib"; sourceTree = ""; }; - 03C96EA81CCF6D030012F15D /* libevent-2.0.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libevent-2.0.5.dylib"; path = "../../../../../usr/local/Cellar/libevent/2.0.22/lib/libevent-2.0.5.dylib"; sourceTree = ""; }; - 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libvdds.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libvdds-stubs.dylib"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = RoundTrip.c; sourceTree = ""; }; - 03E6CEB81CCE0DAB00D73982 /* RoundTrip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoundTrip.h; sourceTree = ""; }; - 03E6CEB91CCE0DAB00D73982 /* RoundTrip.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = RoundTrip.idl; sourceTree = ""; }; - 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Throughput.c; sourceTree = ""; }; - 03E6CEBB1CCE0DAB00D73982 /* Throughput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Throughput.h; sourceTree = ""; }; - 03E6CEBC1CCE0DAB00D73982 /* Throughput.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Throughput.idl; sourceTree = ""; }; - 03E6CEBD1CCE0DAB00D73982 /* ping.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ping.c; sourceTree = ""; }; - 03E6CEBE1CCE0DAB00D73982 /* pong.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pong.c; sourceTree = ""; }; - 03E6CEBF1CCE0DAB00D73982 /* publisher.c */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.c; path = publisher.c; sourceTree = ""; }; - 03E6CEC01CCE0DAB00D73982 /* subscriber.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = subscriber.c; sourceTree = ""; }; - 03E6CEC31CCE0DAB00D73982 /* dds_public_alloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_alloc.h; sourceTree = ""; }; - 03E6CEC41CCE0DAB00D73982 /* dds_public_error.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_error.h; sourceTree = ""; }; - 03E6CEC51CCE0DAB00D73982 /* dds_public_impl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_impl.h; sourceTree = ""; }; - 03E6CEC61CCE0DAB00D73982 /* dds_public_log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_log.h; sourceTree = ""; }; - 03E6CEC71CCE0DAB00D73982 /* dds_public_qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_qos.h; sourceTree = ""; }; - 03E6CEC81CCE0DAB00D73982 /* dds_public_status.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_status.h; sourceTree = ""; }; - 03E6CEC91CCE0DAB00D73982 /* dds_public_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_stream.h; sourceTree = ""; }; - 03E6CECA1CCE0DAB00D73982 /* dds_public_time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_public_time.h; sourceTree = ""; }; - 03E6CED21CCE0DAB00D73982 /* dds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds.h; sourceTree = ""; }; - 03E6CED41CCE0DAB00D73982 /* ddsi_ser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ddsi_ser.h; sourceTree = ""; }; - 03E6CED51CCE0DAB00D73982 /* ddsi_ssl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ddsi_ssl.h; sourceTree = ""; }; - 03E6CED61CCE0DAB00D73982 /* ddsi_tcp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ddsi_tcp.h; sourceTree = ""; }; - 03E6CED71CCE0DAB00D73982 /* ddsi_tran.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ddsi_tran.h; sourceTree = ""; }; - 03E6CED81CCE0DAB00D73982 /* ddsi_udp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ddsi_udp.h; sourceTree = ""; }; - 03E6CED91CCE0DAB00D73982 /* probes-constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "probes-constants.h"; sourceTree = ""; }; - 03E6CEDA1CCE0DAB00D73982 /* q_addrset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_addrset.h; sourceTree = ""; }; - 03E6CEDB1CCE0DAB00D73982 /* q_align.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_align.h; sourceTree = ""; }; - 03E6CEDC1CCE0DAB00D73982 /* q_bitset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_bitset.h; sourceTree = ""; }; - 03E6CEDD1CCE0DAB00D73982 /* q_bswap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_bswap.h; sourceTree = ""; }; - 03E6CEDE1CCE0DAB00D73982 /* q_builtin_topic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_builtin_topic.h; sourceTree = ""; }; - 03E6CEDF1CCE0DAB00D73982 /* q_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_config.h; sourceTree = ""; }; - 03E6CEE01CCE0DAB00D73982 /* q_ddsi_discovery.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_ddsi_discovery.h; sourceTree = ""; }; - 03E6CEE11CCE0DAB00D73982 /* q_debmon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_debmon.h; sourceTree = ""; }; - 03E6CEE21CCE0DAB00D73982 /* q_entity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_entity.h; sourceTree = ""; }; - 03E6CEE31CCE0DAB00D73982 /* q_ephash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_ephash.h; sourceTree = ""; }; - 03E6CEE41CCE0DAB00D73982 /* q_error.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_error.h; sourceTree = ""; }; - 03E6CEE51CCE0DAB00D73982 /* q_feature_check.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_feature_check.h; sourceTree = ""; }; - 03E6CEE61CCE0DAB00D73982 /* q_gc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_gc.h; sourceTree = ""; }; - 03E6CEE71CCE0DAB00D73982 /* q_globals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_globals.h; sourceTree = ""; }; - 03E6CEE81CCE0DAB00D73982 /* q_hbcontrol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_hbcontrol.h; sourceTree = ""; }; - 03E6CEE91CCE0DAB00D73982 /* q_inline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_inline.h; sourceTree = ""; }; - 03E6CEEA1CCE0DAB00D73982 /* q_lat_estim.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_lat_estim.h; sourceTree = ""; }; - 03E6CEEB1CCE0DAB00D73982 /* q_lease.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_lease.h; sourceTree = ""; }; - 03E6CEEC1CCE0DAB00D73982 /* q_log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_log.h; sourceTree = ""; }; - 03E6CEED1CCE0DAB00D73982 /* q_md5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_md5.h; sourceTree = ""; }; - 03E6CEEE1CCE0DAB00D73982 /* q_misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_misc.h; sourceTree = ""; }; - 03E6CEEF1CCE0DAB00D73982 /* q_nwif.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_nwif.h; sourceTree = ""; }; - 03E6CEF01CCE0DAB00D73982 /* q_pcap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_pcap.h; sourceTree = ""; }; - 03E6CEF11CCE0DAB00D73982 /* q_plist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_plist.h; sourceTree = ""; }; - 03E6CEF21CCE0DAB00D73982 /* q_protocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_protocol.h; sourceTree = ""; }; - 03E6CEF31CCE0DAB00D73982 /* q_qosmatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_qosmatch.h; sourceTree = ""; }; - 03E6CEF41CCE0DAB00D73982 /* q_radmin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_radmin.h; sourceTree = ""; }; - 03E6CEF51CCE0DAB00D73982 /* q_receive.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_receive.h; sourceTree = ""; }; - 03E6CEF61CCE0DAB00D73982 /* q_rtps.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_rtps.h; sourceTree = ""; }; - 03E6CEF71CCE0DAB00D73982 /* q_security.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_security.h; sourceTree = ""; }; - 03E6CEF81CCE0DAB00D73982 /* q_servicelease.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_servicelease.h; sourceTree = ""; }; - 03E6CEF91CCE0DAB00D73982 /* q_sockwaitset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_sockwaitset.h; sourceTree = ""; }; - 03E6CEFA1CCE0DAB00D73982 /* q_static_assert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_static_assert.h; sourceTree = ""; }; - 03E6CEFB1CCE0DAB00D73982 /* q_thread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_thread.h; sourceTree = ""; }; - 03E6CEFC1CCE0DAB00D73982 /* q_time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_time.h; sourceTree = ""; }; - 03E6CEFD1CCE0DAB00D73982 /* q_transmit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_transmit.h; sourceTree = ""; }; - 03E6CEFE1CCE0DAB00D73982 /* q_unused.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_unused.h; sourceTree = ""; }; - 03E6CEFF1CCE0DAB00D73982 /* q_whc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_whc.h; sourceTree = ""; }; - 03E6CF001CCE0DAB00D73982 /* q_xevent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_xevent.h; sourceTree = ""; }; - 03E6CF011CCE0DAB00D73982 /* q_xmsg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_xmsg.h; sourceTree = ""; }; - 03E6CF021CCE0DAB00D73982 /* q_xqos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_xqos.h; sourceTree = ""; }; - 03E6CF031CCE0DAB00D73982 /* sysdeps.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sysdeps.h; sourceTree = ""; }; - 03E6CF051CCE0DAB00D73982 /* dds_alloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_alloc.h; sourceTree = ""; }; - 03E6CF061CCE0DAB00D73982 /* dds_condition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_condition.h; sourceTree = ""; }; - 03E6CF071CCE0DAB00D73982 /* dds_domain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_domain.h; sourceTree = ""; }; - 03E6CF081CCE0DAB00D73982 /* dds_entity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_entity.h; sourceTree = ""; }; - 03E6CF091CCE0DAB00D73982 /* dds_export.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_export.h; sourceTree = ""; }; - 03E6CF0A1CCE0DAB00D73982 /* dds_guardcond.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_guardcond.h; sourceTree = ""; }; - 03E6CF0B1CCE0DAB00D73982 /* dds_iid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_iid.h; sourceTree = ""; }; - 03E6CF0C1CCE0DAB00D73982 /* dds_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_init.h; sourceTree = ""; }; - 03E6CF0D1CCE0DAB00D73982 /* dds_key.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_key.h; sourceTree = ""; }; - 03E6CF0E1CCE0DAB00D73982 /* dds_listener.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_listener.h; sourceTree = ""; }; - 03E6CF0F1CCE0DAB00D73982 /* dds_participant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_participant.h; sourceTree = ""; }; - 03E6CF101CCE0DAB00D73982 /* dds_qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_qos.h; sourceTree = ""; }; - 03E6CF111CCE0DAB00D73982 /* dds_querycond.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_querycond.h; sourceTree = ""; }; - 03E6CF121CCE0DAB00D73982 /* dds_readcond.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_readcond.h; sourceTree = ""; }; - 03E6CF131CCE0DAB00D73982 /* dds_reader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_reader.h; sourceTree = ""; }; - 03E6CF141CCE0DAB00D73982 /* dds_rhc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_rhc.h; sourceTree = ""; }; - 03E6CF151CCE0DAB00D73982 /* dds_status.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_status.h; sourceTree = ""; }; - 03E6CF161CCE0DAB00D73982 /* dds_statuscond.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_statuscond.h; sourceTree = ""; }; - 03E6CF171CCE0DAB00D73982 /* dds_stream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_stream.h; sourceTree = ""; }; - 03E6CF181CCE0DAB00D73982 /* dds_tkmap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_tkmap.h; sourceTree = ""; }; - 03E6CF191CCE0DAB00D73982 /* dds_topic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_topic.h; sourceTree = ""; }; - 03E6CF1A1CCE0DAB00D73982 /* dds_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_types.h; sourceTree = ""; }; - 03E6CF1B1CCE0DAB00D73982 /* dds_waitset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_waitset.h; sourceTree = ""; }; - 03E6CF1C1CCE0DAB00D73982 /* dds_write.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_write.h; sourceTree = ""; }; - 03E6CF1D1CCE0DAB00D73982 /* dds_writer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dds_writer.h; sourceTree = ""; }; - 03E6CF1E1CCE0DAB00D73982 /* q_osplser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = q_osplser.h; sourceTree = ""; }; - 03E6CF211CCE0DAB00D73982 /* os_platform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_platform.h; sourceTree = ""; }; - 03E6CF271CCE0DAB00D73982 /* os.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os.h; sourceTree = ""; }; - 03E6CF281CCE0DAB00D73982 /* os_atomics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_atomics.h; sourceTree = ""; }; - 03E6CF291CCE0DAB00D73982 /* os_atomics_gcc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_atomics_gcc.h; sourceTree = ""; }; - 03E6CF2A1CCE0DAB00D73982 /* os_decl_attributes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_decl_attributes.h; sourceTree = ""; }; - 03E6CF2B1CCE0DAB00D73982 /* os_decl_attributes_sal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_decl_attributes_sal.h; sourceTree = ""; }; - 03E6CF2C1CCE0DAB00D73982 /* os_defs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_defs.h; sourceTree = ""; }; - 03E6CF2D1CCE0DAB00D73982 /* os_errno.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_errno.h; sourceTree = ""; }; - 03E6CF2E1CCE0DAB00D73982 /* os_heap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_heap.h; sourceTree = ""; }; - 03E6CF2F1CCE0DAB00D73982 /* os_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_init.h; sourceTree = ""; }; - 03E6CF301CCE0DAB00D73982 /* os_process.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_process.h; sourceTree = ""; }; - 03E6CF311CCE0DAB00D73982 /* os_public.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_public.h; sourceTree = ""; }; - 03E6CF321CCE0DAB00D73982 /* os_report.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_report.h; sourceTree = ""; }; - 03E6CF331CCE0DAB00D73982 /* os_socket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_socket.h; sourceTree = ""; }; - 03E6CF341CCE0DAB00D73982 /* os_stdlib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_stdlib.h; sourceTree = ""; }; - 03E6CF351CCE0DAB00D73982 /* os_sync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_sync.h; sourceTree = ""; }; - 03E6CF361CCE0DAB00D73982 /* os_thread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_thread.h; sourceTree = ""; }; - 03E6CF371CCE0DAB00D73982 /* os_time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_time.h; sourceTree = ""; }; - 03E6CF391CCE0DAB00D73982 /* ut_avl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_avl.h; sourceTree = ""; }; - 03E6CF3A1CCE0DAB00D73982 /* ut_crc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_crc.h; sourceTree = ""; }; - 03E6CF3B1CCE0DAB00D73982 /* ut_expand_envvars.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_expand_envvars.h; sourceTree = ""; }; - 03E6CF3C1CCE0DAB00D73982 /* ut_fibheap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_fibheap.h; sourceTree = ""; }; - 03E6CF3D1CCE0DAB00D73982 /* ut_hopscotch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_hopscotch.h; sourceTree = ""; }; - 03E6CF3E1CCE0DAB00D73982 /* ut_thread_pool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_thread_pool.h; sourceTree = ""; }; - 03E6CF3F1CCE0DAB00D73982 /* ut_xmlparser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ut_xmlparser.h; sourceTree = ""; }; - 03E6CF421CCE0DAB00D73982 /* rpc-ping.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "rpc-ping.c"; sourceTree = ""; }; - 03E6CF431CCE0DAB00D73982 /* rpc-pong.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "rpc-pong.c"; sourceTree = ""; }; - 03E6CF441CCE0DAB00D73982 /* rpc-publisher.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "rpc-publisher.c"; sourceTree = ""; }; - 03E6CF451CCE0DAB00D73982 /* rpc-subscriber.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "rpc-subscriber.c"; sourceTree = ""; }; - 03E6CF481CCE0DAB00D73982 /* ddsi_ser.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ddsi_ser.c; sourceTree = ""; }; - 03E6CF491CCE0DAB00D73982 /* ddsi_ssl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ddsi_ssl.c; sourceTree = ""; }; - 03E6CF4A1CCE0DAB00D73982 /* ddsi_tcp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ddsi_tcp.c; sourceTree = ""; }; - 03E6CF4B1CCE0DAB00D73982 /* ddsi_tran.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ddsi_tran.c; sourceTree = ""; }; - 03E6CF4C1CCE0DAB00D73982 /* ddsi_udp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ddsi_udp.c; sourceTree = ""; }; - 03E6CF4D1CCE0DAB00D73982 /* q_addrset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_addrset.c; sourceTree = ""; }; - 03E6CF4E1CCE0DAB00D73982 /* q_bitset_inlines.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_bitset_inlines.c; sourceTree = ""; }; - 03E6CF501CCE0DAB00D73982 /* q_bswap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_bswap.c; sourceTree = ""; }; - 03E6CF511CCE0DAB00D73982 /* q_bswap_inlines.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_bswap_inlines.c; sourceTree = ""; }; - 03E6CF531CCE0DAB00D73982 /* q_config.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_config.c; sourceTree = ""; }; - 03E6CF541CCE0DAB00D73982 /* q_ddsi_discovery.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_ddsi_discovery.c; sourceTree = ""; }; - 03E6CF551CCE0DAB00D73982 /* q_debmon.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_debmon.c; sourceTree = ""; }; - 03E6CF561CCE0DAB00D73982 /* q_entity.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_entity.c; sourceTree = ""; }; - 03E6CF571CCE0DAB00D73982 /* q_ephash.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_ephash.c; sourceTree = ""; }; - 03E6CF581CCE0DAB00D73982 /* q_gc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_gc.c; sourceTree = ""; }; - 03E6CF591CCE0DAB00D73982 /* q_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_init.c; sourceTree = ""; }; - 03E6CF5A1CCE0DAB00D73982 /* q_lat_estim.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_lat_estim.c; sourceTree = ""; }; - 03E6CF5B1CCE0DAB00D73982 /* q_lease.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_lease.c; sourceTree = ""; }; - 03E6CF5C1CCE0DAB00D73982 /* q_log.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_log.c; sourceTree = ""; }; - 03E6CF5D1CCE0DAB00D73982 /* q_md5.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_md5.c; sourceTree = ""; }; - 03E6CF5E1CCE0DAB00D73982 /* q_misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_misc.c; sourceTree = ""; }; - 03E6CF5F1CCE0DAB00D73982 /* q_nwif.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_nwif.c; sourceTree = ""; }; - 03E6CF601CCE0DAB00D73982 /* q_pcap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_pcap.c; sourceTree = ""; }; - 03E6CF611CCE0DAB00D73982 /* q_plist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_plist.c; sourceTree = ""; }; - 03E6CF621CCE0DAB00D73982 /* q_qosmatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_qosmatch.c; sourceTree = ""; }; - 03E6CF631CCE0DAB00D73982 /* q_radmin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_radmin.c; sourceTree = ""; }; - 03E6CF641CCE0DAB00D73982 /* q_receive.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_receive.c; sourceTree = ""; }; - 03E6CF651CCE0DAB00D73982 /* q_security.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_security.c; sourceTree = ""; }; - 03E6CF661CCE0DAB00D73982 /* q_servicelease.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_servicelease.c; sourceTree = ""; }; - 03E6CF671CCE0DAB00D73982 /* q_sockwaitset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_sockwaitset.c; sourceTree = ""; }; - 03E6CF681CCE0DAB00D73982 /* q_thread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_thread.c; sourceTree = ""; }; - 03E6CF691CCE0DAB00D73982 /* q_thread_inlines.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_thread_inlines.c; sourceTree = ""; }; - 03E6CF6B1CCE0DAB00D73982 /* q_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_time.c; sourceTree = ""; }; - 03E6CF6C1CCE0DAB00D73982 /* q_transmit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_transmit.c; sourceTree = ""; }; - 03E6CF6D1CCE0DAB00D73982 /* q_whc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_whc.c; sourceTree = ""; }; - 03E6CF6E1CCE0DAB00D73982 /* q_xevent.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_xevent.c; sourceTree = ""; }; - 03E6CF6F1CCE0DAB00D73982 /* q_xmsg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_xmsg.c; sourceTree = ""; }; - 03E6CF701CCE0DAB00D73982 /* sysdeps.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sysdeps.c; sourceTree = ""; }; - 03E6CF721CCE0DAB00D73982 /* dds_alloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_alloc.c; sourceTree = ""; }; - 03E6CF731CCE0DAB00D73982 /* dds_condition.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_condition.c; sourceTree = ""; }; - 03E6CF741CCE0DAB00D73982 /* dds_domain.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_domain.c; sourceTree = ""; }; - 03E6CF751CCE0DAB00D73982 /* dds_entity.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_entity.c; sourceTree = ""; }; - 03E6CF761CCE0DAB00D73982 /* dds_err.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_err.c; sourceTree = ""; }; - 03E6CF771CCE0DAB00D73982 /* dds_guardcond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_guardcond.c; sourceTree = ""; }; - 03E6CF781CCE0DAB00D73982 /* dds_iid.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_iid.c; sourceTree = ""; }; - 03E6CF791CCE0DAB00D73982 /* dds_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_init.c; sourceTree = ""; }; - 03E6CF7A1CCE0DAB00D73982 /* dds_instance.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_instance.c; sourceTree = ""; }; - 03E6CF7B1CCE0DAB00D73982 /* dds_key.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_key.c; sourceTree = ""; }; - 03E6CF7C1CCE0DAB00D73982 /* dds_listener.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_listener.c; sourceTree = ""; }; - 03E6CF7D1CCE0DAB00D73982 /* dds_log.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_log.c; sourceTree = ""; }; - 03E6CF7E1CCE0DAB00D73982 /* dds_participant.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_participant.c; sourceTree = ""; }; - 03E6CF7F1CCE0DAB00D73982 /* dds_publisher.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_publisher.c; sourceTree = ""; }; - 03E6CF801CCE0DAB00D73982 /* dds_qos.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_qos.c; sourceTree = ""; }; - 03E6CF811CCE0DAB00D73982 /* dds_querycond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_querycond.c; sourceTree = ""; }; - 03E6CF821CCE0DAB00D73982 /* dds_read.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_read.c; sourceTree = ""; }; - 03E6CF831CCE0DAB00D73982 /* dds_readcond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_readcond.c; sourceTree = ""; }; - 03E6CF841CCE0DAB00D73982 /* dds_reader.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_reader.c; sourceTree = ""; }; - 03E6CF851CCE0DAB00D73982 /* dds_rhc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_rhc.c; sourceTree = ""; }; - 03E6CF861CCE0DAB00D73982 /* dds_status.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_status.c; sourceTree = ""; }; - 03E6CF871CCE0DAB00D73982 /* dds_statuscond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_statuscond.c; sourceTree = ""; }; - 03E6CF881CCE0DAB00D73982 /* dds_stream.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_stream.c; sourceTree = ""; }; - 03E6CF891CCE0DAB00D73982 /* dds_subscriber.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_subscriber.c; sourceTree = ""; }; - 03E6CF8A1CCE0DAB00D73982 /* dds_thread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_thread.c; sourceTree = ""; }; - 03E6CF8B1CCE0DAB00D73982 /* dds_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_time.c; sourceTree = ""; }; - 03E6CF8C1CCE0DAB00D73982 /* dds_tkmap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_tkmap.c; sourceTree = ""; }; - 03E6CF8D1CCE0DAB00D73982 /* dds_topic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_topic.c; sourceTree = ""; }; - 03E6CF8E1CCE0DAB00D73982 /* dds_waitset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_waitset.c; sourceTree = ""; }; - 03E6CF8F1CCE0DAB00D73982 /* dds_write.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_write.c; sourceTree = ""; }; - 03E6CF901CCE0DAB00D73982 /* dds_writer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dds_writer.c; sourceTree = ""; }; - 03E6CF911CCE0DAB00D73982 /* q_osplser.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = q_osplser.c; sourceTree = ""; }; - 03E6CF9E1CCE0DAB00D73982 /* os_atomics.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_atomics.c; sourceTree = ""; }; - 03E6CF9F1CCE0DAB00D73982 /* os_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_init.c; sourceTree = ""; }; - 03E6CFA01CCE0DAB00D73982 /* os_report.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_report.c; sourceTree = ""; }; - 03E6CFA11CCE0DAB00D73982 /* os_socket.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_socket.c; sourceTree = ""; }; - 03E6CFA21CCE0DAB00D73982 /* os_sync.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_sync.c; sourceTree = ""; }; - 03E6CFA31CCE0DAB00D73982 /* os_thread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_thread.c; sourceTree = ""; }; - 03E6CFA41CCE0DAB00D73982 /* os_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_time.c; sourceTree = ""; }; - 03E6CFA71CCE0DAB00D73982 /* os_gethostname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_gethostname.c; sourceTree = ""; }; - 03E6CFA81CCE0DAB00D73982 /* os_heap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_heap.c; sourceTree = ""; }; - 03E6CFA91CCE0DAB00D73982 /* os_posix_errno.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_posix_errno.c; sourceTree = ""; }; - 03E6CFAA1CCE0DAB00D73982 /* os_posix_process.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_posix_process.c; sourceTree = ""; }; - 03E6CFAB1CCE0DAB00D73982 /* os_posix_thread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_posix_thread.c; sourceTree = ""; }; - 03E6CFAC1CCE0DAB00D73982 /* os_stdlib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib.c; sourceTree = ""; }; - 03E6CFAD1CCE0DAB00D73982 /* os_stdlib_bsearch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib_bsearch.c; sourceTree = ""; }; - 03E6CFAE1CCE0DAB00D73982 /* os_stdlib_strsep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib_strsep.c; sourceTree = ""; }; - 03E6CFAF1CCE0DAB00D73982 /* os_stdlib_strtod.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib_strtod.c; sourceTree = ""; }; - 03E6CFB01CCE0DAB00D73982 /* os_stdlib_strtok_r.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib_strtok_r.c; sourceTree = ""; }; - 03E6CFB11CCE0DAB00D73982 /* os_stdlib_strtol.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = os_stdlib_strtol.c; sourceTree = ""; }; - 03E6CFB31CCE0DAB00D73982 /* os_posix_stdlib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = os_posix_stdlib.h; sourceTree = ""; }; - 03E6CFC51CCE0DAB00D73982 /* ut_avl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_avl.c; sourceTree = ""; }; - 03E6CFC61CCE0DAB00D73982 /* ut_crc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_crc.c; sourceTree = ""; }; - 03E6CFC71CCE0DAB00D73982 /* ut_expand_envvars.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_expand_envvars.c; sourceTree = ""; }; - 03E6CFC81CCE0DAB00D73982 /* ut_fibheap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_fibheap.c; sourceTree = ""; }; - 03E6CFC91CCE0DAB00D73982 /* ut_hopscotch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_hopscotch.c; sourceTree = ""; }; - 03E6CFCA1CCE0DAB00D73982 /* ut_thread_pool.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_thread_pool.c; sourceTree = ""; }; - 03E6CFCB1CCE0DAB00D73982 /* ut_xmlparser.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ut_xmlparser.c; sourceTree = ""; }; - 03E6CFCD1CCE0DAB00D73982 /* server.c */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = ""; }; - 03E6CFCE1CCE0DAB00D73982 /* server.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = server.h; sourceTree = ""; }; - 03E6CFCF1CCE0DAB00D73982 /* vdds-stubs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "vdds-stubs.c"; sourceTree = ""; }; - 03E6D0531CCE116900D73982 /* vdds-server */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "vdds-server"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0601CCE121300D73982 /* publisher */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = publisher; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D06B1CCE121A00D73982 /* subscriber */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = subscriber; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0761CCE121F00D73982 /* ping */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ping; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0811CCE122400D73982 /* pong */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pong; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D08C1CCE122A00D73982 /* rpc-publisher */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rpc-publisher"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0971CCE123000D73982 /* rpc-subscriber */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rpc-subscriber"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0A21CCE123500D73982 /* rpc-ping */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rpc-ping"; sourceTree = BUILT_PRODUCTS_DIR; }; - 03E6D0AD1CCE123A00D73982 /* rpc-pong */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "rpc-pong"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 033520411CEDD22A003E7429 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0335204A1CEDDC48003E7429 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 036D25871DF15EB9009A18C5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 036D25881DF15EB9009A18C5 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03C96E9E1CCE5B8D0012F15D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03C96EA91CCF6D030012F15D /* libevent-2.0.5.dylib in Frameworks */, - 03C96EA71CCE5CD20012F15D /* libevent_pthreads-2.0.5.dylib in Frameworks */, - 03C96E9F1CCE5B8D0012F15D /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6CEA61CCE0CA400D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6CEAE1CCE0CCC00D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0501CCE116900D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D05B1CCE11DA00D73982 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D05D1CCE121300D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0BB1CCE126700D73982 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0681CCE121A00D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0BA1CCE126300D73982 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0731CCE121F00D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B91CCE125F00D73982 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D07E1CCE122400D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B81CCE125C00D73982 /* libvdds.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0891CCE122A00D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B71CCE125800D73982 /* libvdds-stubs.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0941CCE123000D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B61CCE125500D73982 /* libvdds-stubs.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D09F1CCE123500D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B51CCE125100D73982 /* libvdds-stubs.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0AA1CCE123A00D73982 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0B41CCE124D00D73982 /* libvdds-stubs.dylib in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 035877BC1DDCA45B000F61E2 /* posix */ = { - isa = PBXGroup; - children = ( - 035877BD1DDCA45B000F61E2 /* os_platform_errno.c */, - 035877BE1DDCA45B000F61E2 /* os_platform_heap.c */, - 035877BF1DDCA45B000F61E2 /* os_platform_init.c */, - 035877C01DDCA45B000F61E2 /* os_platform_process.c */, - 035877C11DDCA45B000F61E2 /* os_platform_socket.c */, - 035877C21DDCA45B000F61E2 /* os_platform_stdlib.c */, - 035877C31DDCA45B000F61E2 /* os_platform_sync.c */, - 035877C41DDCA45B000F61E2 /* os_platform_thread.c */, - 035877C51DDCA45B000F61E2 /* os_platform_time.c */, - ); - path = posix; - sourceTree = ""; - }; - 035877D81DDCA54F000F61E2 /* posix */ = { - isa = PBXGroup; - children = ( - 035877D91DDCA54F000F61E2 /* os_platform_public.h */, - 035877DA1DDCA54F000F61E2 /* os_platform_socket.h */, - 035877DB1DDCA54F000F61E2 /* os_platform_stdlib.h */, - 035877DC1DDCA54F000F61E2 /* os_platform_sync.h */, - 035877DD1DDCA54F000F61E2 /* os_platform_thread.h */, - ); - path = posix; - sourceTree = ""; - }; - 035877DE1DDCA54F000F61E2 /* linux */ = { - isa = PBXGroup; - children = ( - 035877DF1DDCA54F000F61E2 /* os_platform.h */, - ); - path = linux; - sourceTree = ""; - }; - 037D2E7F1CD24583004434B2 /* win32 */ = { - isa = PBXGroup; - children = ( - 037D2E801CD245BB004434B2 /* os_platform_public.h */, - 037D2E811CD245BB004434B2 /* os_platform_socket.h */, - 037D2E821CD245BB004434B2 /* os_platform_stdlib.h */, - 037D2E831CD245BB004434B2 /* os_platform_sync.h */, - 037D2E841CD245BB004434B2 /* os_platform_thread.h */, - 037D2E851CD245BB004434B2 /* os_platform_time.h */, - 037D2E861CD245BB004434B2 /* os_platform.h */, - ); - path = win32; - sourceTree = ""; - }; - 03E6CE951CCE0C6B00D73982 = { - isa = PBXGroup; - children = ( - 035877B71DDB0A20000F61E2 /* lite.xml */, - 035877B81DDB0A20000F61E2 /* config.mk */, - 035877B91DDB0A20000F61E2 /* guess-config */, - 035877BA1DDB0A20000F61E2 /* makefile */, - 03C96EA81CCF6D030012F15D /* libevent-2.0.5.dylib */, - 03C96EA61CCE5CD20012F15D /* libevent_pthreads-2.0.5.dylib */, - 03E6CEC11CCE0DAB00D73982 /* include */, - 03E6CF461CCE0DAB00D73982 /* src */, - 03E6CFCC1CCE0DAB00D73982 /* vdds-server */, - 03E6CEB51CCE0DAB00D73982 /* examples */, - 03E6CF401CCE0DAB00D73982 /* rpc-examples */, - 03E6CE9F1CCE0C6B00D73982 /* Products */, - ); - sourceTree = ""; - }; - 03E6CE9F1CCE0C6B00D73982 /* Products */ = { - isa = PBXGroup; - children = ( - 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */, - 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */, - 03E6D0531CCE116900D73982 /* vdds-server */, - 03E6D0601CCE121300D73982 /* publisher */, - 03E6D06B1CCE121A00D73982 /* subscriber */, - 03E6D0761CCE121F00D73982 /* ping */, - 03E6D0811CCE122400D73982 /* pong */, - 03E6D08C1CCE122A00D73982 /* rpc-publisher */, - 03E6D0971CCE123000D73982 /* rpc-subscriber */, - 03E6D0A21CCE123500D73982 /* rpc-ping */, - 03E6D0AD1CCE123A00D73982 /* rpc-pong */, - 03C96EA41CCE5B8D0012F15D /* vdds-server2 */, - 033520471CEDD22A003E7429 /* rpc-pingpong */, - 036D258D1DF15EBA009A18C5 /* ddpingpong */, - ); - name = Products; - sourceTree = ""; - }; - 03E6CEB51CCE0DAB00D73982 /* examples */ = { - isa = PBXGroup; - children = ( - 036D25821DF15EAF009A18C5 /* ddpingpong.c */, - 03E6CEB61CCE0DAB00D73982 /* generated */, - 03E6CEBD1CCE0DAB00D73982 /* ping.c */, - 03E6CEBE1CCE0DAB00D73982 /* pong.c */, - 03E6CEBF1CCE0DAB00D73982 /* publisher.c */, - 03E6CEC01CCE0DAB00D73982 /* subscriber.c */, - ); - indentWidth = 4; - name = examples; - path = ../examples; - sourceTree = ""; - }; - 03E6CEB61CCE0DAB00D73982 /* generated */ = { - isa = PBXGroup; - children = ( - 03E6CEB71CCE0DAB00D73982 /* RoundTrip.c */, - 03E6CEB81CCE0DAB00D73982 /* RoundTrip.h */, - 03E6CEB91CCE0DAB00D73982 /* RoundTrip.idl */, - 03E6CEBA1CCE0DAB00D73982 /* Throughput.c */, - 03E6CEBB1CCE0DAB00D73982 /* Throughput.h */, - 03E6CEBC1CCE0DAB00D73982 /* Throughput.idl */, - ); - path = generated; - sourceTree = ""; - }; - 03E6CEC11CCE0DAB00D73982 /* include */ = { - isa = PBXGroup; - children = ( - 03E6CEC21CCE0DAB00D73982 /* dds */, - 03E6CED21CCE0DAB00D73982 /* dds.h */, - 03E6CED31CCE0DAB00D73982 /* ddsi */, - 03E6CF041CCE0DAB00D73982 /* kernel */, - 03E6CF1F1CCE0DAB00D73982 /* os */, - 03E6CF381CCE0DAB00D73982 /* util */, - ); - name = include; - path = ../include; - sourceTree = ""; - }; - 03E6CEC21CCE0DAB00D73982 /* dds */ = { - isa = PBXGroup; - children = ( - 03E6CEC31CCE0DAB00D73982 /* dds_public_alloc.h */, - 03E6CEC41CCE0DAB00D73982 /* dds_public_error.h */, - 03E6CEC51CCE0DAB00D73982 /* dds_public_impl.h */, - 03E6CEC61CCE0DAB00D73982 /* dds_public_log.h */, - 03E6CEC71CCE0DAB00D73982 /* dds_public_qos.h */, - 03E6CEC81CCE0DAB00D73982 /* dds_public_status.h */, - 03E6CEC91CCE0DAB00D73982 /* dds_public_stream.h */, - 03E6CECA1CCE0DAB00D73982 /* dds_public_time.h */, - 03E6CECB1CCE0DAB00D73982 /* os */, - ); - path = dds; - sourceTree = ""; - }; - 03E6CECB1CCE0DAB00D73982 /* os */ = { - isa = PBXGroup; - children = ( - 03E6CECC1CCE0DAB00D73982 /* linux */, - 03E6CECD1CCE0DAB00D73982 /* osx */, - 03E6CECE1CCE0DAB00D73982 /* qnx */, - 03E6CECF1CCE0DAB00D73982 /* solaris */, - 03E6CED01CCE0DAB00D73982 /* vxworks */, - 03E6CED11CCE0DAB00D73982 /* win32 */, - ); - path = os; - sourceTree = ""; - }; - 03E6CECC1CCE0DAB00D73982 /* linux */ = { - isa = PBXGroup; - children = ( - ); - path = linux; - sourceTree = ""; - }; - 03E6CECD1CCE0DAB00D73982 /* osx */ = { - isa = PBXGroup; - children = ( - ); - path = osx; - sourceTree = ""; - }; - 03E6CECE1CCE0DAB00D73982 /* qnx */ = { - isa = PBXGroup; - children = ( - ); - path = qnx; - sourceTree = ""; - }; - 03E6CECF1CCE0DAB00D73982 /* solaris */ = { - isa = PBXGroup; - children = ( - ); - path = solaris; - sourceTree = ""; - }; - 03E6CED01CCE0DAB00D73982 /* vxworks */ = { - isa = PBXGroup; - children = ( - ); - path = vxworks; - sourceTree = ""; - }; - 03E6CED11CCE0DAB00D73982 /* win32 */ = { - isa = PBXGroup; - children = ( - ); - path = win32; - sourceTree = ""; - }; - 03E6CED31CCE0DAB00D73982 /* ddsi */ = { - isa = PBXGroup; - children = ( - 03E6CED41CCE0DAB00D73982 /* ddsi_ser.h */, - 03E6CED51CCE0DAB00D73982 /* ddsi_ssl.h */, - 03E6CED61CCE0DAB00D73982 /* ddsi_tcp.h */, - 03E6CED71CCE0DAB00D73982 /* ddsi_tran.h */, - 03E6CED81CCE0DAB00D73982 /* ddsi_udp.h */, - 03E6CED91CCE0DAB00D73982 /* probes-constants.h */, - 03E6CEDA1CCE0DAB00D73982 /* q_addrset.h */, - 03E6CEDB1CCE0DAB00D73982 /* q_align.h */, - 0335204B1CEF4B21003E7429 /* q_bitset_template.h */, - 03E6CEDC1CCE0DAB00D73982 /* q_bitset.h */, - 0335204C1CEF4B21003E7429 /* q_bswap_template.h */, - 03E6CEDD1CCE0DAB00D73982 /* q_bswap.h */, - 03E6CEDE1CCE0DAB00D73982 /* q_builtin_topic.h */, - 03E6CEDF1CCE0DAB00D73982 /* q_config.h */, - 03E6CEE01CCE0DAB00D73982 /* q_ddsi_discovery.h */, - 03E6CEE11CCE0DAB00D73982 /* q_debmon.h */, - 03E6CEE21CCE0DAB00D73982 /* q_entity.h */, - 03E6CEE31CCE0DAB00D73982 /* q_ephash.h */, - 03E6CEE41CCE0DAB00D73982 /* q_error.h */, - 03E6CEE51CCE0DAB00D73982 /* q_feature_check.h */, - 03E6CEE61CCE0DAB00D73982 /* q_gc.h */, - 03E6CEE71CCE0DAB00D73982 /* q_globals.h */, - 03E6CEE81CCE0DAB00D73982 /* q_hbcontrol.h */, - 03E6CEE91CCE0DAB00D73982 /* q_inline.h */, - 03E6CEEA1CCE0DAB00D73982 /* q_lat_estim.h */, - 03E6CEEB1CCE0DAB00D73982 /* q_lease.h */, - 03E6CEEC1CCE0DAB00D73982 /* q_log.h */, - 03E6CEED1CCE0DAB00D73982 /* q_md5.h */, - 03E6CEEE1CCE0DAB00D73982 /* q_misc.h */, - 03E6CEEF1CCE0DAB00D73982 /* q_nwif.h */, - 03E6CEF01CCE0DAB00D73982 /* q_pcap.h */, - 03E6CEF11CCE0DAB00D73982 /* q_plist.h */, - 03E6CEF21CCE0DAB00D73982 /* q_protocol.h */, - 03E6CEF31CCE0DAB00D73982 /* q_qosmatch.h */, - 03E6CEF41CCE0DAB00D73982 /* q_radmin.h */, - 03E6CEF51CCE0DAB00D73982 /* q_receive.h */, - 03E6CEF61CCE0DAB00D73982 /* q_rtps.h */, - 03E6CEF71CCE0DAB00D73982 /* q_security.h */, - 03E6CEF81CCE0DAB00D73982 /* q_servicelease.h */, - 03E6CEF91CCE0DAB00D73982 /* q_sockwaitset.h */, - 03E6CEFA1CCE0DAB00D73982 /* q_static_assert.h */, - 0335204D1CEF4B21003E7429 /* q_thread_template.h */, - 03E6CEFB1CCE0DAB00D73982 /* q_thread.h */, - 034CF9301DE2FDF300DD6073 /* q_freelist.h */, - 03E6CEFC1CCE0DAB00D73982 /* q_time.h */, - 03E6CEFD1CCE0DAB00D73982 /* q_transmit.h */, - 03E6CEFE1CCE0DAB00D73982 /* q_unused.h */, - 03E6CEFF1CCE0DAB00D73982 /* q_whc.h */, - 03E6CF001CCE0DAB00D73982 /* q_xevent.h */, - 03E6CF011CCE0DAB00D73982 /* q_xmsg.h */, - 03E6CF021CCE0DAB00D73982 /* q_xqos.h */, - 03E6CF031CCE0DAB00D73982 /* sysdeps.h */, - ); - path = ddsi; - sourceTree = ""; - }; - 03E6CF041CCE0DAB00D73982 /* kernel */ = { - isa = PBXGroup; - children = ( - 03E6CF051CCE0DAB00D73982 /* dds_alloc.h */, - 03E6CF061CCE0DAB00D73982 /* dds_condition.h */, - 03E6CF071CCE0DAB00D73982 /* dds_domain.h */, - 03E6CF081CCE0DAB00D73982 /* dds_entity.h */, - 03E6CF091CCE0DAB00D73982 /* dds_export.h */, - 03E6CF0A1CCE0DAB00D73982 /* dds_guardcond.h */, - 03E6CF0B1CCE0DAB00D73982 /* dds_iid.h */, - 03E6CF0C1CCE0DAB00D73982 /* dds_init.h */, - 03E6CF0D1CCE0DAB00D73982 /* dds_key.h */, - 03E6CF0E1CCE0DAB00D73982 /* dds_listener.h */, - 03E6CF0F1CCE0DAB00D73982 /* dds_participant.h */, - 03E6CF101CCE0DAB00D73982 /* dds_qos.h */, - 03E6CF111CCE0DAB00D73982 /* dds_querycond.h */, - 03E6CF121CCE0DAB00D73982 /* dds_readcond.h */, - 03E6CF131CCE0DAB00D73982 /* dds_reader.h */, - 03E6CF141CCE0DAB00D73982 /* dds_rhc.h */, - 03E6CF151CCE0DAB00D73982 /* dds_status.h */, - 03E6CF161CCE0DAB00D73982 /* dds_statuscond.h */, - 03E6CF171CCE0DAB00D73982 /* dds_stream.h */, - 03E6CF181CCE0DAB00D73982 /* dds_tkmap.h */, - 03E6CF191CCE0DAB00D73982 /* dds_topic.h */, - 03E6CF1A1CCE0DAB00D73982 /* dds_types.h */, - 03E6CF1B1CCE0DAB00D73982 /* dds_waitset.h */, - 03E6CF1C1CCE0DAB00D73982 /* dds_write.h */, - 03E6CF1D1CCE0DAB00D73982 /* dds_writer.h */, - 03E6CF1E1CCE0DAB00D73982 /* q_osplser.h */, - ); - path = kernel; - sourceTree = ""; - }; - 03E6CF1F1CCE0DAB00D73982 /* os */ = { - isa = PBXGroup; - children = ( - 035877D81DDCA54F000F61E2 /* posix */, - 035877DE1DDCA54F000F61E2 /* linux */, - 037D2E7F1CD24583004434B2 /* win32 */, - 03E6CF201CCE0DAB00D73982 /* darwin */, - 03E6CF271CCE0DAB00D73982 /* os.h */, - 03E6CF281CCE0DAB00D73982 /* os_atomics.h */, - 03E6CF291CCE0DAB00D73982 /* os_atomics_gcc.h */, - 037D2E771CD24576004434B2 /* os_atomics_win32.h */, - 03E6CF2A1CCE0DAB00D73982 /* os_decl_attributes.h */, - 03E6CF2B1CCE0DAB00D73982 /* os_decl_attributes_sal.h */, - 03E6CF2C1CCE0DAB00D73982 /* os_defs.h */, - 03E6CF2D1CCE0DAB00D73982 /* os_errno.h */, - 03E6CF2E1CCE0DAB00D73982 /* os_heap.h */, - 03E6CF2F1CCE0DAB00D73982 /* os_init.h */, - 03E6CF301CCE0DAB00D73982 /* os_process.h */, - 03E6CF311CCE0DAB00D73982 /* os_public.h */, - 03E6CF321CCE0DAB00D73982 /* os_report.h */, - 03E6CF331CCE0DAB00D73982 /* os_socket.h */, - 03E6CF341CCE0DAB00D73982 /* os_stdlib.h */, - 03E6CF351CCE0DAB00D73982 /* os_sync.h */, - 03E6CF361CCE0DAB00D73982 /* os_thread.h */, - 03E6CF371CCE0DAB00D73982 /* os_time.h */, - ); - path = os; - sourceTree = ""; - }; - 03E6CF201CCE0DAB00D73982 /* darwin */ = { - isa = PBXGroup; - children = ( - 03E6CF211CCE0DAB00D73982 /* os_platform.h */, - ); - path = darwin; - sourceTree = ""; - }; - 03E6CF381CCE0DAB00D73982 /* util */ = { - isa = PBXGroup; - children = ( - 03E6CF391CCE0DAB00D73982 /* ut_avl.h */, - 03E6CF3A1CCE0DAB00D73982 /* ut_crc.h */, - 03E6CF3B1CCE0DAB00D73982 /* ut_expand_envvars.h */, - 03E6CF3C1CCE0DAB00D73982 /* ut_fibheap.h */, - 03E6CF3D1CCE0DAB00D73982 /* ut_hopscotch.h */, - 03E6CF3E1CCE0DAB00D73982 /* ut_thread_pool.h */, - 03E6CF3F1CCE0DAB00D73982 /* ut_xmlparser.h */, - ); - path = util; - sourceTree = ""; - }; - 03E6CF401CCE0DAB00D73982 /* rpc-examples */ = { - isa = PBXGroup; - children = ( - 03E6CF421CCE0DAB00D73982 /* rpc-ping.c */, - 03E6CF431CCE0DAB00D73982 /* rpc-pong.c */, - 03E6CF441CCE0DAB00D73982 /* rpc-publisher.c */, - 03E6CF451CCE0DAB00D73982 /* rpc-subscriber.c */, - 0335203C1CEDD031003E7429 /* rpc-pingpong.c */, - ); - indentWidth = 2; - name = "rpc-examples"; - path = "../rpc-examples"; - sourceTree = ""; - }; - 03E6CF461CCE0DAB00D73982 /* src */ = { - isa = PBXGroup; - children = ( - 03E6CF471CCE0DAB00D73982 /* ddsi */, - 03E6CF711CCE0DAB00D73982 /* kernel */, - 03E6CF921CCE0DAB00D73982 /* os */, - 03E6CFC41CCE0DAB00D73982 /* util */, - ); - name = src; - path = ../src; - sourceTree = ""; - }; - 03E6CF471CCE0DAB00D73982 /* ddsi */ = { - isa = PBXGroup; - children = ( - 03E6CF481CCE0DAB00D73982 /* ddsi_ser.c */, - 03E6CF491CCE0DAB00D73982 /* ddsi_ssl.c */, - 03E6CF4A1CCE0DAB00D73982 /* ddsi_tcp.c */, - 03E6CF4B1CCE0DAB00D73982 /* ddsi_tran.c */, - 03E6CF4C1CCE0DAB00D73982 /* ddsi_udp.c */, - 03E6CF4D1CCE0DAB00D73982 /* q_addrset.c */, - 03E6CF4E1CCE0DAB00D73982 /* q_bitset_inlines.c */, - 03E6CF501CCE0DAB00D73982 /* q_bswap.c */, - 03E6CF511CCE0DAB00D73982 /* q_bswap_inlines.c */, - 03E6CF531CCE0DAB00D73982 /* q_config.c */, - 03E6CF541CCE0DAB00D73982 /* q_ddsi_discovery.c */, - 03E6CF551CCE0DAB00D73982 /* q_debmon.c */, - 03E6CF561CCE0DAB00D73982 /* q_entity.c */, - 03E6CF571CCE0DAB00D73982 /* q_ephash.c */, - 03E6CF581CCE0DAB00D73982 /* q_gc.c */, - 03E6CF591CCE0DAB00D73982 /* q_init.c */, - 03E6CF5A1CCE0DAB00D73982 /* q_lat_estim.c */, - 03E6CF5B1CCE0DAB00D73982 /* q_lease.c */, - 03E6CF5C1CCE0DAB00D73982 /* q_log.c */, - 03E6CF5D1CCE0DAB00D73982 /* q_md5.c */, - 03E6CF5E1CCE0DAB00D73982 /* q_misc.c */, - 03E6CF5F1CCE0DAB00D73982 /* q_nwif.c */, - 03E6CF601CCE0DAB00D73982 /* q_pcap.c */, - 03E6CF611CCE0DAB00D73982 /* q_plist.c */, - 03E6CF621CCE0DAB00D73982 /* q_qosmatch.c */, - 03E6CF631CCE0DAB00D73982 /* q_radmin.c */, - 03E6CF641CCE0DAB00D73982 /* q_receive.c */, - 03E6CF651CCE0DAB00D73982 /* q_security.c */, - 03E6CF661CCE0DAB00D73982 /* q_servicelease.c */, - 03E6CF671CCE0DAB00D73982 /* q_sockwaitset.c */, - 03E6CF681CCE0DAB00D73982 /* q_thread.c */, - 03E6CF691CCE0DAB00D73982 /* q_thread_inlines.c */, - 03E6CF6B1CCE0DAB00D73982 /* q_time.c */, - 03E6CF6C1CCE0DAB00D73982 /* q_transmit.c */, - 03E6CF6D1CCE0DAB00D73982 /* q_whc.c */, - 03E6CF6E1CCE0DAB00D73982 /* q_xevent.c */, - 03E6CF6F1CCE0DAB00D73982 /* q_xmsg.c */, - 03E6CF701CCE0DAB00D73982 /* sysdeps.c */, - 034CF92F1DE2FDF300DD6073 /* q_freelist.c */, - ); - path = ddsi; - sourceTree = ""; - }; - 03E6CF711CCE0DAB00D73982 /* kernel */ = { - isa = PBXGroup; - children = ( - 03E6CF721CCE0DAB00D73982 /* dds_alloc.c */, - 03E6CF731CCE0DAB00D73982 /* dds_condition.c */, - 03E6CF741CCE0DAB00D73982 /* dds_domain.c */, - 03E6CF751CCE0DAB00D73982 /* dds_entity.c */, - 03E6CF761CCE0DAB00D73982 /* dds_err.c */, - 03E6CF771CCE0DAB00D73982 /* dds_guardcond.c */, - 03E6CF781CCE0DAB00D73982 /* dds_iid.c */, - 03E6CF791CCE0DAB00D73982 /* dds_init.c */, - 03E6CF7A1CCE0DAB00D73982 /* dds_instance.c */, - 03E6CF7B1CCE0DAB00D73982 /* dds_key.c */, - 03E6CF7C1CCE0DAB00D73982 /* dds_listener.c */, - 03E6CF7D1CCE0DAB00D73982 /* dds_log.c */, - 03E6CF7E1CCE0DAB00D73982 /* dds_participant.c */, - 03E6CF7F1CCE0DAB00D73982 /* dds_publisher.c */, - 03E6CF801CCE0DAB00D73982 /* dds_qos.c */, - 03E6CF811CCE0DAB00D73982 /* dds_querycond.c */, - 03E6CF821CCE0DAB00D73982 /* dds_read.c */, - 03E6CF831CCE0DAB00D73982 /* dds_readcond.c */, - 03E6CF841CCE0DAB00D73982 /* dds_reader.c */, - 03E6CF851CCE0DAB00D73982 /* dds_rhc.c */, - 03E6CF861CCE0DAB00D73982 /* dds_status.c */, - 03E6CF871CCE0DAB00D73982 /* dds_statuscond.c */, - 03E6CF881CCE0DAB00D73982 /* dds_stream.c */, - 03E6CF891CCE0DAB00D73982 /* dds_subscriber.c */, - 03E6CF8A1CCE0DAB00D73982 /* dds_thread.c */, - 03E6CF8B1CCE0DAB00D73982 /* dds_time.c */, - 03E6CF8C1CCE0DAB00D73982 /* dds_tkmap.c */, - 03E6CF8D1CCE0DAB00D73982 /* dds_topic.c */, - 03E6CF8E1CCE0DAB00D73982 /* dds_waitset.c */, - 03E6CF8F1CCE0DAB00D73982 /* dds_write.c */, - 03E6CF901CCE0DAB00D73982 /* dds_writer.c */, - 03E6CF911CCE0DAB00D73982 /* q_osplser.c */, - ); - path = kernel; - sourceTree = ""; - }; - 03E6CF921CCE0DAB00D73982 /* os */ = { - isa = PBXGroup; - children = ( - 035877BC1DDCA45B000F61E2 /* posix */, - 03E6CF9E1CCE0DAB00D73982 /* os_atomics.c */, - 03E6CF9F1CCE0DAB00D73982 /* os_init.c */, - 03E6CFA01CCE0DAB00D73982 /* os_report.c */, - 03E6CFA11CCE0DAB00D73982 /* os_socket.c */, - 03E6CFA21CCE0DAB00D73982 /* os_sync.c */, - 03E6CFA31CCE0DAB00D73982 /* os_thread.c */, - 03E6CFA41CCE0DAB00D73982 /* os_time.c */, - 03E6CFA51CCE0DAB00D73982 /* snippets */, - 03E6CFB41CCE0DAB00D73982 /* win32 */, - ); - path = os; - sourceTree = ""; - }; - 03E6CFA51CCE0DAB00D73982 /* snippets */ = { - isa = PBXGroup; - children = ( - 03E6CFA61CCE0DAB00D73982 /* code */, - 03E6CFB21CCE0DAB00D73982 /* include */, - ); - path = snippets; - sourceTree = ""; - }; - 03E6CFA61CCE0DAB00D73982 /* code */ = { - isa = PBXGroup; - children = ( - 03E6CFA71CCE0DAB00D73982 /* os_gethostname.c */, - 03E6CFA81CCE0DAB00D73982 /* os_heap.c */, - 03E6CFA91CCE0DAB00D73982 /* os_posix_errno.c */, - 03E6CFAA1CCE0DAB00D73982 /* os_posix_process.c */, - 03E6CFAB1CCE0DAB00D73982 /* os_posix_thread.c */, - 03E6CFAC1CCE0DAB00D73982 /* os_stdlib.c */, - 03E6CFAD1CCE0DAB00D73982 /* os_stdlib_bsearch.c */, - 03E6CFAE1CCE0DAB00D73982 /* os_stdlib_strsep.c */, - 03E6CFAF1CCE0DAB00D73982 /* os_stdlib_strtod.c */, - 03E6CFB01CCE0DAB00D73982 /* os_stdlib_strtok_r.c */, - 03E6CFB11CCE0DAB00D73982 /* os_stdlib_strtol.c */, - ); - path = code; - sourceTree = ""; - }; - 03E6CFB21CCE0DAB00D73982 /* include */ = { - isa = PBXGroup; - children = ( - 03E6CFB31CCE0DAB00D73982 /* os_posix_stdlib.h */, - ); - path = include; - sourceTree = ""; - }; - 03E6CFB41CCE0DAB00D73982 /* win32 */ = { - isa = PBXGroup; - children = ( - 037D2E711CD2455A004434B2 /* os_platform_heap.c */, - 037D2E721CD2455A004434B2 /* os_platform_init.c */, - 037D2E731CD2455A004434B2 /* os_platform_socket.c */, - 037D2E741CD2455A004434B2 /* os_platform_sync.c */, - 037D2E751CD2455A004434B2 /* os_platform_thread.c */, - 037D2E761CD2455A004434B2 /* os_platform_time.c */, - ); - path = win32; - sourceTree = ""; - }; - 03E6CFC41CCE0DAB00D73982 /* util */ = { - isa = PBXGroup; - children = ( - 03E6CFC51CCE0DAB00D73982 /* ut_avl.c */, - 03E6CFC61CCE0DAB00D73982 /* ut_crc.c */, - 03E6CFC71CCE0DAB00D73982 /* ut_expand_envvars.c */, - 03E6CFC81CCE0DAB00D73982 /* ut_fibheap.c */, - 03E6CFC91CCE0DAB00D73982 /* ut_hopscotch.c */, - 03E6CFCA1CCE0DAB00D73982 /* ut_thread_pool.c */, - 03E6CFCB1CCE0DAB00D73982 /* ut_xmlparser.c */, - ); - path = util; - sourceTree = ""; - }; - 03E6CFCC1CCE0DAB00D73982 /* vdds-server */ = { - isa = PBXGroup; - children = ( - 03C96E9A1CCE5B800012F15D /* server2.c */, - 03E6CFCD1CCE0DAB00D73982 /* server.c */, - 03E6CFCE1CCE0DAB00D73982 /* server.h */, - 03E6CFCF1CCE0DAB00D73982 /* vdds-stubs.c */, - ); - indentWidth = 4; - name = "vdds-server"; - path = "../vdds-server"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 03E6CEA71CCE0CA400D73982 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 035877E21DDCA54F000F61E2 /* os_platform_stdlib.h in Headers */, - 034CF9321DE2FDF300DD6073 /* q_freelist.h in Headers */, - 035877E41DDCA54F000F61E2 /* os_platform_thread.h in Headers */, - 035877E11DDCA54F000F61E2 /* os_platform_socket.h in Headers */, - 035877E51DDCA54F000F61E2 /* os_platform.h in Headers */, - 035877E31DDCA54F000F61E2 /* os_platform_sync.h in Headers */, - 035877E01DDCA54F000F61E2 /* os_platform_public.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6CEAF1CCE0CCC00D73982 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 0335203D1CEDD22A003E7429 /* rpc-pingpong */ = { - isa = PBXNativeTarget; - buildConfigurationList = 033520441CEDD22A003E7429 /* Build configuration list for PBXNativeTarget "rpc-pingpong" */; - buildPhases = ( - 0335203E1CEDD22A003E7429 /* Sources */, - 033520411CEDD22A003E7429 /* Frameworks */, - 033520431CEDD22A003E7429 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "rpc-pingpong"; - productName = "rpc-ping"; - productReference = 033520471CEDD22A003E7429 /* rpc-pingpong */; - productType = "com.apple.product-type.tool"; - }; - 036D25831DF15EB9009A18C5 /* ddpingpong */ = { - isa = PBXNativeTarget; - buildConfigurationList = 036D258A1DF15EB9009A18C5 /* Build configuration list for PBXNativeTarget "ddpingpong" */; - buildPhases = ( - 036D25841DF15EB9009A18C5 /* Sources */, - 036D25871DF15EB9009A18C5 /* Frameworks */, - 036D25891DF15EB9009A18C5 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ddpingpong; - productName = ping; - productReference = 036D258D1DF15EBA009A18C5 /* ddpingpong */; - productType = "com.apple.product-type.tool"; - }; - 03C96E9B1CCE5B8D0012F15D /* vdds-server2 */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03C96EA11CCE5B8D0012F15D /* Build configuration list for PBXNativeTarget "vdds-server2" */; - buildPhases = ( - 03C96E9C1CCE5B8D0012F15D /* Sources */, - 03C96E9E1CCE5B8D0012F15D /* Frameworks */, - 03C96EA01CCE5B8D0012F15D /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "vdds-server2"; - productName = "vdds-server"; - productReference = 03C96EA41CCE5B8D0012F15D /* vdds-server2 */; - productType = "com.apple.product-type.tool"; - }; - 03E6CEA81CCE0CA400D73982 /* vdds */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6CEAA1CCE0CA400D73982 /* Build configuration list for PBXNativeTarget "vdds" */; - buildPhases = ( - 03E6CEA51CCE0CA400D73982 /* Sources */, - 03E6CEA61CCE0CA400D73982 /* Frameworks */, - 03E6CEA71CCE0CA400D73982 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = vdds; - productName = vdds; - productReference = 03E6CEA91CCE0CA400D73982 /* libvdds.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; - 03E6CEB01CCE0CCC00D73982 /* vdds-stubs */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6CEB21CCE0CCC00D73982 /* Build configuration list for PBXNativeTarget "vdds-stubs" */; - buildPhases = ( - 03E6CEAD1CCE0CCC00D73982 /* Sources */, - 03E6CEAE1CCE0CCC00D73982 /* Frameworks */, - 03E6CEAF1CCE0CCC00D73982 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "vdds-stubs"; - productName = "vdds-stubs"; - productReference = 03E6CEB11CCE0CCC00D73982 /* libvdds-stubs.dylib */; - productType = "com.apple.product-type.library.dynamic"; - }; - 03E6D0521CCE116900D73982 /* vdds-server */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0571CCE116900D73982 /* Build configuration list for PBXNativeTarget "vdds-server" */; - buildPhases = ( - 03E6D04F1CCE116900D73982 /* Sources */, - 03E6D0501CCE116900D73982 /* Frameworks */, - 03E6D0511CCE116900D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "vdds-server"; - productName = "vdds-server"; - productReference = 03E6D0531CCE116900D73982 /* vdds-server */; - productType = "com.apple.product-type.tool"; - }; - 03E6D05F1CCE121300D73982 /* publisher */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0641CCE121300D73982 /* Build configuration list for PBXNativeTarget "publisher" */; - buildPhases = ( - 03E6D05C1CCE121300D73982 /* Sources */, - 03E6D05D1CCE121300D73982 /* Frameworks */, - 03E6D05E1CCE121300D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = publisher; - productName = publisher; - productReference = 03E6D0601CCE121300D73982 /* publisher */; - productType = "com.apple.product-type.tool"; - }; - 03E6D06A1CCE121A00D73982 /* subscriber */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D06F1CCE121A00D73982 /* Build configuration list for PBXNativeTarget "subscriber" */; - buildPhases = ( - 03E6D0671CCE121A00D73982 /* Sources */, - 03E6D0681CCE121A00D73982 /* Frameworks */, - 03E6D0691CCE121A00D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = subscriber; - productName = subscriber; - productReference = 03E6D06B1CCE121A00D73982 /* subscriber */; - productType = "com.apple.product-type.tool"; - }; - 03E6D0751CCE121F00D73982 /* ping */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D07A1CCE121F00D73982 /* Build configuration list for PBXNativeTarget "ping" */; - buildPhases = ( - 03E6D0721CCE121F00D73982 /* Sources */, - 03E6D0731CCE121F00D73982 /* Frameworks */, - 03E6D0741CCE121F00D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ping; - productName = ping; - productReference = 03E6D0761CCE121F00D73982 /* ping */; - productType = "com.apple.product-type.tool"; - }; - 03E6D0801CCE122400D73982 /* pong */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0851CCE122400D73982 /* Build configuration list for PBXNativeTarget "pong" */; - buildPhases = ( - 03E6D07D1CCE122400D73982 /* Sources */, - 03E6D07E1CCE122400D73982 /* Frameworks */, - 03E6D07F1CCE122400D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = pong; - productName = pong; - productReference = 03E6D0811CCE122400D73982 /* pong */; - productType = "com.apple.product-type.tool"; - }; - 03E6D08B1CCE122A00D73982 /* rpc-publisher */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0901CCE122A00D73982 /* Build configuration list for PBXNativeTarget "rpc-publisher" */; - buildPhases = ( - 03E6D0881CCE122A00D73982 /* Sources */, - 03E6D0891CCE122A00D73982 /* Frameworks */, - 03E6D08A1CCE122A00D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "rpc-publisher"; - productName = "rpc-publisher"; - productReference = 03E6D08C1CCE122A00D73982 /* rpc-publisher */; - productType = "com.apple.product-type.tool"; - }; - 03E6D0961CCE123000D73982 /* rpc-subscriber */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D09B1CCE123000D73982 /* Build configuration list for PBXNativeTarget "rpc-subscriber" */; - buildPhases = ( - 03E6D0931CCE123000D73982 /* Sources */, - 03E6D0941CCE123000D73982 /* Frameworks */, - 03E6D0951CCE123000D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "rpc-subscriber"; - productName = "rpc-subscriber"; - productReference = 03E6D0971CCE123000D73982 /* rpc-subscriber */; - productType = "com.apple.product-type.tool"; - }; - 03E6D0A11CCE123500D73982 /* rpc-ping */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0A61CCE123500D73982 /* Build configuration list for PBXNativeTarget "rpc-ping" */; - buildPhases = ( - 03E6D09E1CCE123500D73982 /* Sources */, - 03E6D09F1CCE123500D73982 /* Frameworks */, - 03E6D0A01CCE123500D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "rpc-ping"; - productName = "rpc-ping"; - productReference = 03E6D0A21CCE123500D73982 /* rpc-ping */; - productType = "com.apple.product-type.tool"; - }; - 03E6D0AC1CCE123A00D73982 /* rpc-pong */ = { - isa = PBXNativeTarget; - buildConfigurationList = 03E6D0B11CCE123A00D73982 /* Build configuration list for PBXNativeTarget "rpc-pong" */; - buildPhases = ( - 03E6D0A91CCE123A00D73982 /* Sources */, - 03E6D0AA1CCE123A00D73982 /* Frameworks */, - 03E6D0AB1CCE123A00D73982 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "rpc-pong"; - productName = "rpc-pong"; - productReference = 03E6D0AD1CCE123A00D73982 /* rpc-pong */; - productType = "com.apple.product-type.tool"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 03E6CE961CCE0C6B00D73982 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0810; - ORGANIZATIONNAME = PrismTech; - TargetAttributes = { - 03E6CEA81CCE0CA400D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6CEB01CCE0CCC00D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0521CCE116900D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D05F1CCE121300D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D06A1CCE121A00D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0751CCE121F00D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0801CCE122400D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D08B1CCE122A00D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0961CCE123000D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0A11CCE123500D73982 = { - CreatedOnToolsVersion = 7.3; - }; - 03E6D0AC1CCE123A00D73982 = { - CreatedOnToolsVersion = 7.3; - }; - }; - }; - buildConfigurationList = 03E6CE991CCE0C6B00D73982 /* Build configuration list for PBXProject "vdds-xcode" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 03E6CE951CCE0C6B00D73982; - productRefGroup = 03E6CE9F1CCE0C6B00D73982 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 03E6CEA81CCE0CA400D73982 /* vdds */, - 03E6CEB01CCE0CCC00D73982 /* vdds-stubs */, - 03E6D0521CCE116900D73982 /* vdds-server */, - 03E6D05F1CCE121300D73982 /* publisher */, - 03E6D06A1CCE121A00D73982 /* subscriber */, - 03E6D0751CCE121F00D73982 /* ping */, - 03E6D0801CCE122400D73982 /* pong */, - 03E6D08B1CCE122A00D73982 /* rpc-publisher */, - 03E6D0961CCE123000D73982 /* rpc-subscriber */, - 03E6D0A11CCE123500D73982 /* rpc-ping */, - 03E6D0AC1CCE123A00D73982 /* rpc-pong */, - 03C96E9B1CCE5B8D0012F15D /* vdds-server2 */, - 0335203D1CEDD22A003E7429 /* rpc-pingpong */, - 036D25831DF15EB9009A18C5 /* ddpingpong */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXSourcesBuildPhase section */ - 0335203E1CEDD22A003E7429 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0335203F1CEDD22A003E7429 /* rpc-ping.c in Sources */, - 033520481CEDD242003E7429 /* rpc-pong.c in Sources */, - 033520491CEDD244003E7429 /* rpc-pingpong.c in Sources */, - 033520401CEDD22A003E7429 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 036D25841DF15EB9009A18C5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 036D258E1DF15ECA009A18C5 /* ddpingpong.c in Sources */, - 036D25861DF15EB9009A18C5 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03C96E9C1CCE5B8D0012F15D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03C96EA51CCE5B9F0012F15D /* server2.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6CEA51CCE0CA400D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0191CCE0DED00D73982 /* os_atomics.c in Sources */, - 03E6D01A1CCE0DED00D73982 /* os_init.c in Sources */, - 03E6D01B1CCE0DED00D73982 /* os_report.c in Sources */, - 03E6D01C1CCE0DED00D73982 /* os_socket.c in Sources */, - 03E6D01D1CCE0DED00D73982 /* os_sync.c in Sources */, - 035877CE1DDCA45B000F61E2 /* os_platform_time.c in Sources */, - 03E6D01E1CCE0DED00D73982 /* os_thread.c in Sources */, - 03E6D01F1CCE0DED00D73982 /* os_time.c in Sources */, - 03E6D0291CCE0E0500D73982 /* ut_avl.c in Sources */, - 03E6D02A1CCE0E0500D73982 /* ut_crc.c in Sources */, - 03E6D02B1CCE0E0500D73982 /* ut_expand_envvars.c in Sources */, - 035877CD1DDCA45B000F61E2 /* os_platform_thread.c in Sources */, - 035877C91DDCA45B000F61E2 /* os_platform_process.c in Sources */, - 03E6D02C1CCE0E0500D73982 /* ut_fibheap.c in Sources */, - 03E6D02D1CCE0E0500D73982 /* ut_hopscotch.c in Sources */, - 03E6D02E1CCE0E0500D73982 /* ut_thread_pool.c in Sources */, - 03E6D02F1CCE0E0500D73982 /* ut_xmlparser.c in Sources */, - 03E6CFF91CCE0DE300D73982 /* dds_alloc.c in Sources */, - 03E6CFFA1CCE0DE300D73982 /* dds_condition.c in Sources */, - 03E6CFFB1CCE0DE300D73982 /* dds_domain.c in Sources */, - 03E6CFFC1CCE0DE300D73982 /* dds_entity.c in Sources */, - 03E6CFFD1CCE0DE300D73982 /* dds_err.c in Sources */, - 035877CB1DDCA45B000F61E2 /* os_platform_stdlib.c in Sources */, - 03E6CFFE1CCE0DE300D73982 /* dds_guardcond.c in Sources */, - 03E6CFFF1CCE0DE300D73982 /* dds_iid.c in Sources */, - 035877CC1DDCA45B000F61E2 /* os_platform_sync.c in Sources */, - 035877C61DDCA45B000F61E2 /* os_platform_errno.c in Sources */, - 03E6D0001CCE0DE300D73982 /* dds_init.c in Sources */, - 03E6D0011CCE0DE300D73982 /* dds_instance.c in Sources */, - 03E6D0021CCE0DE300D73982 /* dds_key.c in Sources */, - 03E6D0031CCE0DE300D73982 /* dds_listener.c in Sources */, - 03E6D0041CCE0DE300D73982 /* dds_log.c in Sources */, - 035877C81DDCA45B000F61E2 /* os_platform_init.c in Sources */, - 03E6D0051CCE0DE300D73982 /* dds_participant.c in Sources */, - 03E6D0061CCE0DE300D73982 /* dds_publisher.c in Sources */, - 03E6D0071CCE0DE300D73982 /* dds_qos.c in Sources */, - 035877CA1DDCA45B000F61E2 /* os_platform_socket.c in Sources */, - 03E6D0081CCE0DE300D73982 /* dds_querycond.c in Sources */, - 03E6D0091CCE0DE300D73982 /* dds_read.c in Sources */, - 03E6D00A1CCE0DE300D73982 /* dds_readcond.c in Sources */, - 03E6D00B1CCE0DE300D73982 /* dds_reader.c in Sources */, - 03E6D00C1CCE0DE300D73982 /* dds_rhc.c in Sources */, - 03E6D00D1CCE0DE300D73982 /* dds_status.c in Sources */, - 03E6D00E1CCE0DE300D73982 /* dds_statuscond.c in Sources */, - 03E6D00F1CCE0DE300D73982 /* dds_stream.c in Sources */, - 03E6D0101CCE0DE300D73982 /* dds_subscriber.c in Sources */, - 03E6D0111CCE0DE300D73982 /* dds_thread.c in Sources */, - 03E6D0121CCE0DE300D73982 /* dds_time.c in Sources */, - 03E6D0131CCE0DE300D73982 /* dds_tkmap.c in Sources */, - 03E6D0141CCE0DE300D73982 /* dds_topic.c in Sources */, - 03E6D0151CCE0DE300D73982 /* dds_waitset.c in Sources */, - 035877C71DDCA45B000F61E2 /* os_platform_heap.c in Sources */, - 03E6D0161CCE0DE300D73982 /* dds_write.c in Sources */, - 03E6D0171CCE0DE300D73982 /* dds_writer.c in Sources */, - 03E6D0181CCE0DE300D73982 /* q_osplser.c in Sources */, - 03E6CFD01CCE0DD400D73982 /* ddsi_ser.c in Sources */, - 03E6CFD11CCE0DD400D73982 /* ddsi_ssl.c in Sources */, - 03E6CFD21CCE0DD400D73982 /* ddsi_tcp.c in Sources */, - 03E6CFD31CCE0DD400D73982 /* ddsi_tran.c in Sources */, - 03E6CFD41CCE0DD400D73982 /* ddsi_udp.c in Sources */, - 03E6CFD51CCE0DD400D73982 /* q_addrset.c in Sources */, - 03E6CFD61CCE0DD400D73982 /* q_bitset_inlines.c in Sources */, - 03E6CFD81CCE0DD400D73982 /* q_bswap.c in Sources */, - 03E6CFD91CCE0DD400D73982 /* q_bswap_inlines.c in Sources */, - 03E6CFDB1CCE0DD400D73982 /* q_config.c in Sources */, - 034CF9311DE2FDF300DD6073 /* q_freelist.c in Sources */, - 03E6CFDC1CCE0DD400D73982 /* q_ddsi_discovery.c in Sources */, - 03E6CFDD1CCE0DD400D73982 /* q_debmon.c in Sources */, - 03E6CFDE1CCE0DD400D73982 /* q_entity.c in Sources */, - 03E6CFDF1CCE0DD400D73982 /* q_ephash.c in Sources */, - 03E6CFE01CCE0DD400D73982 /* q_gc.c in Sources */, - 03E6CFE11CCE0DD400D73982 /* q_init.c in Sources */, - 03E6CFE21CCE0DD400D73982 /* q_lat_estim.c in Sources */, - 03E6CFE31CCE0DD400D73982 /* q_lease.c in Sources */, - 03E6CFE41CCE0DD400D73982 /* q_log.c in Sources */, - 03E6CFE51CCE0DD400D73982 /* q_md5.c in Sources */, - 03E6CFE61CCE0DD400D73982 /* q_misc.c in Sources */, - 03E6CFE71CCE0DD400D73982 /* q_nwif.c in Sources */, - 03E6CFE81CCE0DD400D73982 /* q_pcap.c in Sources */, - 03E6CFE91CCE0DD400D73982 /* q_plist.c in Sources */, - 03E6CFEA1CCE0DD400D73982 /* q_qosmatch.c in Sources */, - 03E6CFEB1CCE0DD400D73982 /* q_radmin.c in Sources */, - 03E6CFEC1CCE0DD400D73982 /* q_receive.c in Sources */, - 03E6CFED1CCE0DD400D73982 /* q_security.c in Sources */, - 03E6CFEE1CCE0DD400D73982 /* q_servicelease.c in Sources */, - 03E6CFEF1CCE0DD400D73982 /* q_sockwaitset.c in Sources */, - 03E6CFF01CCE0DD400D73982 /* q_thread.c in Sources */, - 03E6CFF11CCE0DD400D73982 /* q_thread_inlines.c in Sources */, - 03E6CFF31CCE0DD400D73982 /* q_time.c in Sources */, - 03E6CFF41CCE0DD400D73982 /* q_transmit.c in Sources */, - 03E6CFF51CCE0DD400D73982 /* q_whc.c in Sources */, - 03E6CFF61CCE0DD400D73982 /* q_xevent.c in Sources */, - 03E6CFF71CCE0DD400D73982 /* q_xmsg.c in Sources */, - 03E6CFF81CCE0DD400D73982 /* sysdeps.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6CEAD1CCE0CCC00D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 035877CF1DDCA477000F61E2 /* os_platform_errno.c in Sources */, - 035877D01DDCA477000F61E2 /* os_platform_heap.c in Sources */, - 035877D11DDCA477000F61E2 /* os_platform_init.c in Sources */, - 035877D21DDCA477000F61E2 /* os_platform_process.c in Sources */, - 035877D31DDCA477000F61E2 /* os_platform_socket.c in Sources */, - 035877D41DDCA477000F61E2 /* os_platform_stdlib.c in Sources */, - 035877D51DDCA477000F61E2 /* os_platform_sync.c in Sources */, - 035877D61DDCA477000F61E2 /* os_platform_thread.c in Sources */, - 035877D71DDCA477000F61E2 /* os_platform_time.c in Sources */, - 03E6D0391CCE0E6200D73982 /* os_atomics.c in Sources */, - 03E6D03A1CCE0E6200D73982 /* os_init.c in Sources */, - 03E6D03B1CCE0E6200D73982 /* os_report.c in Sources */, - 03E6D03C1CCE0E6200D73982 /* os_socket.c in Sources */, - 03E6D03D1CCE0E6200D73982 /* os_sync.c in Sources */, - 03E6D03E1CCE0E6200D73982 /* os_thread.c in Sources */, - 03E6D03F1CCE0E6200D73982 /* os_time.c in Sources */, - 03E6D0401CCE0E7000D73982 /* vdds-stubs.c in Sources */, - 03E6D0411CCE0EB700D73982 /* dds_alloc.c in Sources */, - 03E6D0421CCE0EBD00D73982 /* dds_time.c in Sources */, - 03E6D0431CCE0EC000D73982 /* dds_stream.c in Sources */, - 03E6D0441CCE0EC600D73982 /* dds_key.c in Sources */, - 03E6D0451CCE0ECB00D73982 /* dds_err.c in Sources */, - 03E6D0461CCE0ED000D73982 /* dds_qos.c in Sources */, - 03E6D0471CCE0EDE00D73982 /* q_bswap.c in Sources */, - 03E6D0481CCE0EE200D73982 /* q_bswap_inlines.c in Sources */, - 03E6D0491CCE0EE800D73982 /* q_md5.c in Sources */, - 03E6D04A1CCE0EEC00D73982 /* q_plist.c in Sources */, - 03E6D04B1CCE0EF100D73982 /* q_time.c in Sources */, - 03E6D04C1CCE104600D73982 /* q_misc.c in Sources */, - 03E6D04D1CCE104E00D73982 /* q_osplser.c in Sources */, - 034CF9331DE3043A00DD6073 /* q_freelist.c in Sources */, - 03E6D04E1CCE105600D73982 /* ddsi_ser.c in Sources */, - 035877BB1DDB0F5B000F61E2 /* sysdeps.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D04F1CCE116900D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D05A1CCE11D300D73982 /* server.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D05C1CCE121300D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0BC1CCE127500D73982 /* publisher.c in Sources */, - 03E6D0BD1CCE127800D73982 /* Throughput.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0671CCE121A00D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0BE1CCE127C00D73982 /* subscriber.c in Sources */, - 03E6D0BF1CCE127F00D73982 /* Throughput.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0721CCE121F00D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0C01CCE128500D73982 /* ping.c in Sources */, - 03E6D0C11CCE128700D73982 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D07D1CCE122400D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0C21CCE128D00D73982 /* pong.c in Sources */, - 03E6D0C31CCE128F00D73982 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0881CCE122A00D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0C41CCE129C00D73982 /* rpc-publisher.c in Sources */, - 03E6D0C51CCE129F00D73982 /* Throughput.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0931CCE123000D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0C61CCE12A400D73982 /* rpc-subscriber.c in Sources */, - 03E6D0C71CCE12A600D73982 /* Throughput.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D09E1CCE123500D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0C81CCE12AC00D73982 /* rpc-ping.c in Sources */, - 03E6D0C91CCE12AE00D73982 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 03E6D0A91CCE123A00D73982 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 03E6D0CA1CCE12B400D73982 /* rpc-pong.c in Sources */, - 03E6D0CB1CCE12B600D73982 /* RoundTrip.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 033520451CEDD22A003E7429 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 033520461CEDD22A003E7429 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 036D258B1DF15EB9009A18C5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 036D258C1DF15EB9009A18C5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03C96EA21CCE5B8D0012F15D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - HEADER_SEARCH_PATHS = /usr/local/include; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - /usr/local/Cellar/libevent/2.0.22/lib, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = "../include ../examples/generated"; - }; - name = Debug; - }; - 03C96EA31CCE5B8D0012F15D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - HEADER_SEARCH_PATHS = /usr/local/include; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - /usr/local/Cellar/libevent/2.0.22/lib, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - USER_HEADER_SEARCH_PATHS = "../include ../examples/generated"; - }; - name = Release; - }; - 03E6CEA01CCE0C6B00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DDSI_INCLUDE_NETWORK_PARTITIONS=1", - "DDSI_INCLUDE_BANDWIDTH_LIMITING=1", - "DDSI_INCLUDE_NETWORK_CHANNELS=1", - "DDSI_INCLUDE_SSM=1", - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - USER_HEADER_SEARCH_PATHS = "../include ../examples/generated"; - USE_HEADERMAP = NO; - }; - name = Debug; - }; - 03E6CEA11CCE0C6B00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - USER_HEADER_SEARCH_PATHS = "../include ../examples/generated"; - USE_HEADERMAP = NO; - }; - name = Release; - }; - 03E6CEAB1CCE0CA400D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - EXECUTABLE_PREFIX = lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6CEAC1CCE0CA400D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - EXECUTABLE_PREFIX = lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6CEB31CCE0CCC00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - EXECUTABLE_PREFIX = lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6CEB41CCE0CCC00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - EXECUTABLE_PREFIX = lib; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0581CCE116900D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0591CCE116900D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0651CCE121300D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0661CCE121300D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0701CCE121A00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0711CCE121A00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D07B1CCE121F00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D07C1CCE121F00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0861CCE122400D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0871CCE122400D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0911CCE122A00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0921CCE122A00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D09C1CCE123000D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D09D1CCE123000D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0A71CCE123500D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0A81CCE123500D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; - 03E6D0B21CCE123A00D73982 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 03E6D0B31CCE123A00D73982 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 033520441CEDD22A003E7429 /* Build configuration list for PBXNativeTarget "rpc-pingpong" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 033520451CEDD22A003E7429 /* Debug */, - 033520461CEDD22A003E7429 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 036D258A1DF15EB9009A18C5 /* Build configuration list for PBXNativeTarget "ddpingpong" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 036D258B1DF15EB9009A18C5 /* Debug */, - 036D258C1DF15EB9009A18C5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03C96EA11CCE5B8D0012F15D /* Build configuration list for PBXNativeTarget "vdds-server2" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03C96EA21CCE5B8D0012F15D /* Debug */, - 03C96EA31CCE5B8D0012F15D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6CE991CCE0C6B00D73982 /* Build configuration list for PBXProject "vdds-xcode" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6CEA01CCE0C6B00D73982 /* Debug */, - 03E6CEA11CCE0C6B00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6CEAA1CCE0CA400D73982 /* Build configuration list for PBXNativeTarget "vdds" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6CEAB1CCE0CA400D73982 /* Debug */, - 03E6CEAC1CCE0CA400D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6CEB21CCE0CCC00D73982 /* Build configuration list for PBXNativeTarget "vdds-stubs" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6CEB31CCE0CCC00D73982 /* Debug */, - 03E6CEB41CCE0CCC00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0571CCE116900D73982 /* Build configuration list for PBXNativeTarget "vdds-server" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0581CCE116900D73982 /* Debug */, - 03E6D0591CCE116900D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0641CCE121300D73982 /* Build configuration list for PBXNativeTarget "publisher" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0651CCE121300D73982 /* Debug */, - 03E6D0661CCE121300D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D06F1CCE121A00D73982 /* Build configuration list for PBXNativeTarget "subscriber" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0701CCE121A00D73982 /* Debug */, - 03E6D0711CCE121A00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D07A1CCE121F00D73982 /* Build configuration list for PBXNativeTarget "ping" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D07B1CCE121F00D73982 /* Debug */, - 03E6D07C1CCE121F00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0851CCE122400D73982 /* Build configuration list for PBXNativeTarget "pong" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0861CCE122400D73982 /* Debug */, - 03E6D0871CCE122400D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0901CCE122A00D73982 /* Build configuration list for PBXNativeTarget "rpc-publisher" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0911CCE122A00D73982 /* Debug */, - 03E6D0921CCE122A00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D09B1CCE123000D73982 /* Build configuration list for PBXNativeTarget "rpc-subscriber" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D09C1CCE123000D73982 /* Debug */, - 03E6D09D1CCE123000D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0A61CCE123500D73982 /* Build configuration list for PBXNativeTarget "rpc-ping" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0A71CCE123500D73982 /* Debug */, - 03E6D0A81CCE123500D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 03E6D0B11CCE123A00D73982 /* Build configuration list for PBXNativeTarget "rpc-pong" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 03E6D0B21CCE123A00D73982 /* Debug */, - 03E6D0B31CCE123A00D73982 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 03E6CE961CCE0C6B00D73982 /* Project object */; -} diff --git a/vdds-xcode/vdds-xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/vdds-xcode/vdds-xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 3331f11..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ddpingpong.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ddpingpong.xcscheme deleted file mode 100644 index f3eaf63..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ddpingpong.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ping.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ping.xcscheme deleted file mode 100644 index 16d61a9..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/ping.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/pong.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/pong.xcscheme deleted file mode 100644 index 3069d2a..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/pong.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/publisher.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/publisher.xcscheme deleted file mode 100644 index 750882b..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/publisher.xcscheme +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-ping.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-ping.xcscheme deleted file mode 100644 index 644e38e..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-ping.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pingpong.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pingpong.xcscheme deleted file mode 100644 index f0357df..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pingpong.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pong.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pong.xcscheme deleted file mode 100644 index 2a6d66f..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-pong.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-publisher.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-publisher.xcscheme deleted file mode 100644 index d89ca2a..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-publisher.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-subscriber.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-subscriber.xcscheme deleted file mode 100644 index 8c230d3..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/rpc-subscriber.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/subscriber.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/subscriber.xcscheme deleted file mode 100644 index d032a34..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/subscriber.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server.xcscheme deleted file mode 100644 index 6e356bb..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server2.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server2.xcscheme deleted file mode 100644 index 94057cb..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-server2.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-stubs.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-stubs.xcscheme deleted file mode 100644 index 627b501..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-stubs.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-xcode.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-xcode.xcscheme deleted file mode 100644 index c773778..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds-xcode.xcscheme +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds.xcscheme b/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds.xcscheme deleted file mode 100644 index cc1b1a5..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcshareddata/xcschemes/vdds.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vdds-xcode/vdds-xcode.xcodeproj/xcuserdata/erik.xcuserdatad/xcschemes/xcschememanagement.plist b/vdds-xcode/vdds-xcode.xcodeproj/xcuserdata/erik.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 286b5c2..0000000 --- a/vdds-xcode/vdds-xcode.xcodeproj/xcuserdata/erik.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,162 +0,0 @@ - - - - - SchemeUserState - - ddpingpong.xcscheme_^#shared#^_ - - orderHint - 14 - - ping.xcscheme_^#shared#^_ - - orderHint - 6 - - pong.xcscheme_^#shared#^_ - - orderHint - 7 - - publisher.xcscheme_^#shared#^_ - - orderHint - 4 - - rpc-ping.xcscheme_^#shared#^_ - - orderHint - 10 - - rpc-pingpong.xcscheme_^#shared#^_ - - orderHint - 13 - - rpc-pong.xcscheme_^#shared#^_ - - orderHint - 11 - - rpc-publisher.xcscheme_^#shared#^_ - - orderHint - 8 - - rpc-subscriber.xcscheme_^#shared#^_ - - orderHint - 9 - - subscriber.xcscheme_^#shared#^_ - - orderHint - 5 - - vdds-server.xcscheme_^#shared#^_ - - orderHint - 3 - - vdds-server2.xcscheme_^#shared#^_ - - orderHint - 12 - - vdds-stubs.xcscheme_^#shared#^_ - - orderHint - 2 - - vdds-xcode.xcscheme_^#shared#^_ - - orderHint - 0 - - vdds.xcscheme_^#shared#^_ - - orderHint - 1 - - - SuppressBuildableAutocreation - - 0335203D1CEDD22A003E7429 - - primary - - - 036D25831DF15EB9009A18C5 - - primary - - - 03C96E9B1CCE5B8D0012F15D - - primary - - - 03E6CE9D1CCE0C6B00D73982 - - primary - - - 03E6CEA81CCE0CA400D73982 - - primary - - - 03E6CEB01CCE0CCC00D73982 - - primary - - - 03E6D0521CCE116900D73982 - - primary - - - 03E6D05F1CCE121300D73982 - - primary - - - 03E6D06A1CCE121A00D73982 - - primary - - - 03E6D0751CCE121F00D73982 - - primary - - - 03E6D0801CCE122400D73982 - - primary - - - 03E6D08B1CCE122A00D73982 - - primary - - - 03E6D0961CCE123000D73982 - - primary - - - 03E6D0A11CCE123500D73982 - - primary - - - 03E6D0AC1CCE123A00D73982 - - primary - - - - -