diff --git a/.travis.yml b/.travis.yml index 8cc036b..95109de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -142,35 +142,35 @@ windows_vs2017: &windows_vs2017 jobs: include: - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] if: type = cron - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, SECURITY=YES, LIFESPAN=NO, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, SECURITY=YES, LIFESPAN=NO, DEADLINE=NO, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=NO, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *osx_xcode9 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] if: type = cron - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ] - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *windows_vs2017 - env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Visual Studio 15 2017" ] + env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017" ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Visual Studio 15 2017 Win64" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, GENERATOR="Visual Studio 15 2017 Win64" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] before_script: - conan profile new default --detect @@ -203,6 +203,7 @@ script: -DENABLE_SSL=${SSL} -DENABLE_SECURITY=${SECURITY} -DENABLE_LIFESPAN=${LIFESPAN} + -DENABLE_DEADLINE_MISSED=${DEADLINE} -DBUILD_TESTING=on -DWERROR=on -G "${GENERATOR}" .. @@ -217,7 +218,7 @@ script: ${SCAN_BUILD} cmake --build . --config ${BUILD_TYPE} --target install ;; esac - - CYCLONEDDS_URI='allconfigstderr' ctest -j 4 --output-on-failure -T test -E '^CUnit_ddsrt_random_default_random$' -C ${BUILD_TYPE} + - CYCLONEDDS_URI='alltrueconfigstderr' ctest -j 4 --output-on-failure -T test -E '^CUnit_ddsrt_random_default_random$' -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}"; diff --git a/README.md b/README.md index c0c5def..6a85ddb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ current [ROS2 RMW layer](https://github.com/ros2/rmw_cyclonedds), that is suffic To obtain Eclipse Cyclone DDS, do - $ git clone https://github.com/eclipse-cyclonedds/cyclonedds.git + $ git clone https://github.com/eclipse-cyclonedds/cyclonedds.git $ cd cyclonedds $ mkdir build @@ -66,7 +66,7 @@ generating build files. For example, "Visual Studio 15 2017 Win64" would target using Visual Studio 2017. To install it after a successful build, do: - + $ cmake --build . --target install which will copy everything to: @@ -102,12 +102,22 @@ Such a build requires the presence of [CUnit](http://cunit.sourceforge.net/). Y yourself, or you can choose to instead rely on the [Conan](https://conan.io) packaging system that the CI build infrastructure also uses. In that case, install Conan and do: - $ conan install .. + $ conan install .. --build missing -in the build directory prior to running cmake. For Windows, depending on the generator, you might -also need to add switches to select the architecture and build type, e.g., ``conan install -s -arch=x86_64 -s build_type=Debug ..`` This will automatically download and/or build CUnit (and, at -the moment, OpenSSL). +in the build directory prior to running cmake. + +The CUnit Conan package is hosted in the +[Bincrafters Bintray repository](https://bintray.com/bincrafters/public-conan). In case this repository +was not added to your Conan remotes list yet (and the above mentioned install command failed because it +could not find the CUnit package), you can add the Bintray repository by: + + $ conan remote add https://api.bintray.com/conan/bincrafters/public-conan + +Replace ```` with a name that identifies the repository (e.g. ``bincrafters``). + +For Windows, depending on the generator, you might also need to add switches to select the architecture +and build type, e.g., ``conan install -s arch=x86_64 -s build_type=Debug ..`` This will automatically +download and/or build CUnit (and, at the moment, OpenSSL). ## Documentation @@ -128,14 +138,14 @@ to run the program, it is merely to illustrate the process. $ cd roundtrip $ cmake /share/CycloneDDS/examples/roundtrip $ cmake --build . - + On one terminal start the application that will be responding to pings: $ ./RoundtripPong On another terminal, start the application that will be sending the pings: - - $ ./RoundtripPing 0 0 0 + + $ ./RoundtripPing 0 0 0 # payloadSize: 0 | numSamples: 0 | timeOut: 0 # Waiting for startup jitter to stabilise # Warm up complete. diff --git a/docs/makernc.pl b/docs/makernc.pl index 0de6a8e..98ebe8c 100644 --- a/docs/makernc.pl +++ b/docs/makernc.pl @@ -344,7 +344,7 @@ sub conv_to_rnc { } elsif ($fs->{kstr} eq "Enum") { die unless exists $enum_values{$fs->{typehint}}; my @vs = split /;/, $enum_values{$fs->{typehint}}; - printf $fh "${indent} ${sep}%s\n", (join '|', map { "\"$_\"" } @vs); + printf $fh "${indent} ${sep}(%s)\n", (join '|', map { "\"$_\"" } @vs); } elsif ($fs->{kstr} eq "Int") { printf $fh "${indent} ${sep}xsd:integer\n"; #if (exists $range{$lctn} || exists $range{$fs->{typehint}}) { diff --git a/docs/manual/options.md b/docs/manual/options.md index 85ae1eb..4cb7bd3 100644 --- a/docs/manual/options.md +++ b/docs/manual/options.md @@ -1253,15 +1253,17 @@ The default value is: "-1". #### //CycloneDDS/Domain/Internal/MultipleReceiveThreads Attributes: [maxretries](#cycloneddsdomaininternalmultiplereceivethreadsmaxretries) -Boolean +One of: false, true, default 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). +thread (false) or whether multiple receive threads may be used to improve +latency (true). By default it is disabled on Windows because it appears +that one cannot count on being able to send packets to oneself, which is +necessary to stop the thread during shutdown. Currently multiple receive +threads are only used for connectionless transport (e.g., UDP) and +ManySocketsMode not set to single (the default). -The default value is: "true". +The default value is: "default". #### //CycloneDDS/Domain/Internal/MultipleReceiveThreads[@maxretries] diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc index 9f03f62..b48d950 100644 --- a/etc/cyclonedds.rnc +++ b/etc/cyclonedds.rnc @@ -51,7 +51,7 @@ 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.

The default value is: "single".

""" ] ] element ManySocketsMode { - "false"|"true"|"single"|"none"|"many" + ("false"|"true"|"single"|"none"|"many") }? & [ a:documentation [ xml:lang="en" """

This element sets the level of standards conformance of this instance @@ -78,7 +78,7 @@ though there is no good reason not to.

The default setting is "lax".

The default value is: "lax".

""" ] ] element StandardsConformance { - "lax"|"strict"|"pedantic" + ("lax"|"strict"|"pedantic") }? }* & [ a:documentation [ xml:lang="en" """ @@ -745,13 +745,13 @@ is available.

The default value is: "false".

""" ] ]

This element allows selecting the transport to be used (udp, udp6, tcp, tcp6, raweth)

The default value is: "default".

""" ] ] element Transport { - "default"|"udp"|"udp6"|"tcp"|"tcp6"|"raweth" + ("default"|"udp"|"udp6"|"tcp"|"tcp6"|"raweth") }? & [ a:documentation [ xml:lang="en" """

Deprecated (use Transport instead)

The default value is: "default".

""" ] ] element UseIPv6 { - "false"|"true"|"default" + ("false"|"true"|"default") }? }? & [ a:documentation [ xml:lang="en" """ @@ -810,7 +810,7 @@ most efficient, and full is inefficient but certain to be compliant. See also Internal/ConservativeBuiltinReaderStartup.

The default value is: "writers".

""" ] ] element BuiltinEndpointSet { - "full"|"writers"|"minimal" + ("full"|"writers"|"minimal") }? & [ a:documentation [ xml:lang="en" """

The ControlTopic element allows configured whether Cyclone DDS @@ -1036,10 +1036,13 @@ is: "-1".

""" ] ] }? & [ a:documentation [ xml:lang="en" """

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).

The default value is: "true".

""" ] ] +receive thread (false) or whether multiple receive threads may be used to +improve latency (true). By default it is disabled on Windows because it +appears that one cannot count on being able to send packets to oneself, +which is necessary to stop the thread during shutdown. Currently multiple +receive threads are only used for connectionless transport (e.g., UDP) +and ManySocketsMode not set to single (the default).

The default +value is: "default".

""" ] ] element MultipleReceiveThreads { [ a:documentation [ xml:lang="en" """

Receive threads dedicated to a single socket can only be triggered for @@ -1051,7 +1054,7 @@ attribute before aborting.

The default value is: attribute maxretries { xsd:integer }? - & xsd:boolean + & ("false"|"true"|"default") }? & [ a:documentation [ xml:lang="en" """

This setting controls the delay between receipt of a HEARTBEAT @@ -1136,7 +1139,7 @@ try to merge. Internal/RetransmitMergingPeriod.

The default value is: "never".

""" ] ] element RetransmitMerging { - "never"|"adaptive"|"always" + ("never"|"adaptive"|"always") }? & [ a:documentation [ xml:lang="en" """

This setting determines the size of the time window in which a NACK of @@ -1521,7 +1524,7 @@ using TCP.

The default value is: "false".

""" ] ] General/Transport instead.

The default value is: "default".

""" ] ] element Enable { - "false"|"true"|"default" + ("false"|"true"|"default") }? & [ a:documentation [ xml:lang="en" """

This element enables the TCP_NODELAY socket option, preventing @@ -1630,7 +1633,7 @@ from the underlying operating system to be able to assign some of the privileged scheduling classes.

The default value is: "default".

""" ] ] element Class { - "realtime"|"timeshare"|"default" + ("realtime"|"timeshare"|"default") }? & [ a:documentation [ xml:lang="en" """

This element specifies the thread priority (decimal integer or @@ -1771,7 +1774,7 @@ situation rather than the current situation. Currently, the most useful verbosity levels are config, fine and finest.

The default value is: "none".

""" ] ] element Verbosity { - "finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none" + ("finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none") }? }* }* diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd index d0d21dd..9b1944a 100644 --- a/etc/cyclonedds.xsd +++ b/etc/cyclonedds.xsd @@ -1379,14 +1379,24 @@ is: &quot;-1&quot;.</p> <p>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).</p><p>The default value is: &quot;true&quot;.</p> +receive thread (false) or whether multiple receive threads may be used to +improve latency (true). By default it is disabled on Windows because it +appears that one cannot count on being able to send packets to oneself, +which is necessary to stop the thread during shutdown. Currently multiple +receive threads are only used for connectionless transport (e.g., UDP) +and ManySocketsMode not set to single (the default).</p><p>The default +value is: &quot;default&quot;.</p> - + + + + + + + + @@ -1398,7 +1408,7 @@ attribute before aborting.</p><p>The default value is: &quot;4294967295&quot;.</p> - + diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0abfde6..9da094a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -32,6 +32,11 @@ if(ENABLE_LIFESPAN) add_definitions(-DDDSI_INCLUDE_LIFESPAN) endif() +option(ENABLE_DEADLINE_MISSED "Enable Deadline Missed QoS support" ON) +if(ENABLE_DEADLINE_MISSED) + add_definitions(-DDDSI_INCLUDE_DEADLINE_MISSED) +endif() + # 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. diff --git a/src/core/ddsc/CMakeLists.txt b/src/core/ddsc/CMakeLists.txt index b32a4b5..d5bae0c 100644 --- a/src/core/ddsc/CMakeLists.txt +++ b/src/core/ddsc/CMakeLists.txt @@ -30,7 +30,6 @@ PREPEND(srcs_ddsc "${CMAKE_CURRENT_LIST_DIR}/src" dds_topic.c dds_listener.c dds_read.c - dds_stream.c dds_waitset.c dds_readcond.c dds_guardcond.c @@ -51,6 +50,7 @@ PREPEND(hdrs_public_ddsc "$=0 - * A valid topic handle. + * A valid unique topic handle. * @retval DDS_RETCODE_BAD_PARAMETER * Either participant, descriptor, name or qos is invalid. + * @retval DDS_RETCODE_BAD_PARAMETER + * Either participant, descriptor, name or qos is invalid. + * @retval DDS_RETCODE_INCONSISTENT_POLICY + * QoS mismatch between qos and an existing topic's QoS. + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * Mismatch between type name in descriptor and pre-existing + * topic's type name. */ -/* TODO: Check list of retcodes is complete. */ DDS_EXPORT dds_entity_t dds_create_topic( dds_entity_t participant, @@ -986,13 +998,17 @@ dds_create_topic( const dds_qos_t *qos, const dds_listener_t *listener); -struct ddsi_sertopic; -struct nn_plist; /** * @brief Creates a new topic with arbitrary type handling. * * The type name for the topic is taken from the provided "sertopic" object. Topic - * matching is done on a combination of topic name and type name. + * matching is done on a combination of topic name and type name. Each successful + * call to dds_create_topic creates a new topic entity sharing the same QoS + * settings with all other topics of the same name. + * + * If sertopic is not yet known in the domain, it is added and its refcount + * incremented; if an equivalent sertopic object is already known, then the known + * one is used instead. * * @param[in] participant Participant on which to create the topic. * @param[in] sertopic Internal description of the topic type (includes name). @@ -1000,21 +1016,27 @@ struct nn_plist; * @param[in] listener Any listener functions associated with the new topic (can be NULL). * @param[in] sedp_plist Topic description to be published as part of discovery (if NULL, not published). * - * @returns A valid topic handle or an error code. + * @returns A valid, unique topic handle or an error code. * * @retval >=0 - * A valid topic handle. + * A valid unique topic handle. * @retval DDS_RETCODE_BAD_PARAMETER * Either participant, descriptor, name or qos is invalid. + * @retval DDS_RETCODE_BAD_PARAMETER + * Either participant, descriptor, name or qos is invalid. + * @retval DDS_RETCODE_INCONSISTENT_POLICY + * QoS mismatch between qos and an existing topic's QoS. + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * Mismatch between type name in sertopic and pre-existing + * topic's type name. */ -/* TODO: Check list of retcodes is complete. */ 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 struct nn_plist *sedp_plist); + const struct ddsi_plist *sedp_plist); /** * @brief Finds a named topic. @@ -1030,8 +1052,9 @@ dds_create_topic_arbitrary ( * A valid topic handle. * @retval DDS_RETCODE_BAD_PARAMETER * Participant was invalid. + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * No topic of this name existed yet in the participant */ -/* TODO: Check list of retcodes is complete. */ DDS_EXPORT dds_entity_t dds_find_topic(dds_entity_t participant, const char *name); @@ -1047,8 +1070,6 @@ dds_find_topic(dds_entity_t participant, const char *name); * @retval DDS_RETCODE_OK * Success. */ -/* TODO: do we need a convenience version as well that allocates and add a _s suffix to this one? */ -/* TODO: Check annotation. Could be _Out_writes_to_(size, return + 1) as well. */ DDS_EXPORT dds_return_t dds_get_name(dds_entity_t topic, char *name, size_t size); @@ -1324,7 +1345,7 @@ dds_create_writer( * * This operation registers an instance with a key value to the data writer and * returns an instance handle that could be used for successive write & dispose - * operations. When the handle is not allocated, the function will return and + * operations. When the handle is not allocated, the function will return an * error and the handle will be un-touched. * * @param[in] writer The writer to which instance has be associated. @@ -2035,7 +2056,7 @@ dds_waitset_attach( * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK - * Entity attached. + * Entity detached. * @retval DDS_RETCODE_ERROR * An internal error has occurred. * @retval DDS_RETCODE_BAD_PARAMETER @@ -2072,7 +2093,7 @@ dds_waitset_detach( * @returns A dds_return_t indicating success or failure. * * @retval DDS_RETCODE_OK - * Entity attached. + * Trigger value set. * @retval DDS_RETCODE_ERROR * An internal error has occurred. * @retval DDS_RETCODE_BAD_PARAMETER diff --git a/src/core/ddsc/include/dds/ddsc/dds_internal_api.h b/src/core/ddsc/include/dds/ddsc/dds_internal_api.h new file mode 100644 index 0000000..55c5601 --- /dev/null +++ b/src/core/ddsc/include/dds/ddsc/dds_internal_api.h @@ -0,0 +1,44 @@ +/* + * Copyright(c) 2006 to 2020 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 + * WARNING This file is only needed for the work around for https://github.com/eclipse-cyclonedds/cyclonedds/issues/74 + * Do not include this file in an application! Once issue #74 is solved this header file should be removed. + */ + +#ifndef DDS_INTERNAL_API_H +#define DDS_INTERNAL_API_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#define DDS_READ_WITHOUT_LOCK (0xFFFFFFED) +/* + * @private + * dds_reader_lock_samples: Returns number of samples in read cache and locks the + * reader cache to make sure that the samples content doesn't change. + * Because the cache is locked, you should be able to read/take without having to + * lock first. This is done by passing the DDS_READ_WITHOUT_LOCK value to the + * read/take call as maxs. Then the read/take will not lock but still unlock. + * + * CycloneDDS doesn't support a read/take that just returns all + * available samples issue #74. As a work around to support LENGTH_UNLIMITED in C++. + * dds_reader_lock_samples() and DDS_READ_WITHOUT_LOCK are needed. + */ +DDS_EXPORT uint32_t +dds_reader_lock_samples (dds_entity_t entity); + +#if defined (__cplusplus) +} +#endif +#endif 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 0b0d99d..730020c 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_impl.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_impl.h @@ -112,6 +112,7 @@ typedef enum dds_entity_kind DDS_KIND_DOMAIN, DDS_KIND_CYCLONEDDS } dds_entity_kind_t; +#define DDS_KIND_MAX DDS_KIND_CYCLONEDDS /* Handles are opaque pointers to implementation types */ typedef uint64_t dds_instance_handle_t; 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 1705750..9ce40f0 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h @@ -149,6 +149,8 @@ dds_qset_durability (dds_qos_t * __restrict qos, dds_durability_kind_t kind); /** * @brief Set the history policy of a qos structure. + * + * Note that depth is only relevant for keep last. If you want limited history for keep all, use dds_qset_resource_limits(). * * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy * @param[in] kind - History kind value \ref DCPS_QoS_History @@ -297,7 +299,7 @@ dds_qset_partition1 ( * * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy * @param[in] kind - Reliability kind - * @param[in] max_blocking_time - Max blocking duration applied when kind is reliable. + * @param[in] max_blocking_time - Max blocking duration applied when kind is reliable. This is how long the writer will block when its history is full. */ DDS_EXPORT void dds_qset_reliability ( diff --git a/src/core/ddsc/src/dds__alloc.h b/src/core/ddsc/src/dds__alloc.h index a8f09db..10eadcf 100644 --- a/src/core/ddsc/src/dds__alloc.h +++ b/src/core/ddsc/src/dds__alloc.h @@ -18,8 +18,6 @@ extern "C" { #endif -void dds_sample_free_contents (char * data, const uint32_t * ops); - #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds__entity.h b/src/core/ddsc/src/dds__entity.h index 3725d83..23025c3 100644 --- a/src/core/ddsc/src/dds__entity.h +++ b/src/core/ddsc/src/dds__entity.h @@ -86,7 +86,8 @@ 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_participant *dds_entity_participant (dds_entity *e); +DDS_EXPORT dds_participant *dds_entity_participant (const dds_entity *e); +DDS_EXPORT const ddsi_guid_t *dds_entity_participant_guid (const dds_entity *e); DDS_EXPORT void dds_entity_final_deinit_before_free (dds_entity *e); DDS_EXPORT bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root); diff --git a/src/core/ddsc/src/dds__participant.h b/src/core/ddsc/src/dds__participant.h index ef52d86..feac58c 100644 --- a/src/core/ddsc/src/dds__participant.h +++ b/src/core/ddsc/src/dds__participant.h @@ -20,6 +20,8 @@ extern "C" { DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_participant, DDS_KIND_PARTICIPANT) +extern const ddsrt_avl_treedef_t participant_ktopics_treedef; + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds__qos.h b/src/core/ddsc/src/dds__qos.h index e79febc..2303df0 100644 --- a/src/core/ddsc/src/dds__qos.h +++ b/src/core/ddsc/src/dds__qos.h @@ -12,7 +12,7 @@ #ifndef _DDS_QOS_H_ #define _DDS_QOS_H_ -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #if defined (__cplusplus) extern "C" { diff --git a/src/core/ddsc/src/dds__rhc_default.h b/src/core/ddsc/src/dds__rhc_default.h index 7a8a8e1..cf8fab3 100644 --- a/src/core/ddsc/src/dds__rhc_default.h +++ b/src/core/ddsc/src/dds__rhc_default.h @@ -19,13 +19,18 @@ extern "C" { struct dds_rhc; struct dds_reader; struct ddsi_sertopic; -struct q_globals; +struct ddsi_domaingv; struct dds_rhc_default; struct rhc_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_xchecks (dds_reader *reader, struct ddsi_domaingv *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); +#ifdef DDSI_INCLUDE_LIFESPAN DDS_EXPORT nn_mtime_t dds_rhc_default_sample_expired_cb(void *hc, nn_mtime_t tnow); +#endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +DDS_EXPORT nn_mtime_t dds_rhc_default_deadline_missed_cb(void *hc, nn_mtime_t tnow); +#endif #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__serdata_builtintopic.h b/src/core/ddsc/src/dds__serdata_builtintopic.h index 803f7e3..52509f2 100644 --- a/src/core/ddsc/src/dds__serdata_builtintopic.h +++ b/src/core/ddsc/src/dds__serdata_builtintopic.h @@ -9,10 +9,11 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef DDSI_SERDATA_BUILTINTOPIC_H -#define DDSI_SERDATA_BUILTINTOPIC_H +#ifndef DDS__SERDATA_BUILTINTOPIC_H +#define DDS__SERDATA_BUILTINTOPIC_H -#include "dds/ddsi/q_xqos.h" +#include "dds/dds.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" @@ -33,17 +34,15 @@ 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 q_globals *gv); +struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__topic.h b/src/core/ddsc/src/dds__topic.h index f6de42a..e9656d0 100644 --- a/src/core/ddsc/src/dds__topic.h +++ b/src/core/ddsc/src/dds__topic.h @@ -21,9 +21,13 @@ 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) ddsrt_nonnull_all; DDS_EXPORT void dds_topic_free (dds_domainid_t domainid, struct ddsi_sertopic * st) ddsrt_nonnull_all; +DDS_EXPORT dds_return_t dds_topic_pin (dds_entity_t handle, struct dds_topic **tp) ddsrt_nonnull_all; +DDS_EXPORT void dds_topic_unpin (struct dds_topic *tp) ddsrt_nonnull_all; +DDS_EXPORT void dds_topic_defer_set_qos (struct dds_topic *tp) ddsrt_nonnull_all; +DDS_EXPORT void dds_topic_allow_set_qos (struct dds_topic *tp) ddsrt_nonnull_all; + #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); @@ -35,7 +39,7 @@ DDS_EXPORT void dds_topic_set_filter_with_ctx DDS_EXPORT dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx (dds_entity_t topic); -DDS_EXPORT dds_entity_t dds_create_topic_impl (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_EXPORT dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__types.h b/src/core/ddsc/src/dds__types.h index 4b9eec5..8abc9cc 100644 --- a/src/core/ddsc/src/dds__types.h +++ b/src/core/ddsc/src/dds__types.h @@ -17,7 +17,7 @@ #include "dds/dds.h" #include "dds/ddsrt/sync.h" #include "dds/ddsi/q_rtps.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_builtin_topic_if.h" #include "dds__handles.h" @@ -34,6 +34,7 @@ struct dds_writer; struct dds_publisher; struct dds_subscriber; struct dds_topic; +struct dds_ktopic; struct dds_readcond; struct dds_guardcond; struct dds_statuscond; @@ -127,7 +128,7 @@ typedef struct dds_entity { 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_domain *m_domain; /* constant */ - dds_qos_t *m_qos; /* [m_mutex] */ + dds_qos_t *m_qos; /* [m_mutex]; null for topics (they rely on correpsonding "ktopic") (+waitset,domain,&c.) */ ddsi_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] */ @@ -215,7 +216,6 @@ typedef struct dds_domain { ddsrt_avl_node_t m_node; /* for dds_global.m_domains */ dds_domainid_t m_id; - ddsrt_avl_tree_t m_topics; struct cfgst *cfgst; struct ddsi_sertopic *builtin_participant_topic; @@ -227,7 +227,7 @@ typedef struct dds_domain { struct local_orphan_writer *builtintopic_writer_subscriptions; struct ddsi_builtin_topic_interface btif; - struct q_globals gv; + struct ddsi_domaingv gv; } dds_domain; typedef struct dds_subscriber { @@ -238,14 +238,31 @@ typedef struct dds_publisher { struct dds_entity m_entity; } dds_publisher; +typedef struct dds_ktopic { + /* name -> mapping for topics, part of the participant + and protected by the participant's lock (including the actual QoS + setting) + + defer_set_qos is used to implement an intentionally unfair single-writer/ + multiple-reader lock using the participant's lock & cond var: set_qos + "write-locks" it, create_reader and create_writer "read-lock" it. */ + ddsrt_avl_node_t pp_ktopics_avlnode; + uint32_t refc; + uint32_t defer_set_qos; /* set_qos must wait for this to be 0 */ + dds_qos_t *qos; + char *name; /* [constant] */ + char *type_name; /* [constant] */ +} dds_ktopic; + typedef struct dds_participant { struct dds_entity m_entity; dds_entity_t m_builtin_subscriber; + ddsrt_avl_tree_t m_ktopics; /* [m_entity.m_mutex] */ } dds_participant; typedef struct dds_reader { struct dds_entity m_entity; - struct dds_topic *m_topic; + struct dds_topic *m_topic; /* refc'd, constant, lock(rd) -> lock(tp) allowed */ 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; @@ -265,7 +282,7 @@ typedef struct dds_reader { typedef struct dds_writer { struct dds_entity m_entity; - struct dds_topic *m_topic; + struct dds_topic *m_topic; /* refc'd, constant, lock(wr) -> lock(tp) allowed */ 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 )*/ @@ -287,6 +304,7 @@ typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx); typedef struct dds_topic { struct dds_entity m_entity; struct ddsi_sertopic *m_stopic; + struct dds_ktopic *m_ktopic; /* refc'd, constant */ dds_topic_intern_filter_fn filter_fn; void *filter_ctx; diff --git a/src/core/ddsc/src/dds__whc.h b/src/core/ddsc/src/dds__whc.h index dcaeb42..5f3c7a9 100644 --- a/src/core/ddsc/src/dds__whc.h +++ b/src/core/ddsc/src/dds__whc.h @@ -18,8 +18,13 @@ extern "C" { #endif -struct q_globals; -struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdepth, uint32_t tldepth); +struct ddsi_domaingv; +struct whc_writer_info; +struct dds_writer; + +struct whc *whc_new (struct ddsi_domaingv *gv, const struct whc_writer_info *wrinfo); +struct whc_writer_info *whc_make_wrinfo (struct dds_writer *wr, const dds_qos_t *qos); +void whc_free_wrinfo (struct whc_writer_info *); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__writer.h b/src/core/ddsc/src/dds__writer.h index c2c9336..69ff7e1 100644 --- a/src/core/ddsc/src/dds__writer.h +++ b/src/core/ddsc/src/dds__writer.h @@ -20,6 +20,11 @@ extern "C" { DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_writer, DDS_KIND_WRITER) +struct status_cb_data; + +void dds_writer_status_cb (void *entity, const struct status_cb_data * data); +dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds_alloc.c b/src/core/ddsc/src/dds_alloc.c index 7ff7779..662719d 100644 --- a/src/core/ddsc/src/dds_alloc.c +++ b/src/core/ddsc/src/dds_alloc.c @@ -13,21 +13,9 @@ #include #include "dds__alloc.h" -#include "dds__stream.h" #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_config.h" - -/* -#define OP_DEBUG_FREE 1 -*/ - -#if defined OP_DEBUG_FREE -static const char * stream_op_type[11] = -{ - NULL, "1Byte", "2Byte", "4Byte", "8Byte", "String", - "BString", "Sequence", "Array", "Union", "Struct" -}; -#endif +#include "dds/ddsi/ddsi_cdrstream.h" static dds_allocator_t dds_allocator_fns = { ddsrt_malloc, ddsrt_realloc, ddsrt_free }; @@ -87,287 +75,30 @@ void dds_string_free (char * str) dds_free (str); } -void dds_sample_free_contents (char *data, const uint32_t * ops) +static void dds_sample_free_key (void *vsample, const struct dds_topic_descriptor * desc) { - uint32_t op; - uint32_t type; - uint32_t num; - uint32_t subtype; - char * addr; - - while ((op = *ops) != DDS_OP_RTS) + char *sample = vsample; + for (uint32_t i = 0; i < desc->m_nkeys; i++) { - switch (DDS_OP_MASK & op) - { - case DDS_OP_ADR: - { - type = DDS_OP_TYPE (op); -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-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: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - { - break; - } - case DDS_OP_VAL_STR: - { -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-STR: @ %p %s\n", addr, *((char**) addr)); -#endif - dds_free (*((char**) addr)); - *((char**) addr) = NULL; - break; - } - case DDS_OP_VAL_SEQ: - { - dds_sequence_t * seq = (dds_sequence_t*) addr; - subtype = DDS_OP_SUBTYPE (op); - num = (seq->_maximum > seq->_length) ? seq->_maximum : seq->_length; - -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-SEQ: of %s\n", stream_op_type[subtype]); -#endif - if ((seq->_release && 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: - { - break; - } - case DDS_OP_VAL_BST: - { - ops++; - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr = (char**) seq->_buffer; - while (num--) - { - dds_free (*ptr++); - } - 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_sample_free_contents (ptr, jsr_ops); - ptr += elem_size; - } - ops += jmp ? (jmp - 3) : 1; - break; - } - } - } - if (seq->_release) - { - dds_free (seq->_buffer); - seq->_maximum = 0; - seq->_length = 0; - seq->_buffer = NULL; - } - break; - } - case DDS_OP_VAL_ARR: - { - subtype = DDS_OP_SUBTYPE (op); - num = *ops++; - -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-ARR: of %s size %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: - { - break; - } - case DDS_OP_VAL_STR: - { - char ** ptr = (char**) addr; - while (num--) - { - dds_free (*ptr++); - } - break; - } - case DDS_OP_VAL_BST: - { - 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_sample_free_contents (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); - -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-UNI: switch %s cases %d\n", stream_op_type[subtype], num); -#endif - /* Get discriminant */ - - switch (subtype) - { - case DDS_OP_VAL_1BY: - { - disc = *((uint8_t*) addr); - break; - } - case DDS_OP_VAL_2BY: - { - disc = *((uint16_t*) addr); - break; - } - case DDS_OP_VAL_4BY: - { - disc = *((uint32_t*) addr); - break; - } - default: assert (0); - } - - /* Free 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]; - - switch (subtype) - { - case DDS_OP_VAL_1BY: - case DDS_OP_VAL_2BY: - case DDS_OP_VAL_4BY: - case DDS_OP_VAL_8BY: - case DDS_OP_VAL_BST: - { - break; - } - case DDS_OP_VAL_STR: - { - dds_free (*((char**) addr)); - *((char**) addr) = NULL; - break; - } - default: - { - dds_sample_free_contents (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: - { - ops++; - break; - } - default: assert (0); - } - break; - } - case DDS_OP_JSR: /* Implies nested type */ - { -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-JSR: %d\n", DDS_OP_JUMP (op)); -#endif - dds_sample_free_contents (data, ops + DDS_OP_JUMP (op)); - ops++; - break; - } - default: assert (0); - } - } -#ifdef OP_DEBUG_FREE - DDS_TRACE("F-RTS:\n"); -#endif -} - -static void dds_sample_free_key (char * sample, const struct dds_topic_descriptor * desc) -{ - uint32_t i; - const uint32_t * op; - - for (i = 0; i < desc->m_nkeys; i++) - { - op = desc->m_ops + desc->m_keys[i].m_index; + const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index; if (DDS_OP_TYPE (*op) == DDS_OP_VAL_STR) - { - dds_free (*(char**)(sample + op[1])); - } + dds_free (*(char **) (sample + op[1])); } } void dds_sample_free (void * sample, const struct dds_topic_descriptor * desc, dds_free_op_t op) { + /* external API, so can't replace the dds_topic_decsriptor type ... */ assert (desc); if (sample) { if (op & DDS_FREE_CONTENTS_BIT) - { - dds_sample_free_contents ((char*) sample, desc->m_ops); - } + dds_stream_free_sample (sample, desc->m_ops); else if (op & DDS_FREE_KEY_BIT) - { - dds_sample_free_key ((char*) sample, desc); - } + dds_sample_free_key (sample, desc); + if (op & DDS_FREE_ALL_BIT) - { dds_free (sample); - } } } diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c index ca45561..b7068c4 100644 --- a/src/core/ddsc/src/dds_builtin.c +++ b/src/core/ddsc/src/dds_builtin.c @@ -15,8 +15,8 @@ #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/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds__init.h" #include "dds__domain.h" #include "dds__participant.h" @@ -24,6 +24,7 @@ #include "dds__builtin.h" #include "dds__entity.h" #include "dds__subscriber.h" +#include "dds__topic.h" #include "dds__write.h" #include "dds__writer.h" #include "dds__whc_builtintopic.h" @@ -242,6 +243,13 @@ static void dds__builtin_write (const struct entity_common *e, nn_wctime_t times } } +static void unref_builtin_topics (struct dds_domain *dom) +{ + ddsi_sertopic_unref (dom->builtin_participant_topic); + ddsi_sertopic_unref (dom->builtin_reader_topic); + ddsi_sertopic_unref (dom->builtin_writer_topic); +} + void dds__builtin_init (struct dds_domain *dom) { dds_qos_t *qos = dds__create_builtin_qos (); @@ -253,9 +261,15 @@ void dds__builtin_init (struct dds_domain *dom) 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); + dom->builtin_participant_topic = new_sertopic_builtintopic (DSBT_PARTICIPANT, "DCPSParticipant", "org::eclipse::cyclonedds::builtin::DCPSParticipant"); + dom->builtin_reader_topic = new_sertopic_builtintopic (DSBT_READER, "DCPSSubscription", "org::eclipse::cyclonedds::builtin::DCPSSubscription"); + dom->builtin_writer_topic = new_sertopic_builtintopic (DSBT_WRITER, "DCPSPublication", "org::eclipse::cyclonedds::builtin::DCPSPublication"); + + ddsrt_mutex_lock (&dom->gv.sertopics_lock); + ddsi_sertopic_register_locked (&dom->gv, dom->builtin_participant_topic); + ddsi_sertopic_register_locked (&dom->gv, dom->builtin_reader_topic); + ddsi_sertopic_register_locked (&dom->gv, dom->builtin_writer_topic); + ddsrt_mutex_unlock (&dom->gv.sertopics_lock); thread_state_awake (lookup_thread_state (), &dom->gv); const struct entity_index *gh = dom->gv.entity_index; @@ -265,6 +279,11 @@ void dds__builtin_init (struct dds_domain *dom) thread_state_asleep (lookup_thread_state ()); dds_delete_qos (qos); + + /* ddsi_sertopic_init initializes the refcount to 1 and dds_sertopic_register_locked increments + it. All "real" references (such as readers and writers) are also accounted for in the + reference count, so we have an excess reference here. */ + unref_builtin_topics (dom); } void dds__builtin_fini (struct dds_domain *dom) @@ -275,8 +294,5 @@ void dds__builtin_fini (struct dds_domain *dom) 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); + unref_builtin_topics (dom); } diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c index 1769250..489b49c 100644 --- a/src/core/ddsc/src/dds_domain.c +++ b/src/core/ddsc/src/dds_domain.c @@ -13,6 +13,7 @@ #include "dds/ddsrt/process.h" #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/hopscotch.h" #include "dds__init.h" #include "dds/ddsc/dds_rhc.h" #include "dds__domain.h" @@ -26,7 +27,7 @@ #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/ddsi/ddsi_domaingv.h" static dds_return_t dds_domain_free (dds_entity *vdomain); @@ -59,7 +60,6 @@ static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i domain->m_entity.m_iid = ddsi_iid_gen (); domain->gv.tstart = now (); - ddsrt_avl_init (&dds_topictree_def, &domain->m_topics); /* | domain_id | domain id in config | result +-----------+---------------------+---------- @@ -138,20 +138,9 @@ static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i /* 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; - } + len = (uint32_t) (strlen (progname) + 13); 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); + (void) snprintf (domain->gv.default_local_plist_pp.entity_name, len, "%s<%u>", progname, (unsigned) ddsrt_getpid ()); domain->gv.default_local_plist_pp.present |= PP_ENTITY_NAME; if (rtps_start (&domain->gv) < 0) diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c index 4e6a225..2b842af 100644 --- a/src/core/ddsc/src/dds_entity.c +++ b/src/core/ddsc/src/dds_entity.c @@ -23,7 +23,7 @@ #include "dds__topic.h" #include "dds/version.h" #include "dds/ddsi/ddsi_pmd.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/q_transmit.h" extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink); @@ -135,11 +135,65 @@ static bool entity_has_status (const dds_entity *e) return false; } +static bool entity_may_have_children (const dds_entity *e) +{ + switch (e->m_kind) + { + case DDS_KIND_TOPIC: + return false; + case DDS_KIND_READER: + case DDS_KIND_WRITER: + case DDS_KIND_PUBLISHER: + case DDS_KIND_SUBSCRIBER: + case DDS_KIND_PARTICIPANT: + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + case DDS_KIND_COND_GUARD: + case DDS_KIND_WAITSET: + case DDS_KIND_DOMAIN: + case DDS_KIND_CYCLONEDDS: + break; + case DDS_KIND_DONTCARE: + abort (); + break; + } + return true; +} + +#ifndef NDEBUG +static bool entity_kind_has_qos (dds_entity_kind_t kind) +{ + switch (kind) + { + 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_TOPIC: + case DDS_KIND_COND_READ: + case DDS_KIND_COND_QUERY: + case DDS_KIND_COND_GUARD: + case DDS_KIND_WAITSET: + case DDS_KIND_DOMAIN: + case DDS_KIND_CYCLONEDDS: + break; + case DDS_KIND_DONTCARE: + abort (); + break; + } + return false; +} +#endif + dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask) { dds_handle_t handle; + /* CycloneDDS is at the root of the hierarchy */ assert ((kind == DDS_KIND_CYCLONEDDS) == (parent == NULL)); + assert (entity_kind_has_qos (kind) == (qos != NULL)); assert (e); e->m_kind = kind; @@ -196,7 +250,7 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind { /* for topics, refc counts readers/writers, for all others, it counts children (this we can get away with as long as topics can't have children) */ - if ((handle = dds_handle_create (&e->m_hdllink, implicit, (kind != DDS_KIND_TOPIC))) <= 0) + if ((handle = dds_handle_create (&e->m_hdllink, implicit, entity_may_have_children (e))) <= 0) return (dds_entity_t) handle; } @@ -219,41 +273,40 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child) dds_entity_add_ref_locked (parent); } -static dds_entity *get_first_child (ddsrt_avl_tree_t *remaining_children, bool ignore_topics) +static dds_entity *get_next_child (ddsrt_avl_tree_t *remaining_children, uint32_t allowed_kinds, uint64_t *cursor) { 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)) + for (dds_entity *e = ddsrt_avl_iter_succ (&dds_entity_children_td, remaining_children, &it, cursor); e != NULL; e = ddsrt_avl_iter_next (&it)) { - if ((!ignore_topics) || (dds_entity_kind(e) != DDS_KIND_TOPIC)) + dds_entity_kind_t kind = dds_entity_kind (e); + if ((1u << (uint32_t) kind) & allowed_kinds) return e; } return NULL; } -static void delete_children(struct dds_entity *parent, bool ignore_topics) +static void delete_children (struct dds_entity *parent, uint32_t allowed_kinds) { dds_entity *child; dds_return_t ret; + uint64_t cursor = 0; ddsrt_mutex_lock (&parent->m_mutex); - while ((child = get_first_child(&parent->m_children, ignore_topics)) != NULL) + while ((child = get_next_child (&parent->m_children, allowed_kinds, &cursor)) != NULL) { dds_entity_t child_handle = child->m_hdllink.hdl; + cursor = child->m_iid; /* The child will remove itself from the parent->m_children list. */ ddsrt_mutex_unlock (&parent->m_mutex); ret = dds_delete_impl (child_handle, DIS_FROM_PARENT); assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER); + (void) ret; ddsrt_mutex_lock (&parent->m_mutex); - /* The dds_delete can fail if the child is being deleted in parallel, - * in which case: wait when its not deleted yet. - * The child will trigger the condition after it removed itself from - * the childrens list. */ - if ((ret == DDS_RETCODE_BAD_PARAMETER) && - (get_first_child(&parent->m_children, ignore_topics) == child)) - { + /* The dds_delete can fail if the child is being deleted in parallel, in which case: + wait until it is has gone. */ + if (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &cursor) != NULL) ddsrt_cond_wait (&parent->m_cond, &parent->m_mutex); - } } ddsrt_mutex_unlock (&parent->m_mutex); } @@ -283,12 +336,20 @@ static const char *entity_kindstr (dds_entity_kind_t kind) static void print_delete (const dds_entity *e, enum delete_impl_state delstate , dds_instance_handle_t iid) { - unsigned cm = ddsrt_atomic_ld32 (&e->m_hdllink.cnt_flags); - printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n", - (void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid, - entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "", - e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0x7fff, (cm & 0x80000000) ? "closed" : "open", - ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children"); + if (e) + { + unsigned cm = ddsrt_atomic_ld32 (&e->m_hdllink.cnt_flags); + printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n", + (void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid, + entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "", + e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0x7fff, (cm & 0x80000000) ? "closed" : "open", + ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children"); + } + else + { + printf ("delete(%p, delstate %s, handle %"PRId64"): pin failed\n", + (void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid); + } } #endif @@ -315,7 +376,12 @@ static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state else if (ret == DDS_RETCODE_TRY_AGAIN) /* non-child refs exist */ return DDS_RETCODE_OK; else + { +#if TRACE_DELETE + print_delete (NULL, delstate, (uint64_t) entity); +#endif return ret; + } } dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate) @@ -392,8 +458,15 @@ static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, en * * To circumvent the problem. We ignore topics in the first loop. */ - delete_children(e, true /* ignore topics */); - delete_children(e, false /* delete topics */); + DDSRT_STATIC_ASSERT ((uint32_t) DDS_KIND_MAX < 32); + static const uint32_t disallowed_kinds[] = { + 1u << (uint32_t) DDS_KIND_TOPIC, + (uint32_t) 0 + }; + for (size_t i = 0; i < sizeof (disallowed_kinds) / sizeof (disallowed_kinds[0]); i++) + { + delete_children (e, ~disallowed_kinds[i]); + } /* The dds_handle_delete will wait until the last active claim on that handle is released. It is possible that this last release will be done by a thread that was @@ -476,13 +549,20 @@ dds_entity_t dds_get_parent (dds_entity_t entity) } } -dds_participant *dds_entity_participant (dds_entity *e) +dds_participant *dds_entity_participant (const dds_entity *e) { while (e && dds_entity_kind (e) != DDS_KIND_PARTICIPANT) e = e->m_parent; return (dds_participant *) e; } +const ddsi_guid_t *dds_entity_participant_guid (const dds_entity *e) +{ + struct dds_participant const * const pp = dds_entity_participant (e); + assert (pp != NULL); + return &pp->m_entity.m_guid; +} + dds_entity_t dds_get_participant (dds_entity_t entity) { dds_entity *e; @@ -577,51 +657,124 @@ dds_return_t dds_get_qos (dds_entity_t entity, dds_qos_t *qos) ret = DDS_RETCODE_ILLEGAL_OPERATION; else { + dds_qos_t *entity_qos; + if (dds_entity_kind (e) != DDS_KIND_TOPIC) + entity_qos = e->m_qos; + else + { + struct dds_topic * const tp = (dds_topic *) e; + struct dds_participant * const pp = dds_entity_participant (e); + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + entity_qos = tp->m_ktopic->qos; + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); + } + dds_reset_qos (qos); - nn_xqos_mergein_missing (qos, e->m_qos, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); + ddsi_xqos_mergein_missing (qos, entity_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) +static dds_return_t dds_set_qos_locked_raw (dds_entity *e, dds_qos_t **e_qos_ptr, bool e_enabled, const dds_qos_t *qos, uint64_t mask, const struct ddsrt_log_cfg *logcfg, dds_return_t (*set_qos) (struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all) { dds_return_t ret; + + /* Any attempt to do this on a topic ends up doing it on the ktopic instead, so that there is + but a single QoS for a topic in a participant while there can be multiple definitions of it, + and hence, multiple sertopics. Those are needed for multi-language support. */ 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?) */ + ddsi_xqos_mergein_missing (newqos, qos, mask); + ddsi_xqos_mergein_missing (newqos, *e_qos_ptr, ~(uint64_t)0); + if ((ret = ddsi_xqos_valid (logcfg, newqos)) != DDS_RETCODE_OK) + { + /* invalid or inconsistent QoS settings */ + goto error_or_nochange; + } + else if (!e_enabled) + { + /* do as you please while the entity is not enabled */ + } 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 + const uint64_t delta = ddsi_xqos_delta (*e_qos_ptr, newqos, ~(uint64_t)0); + if (delta == 0) { - /* yay! */ + /* new settings are identical to the old */ + goto error_or_nochange; + } + else if (delta & ~QP_CHANGEABLE_MASK) + { + /* not all QoS may be changed according to the spec */ + ret = DDS_RETCODE_IMMUTABLE_POLICY; + goto error_or_nochange; + } + else if (delta & (QP_RXO_MASK | QP_PARTITION)) + { + /* Cyclone doesn't (yet) support changing QoS that affect matching. Simply re-doing the + matching is easy enough, but the consequences are very weird. E.g., what is the + expectation if a transient-local writer has published data while its partition QoS is set + to A, and then changes its partition to B? Should a reader in B get the data originally + published in A? + + One can do the same thing with other RxO QoS settings, e.g., the latency budget setting. + I find that weird, and I'd rather have sane answers to these questions than set up these + traps and pitfalls for people to walk into ... + */ + ret = DDS_RETCODE_UNSUPPORTED; + goto error_or_nochange; } } - 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); + assert (ret == DDS_RETCODE_OK); + if ((ret = set_qos (e, newqos, e_enabled)) != DDS_RETCODE_OK) + goto error_or_nochange; else { - dds_delete_qos (e->m_qos); - e->m_qos = newqos; + dds_delete_qos (*e_qos_ptr); + *e_qos_ptr = newqos; } + return DDS_RETCODE_OK; + +error_or_nochange: + dds_delete_qos (newqos); return ret; } +static dds_return_t dds_set_qos_locked_impl (dds_entity *e, const dds_qos_t *qos, uint64_t mask) +{ + const struct ddsrt_log_cfg *logcfg = &e->m_domain->gv.logconfig; + dds_entity_kind_t kind = dds_entity_kind (e); + if (kind != DDS_KIND_TOPIC) + { + return dds_set_qos_locked_raw (e, &e->m_qos, (e->m_flags & DDS_ENTITY_ENABLED) != 0, qos, mask, logcfg, dds_entity_deriver_table[kind]->set_qos); + } + else + { + /* Topics must be enabled for now (all are currently, so for now it is not a meaningful limitation): + there can only be a single QoS (or different versions with the same name can have different QoS - + in particular a different value for TOPIC_DATA - and therefore the idea that it is a free-for-all + on the QoS for a disabled entity falls apart for topics. + + FIXME: topic should have a QoS object while still disabled */ + assert (e->m_flags & DDS_ENTITY_ENABLED); + struct dds_topic * const tp = (struct dds_topic *) e; + struct dds_participant * const pp = dds_entity_participant (e); + struct dds_ktopic * const ktp = tp->m_ktopic; + dds_return_t rc; + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + while (ktp->defer_set_qos != 0) + ddsrt_cond_wait (&pp->m_entity.m_cond, &pp->m_entity.m_mutex); + + /* dds_entity_deriver_table[kind]->set_qos had better avoid looking at the entity! */ + rc = dds_set_qos_locked_raw (NULL, &ktp->qos, (e->m_flags & DDS_ENTITY_ENABLED) != 0, qos, mask, logcfg, dds_entity_deriver_table[kind]->set_qos); + + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); + return rc; + } +} + static void pushdown_pubsub_qos (dds_entity *e) { /* e claimed but no mutex held */ @@ -650,7 +803,7 @@ static void pushdown_pubsub_qos (dds_entity *e) ddsrt_mutex_unlock (&e->m_mutex); } -static void pushdown_topic_qos (dds_entity *e, struct dds_entity *tp) +static void pushdown_topic_qos (dds_entity *e, struct dds_ktopic *ktp) { /* on input: both entities claimed but no mutexes held */ enum { NOP, PROP, CHANGE } todo; @@ -658,12 +811,12 @@ static void pushdown_topic_qos (dds_entity *e, struct dds_entity *tp) { case DDS_KIND_READER: { dds_reader *rd = (dds_reader *) e; - todo = (&rd->m_topic->m_entity == tp) ? CHANGE : NOP; + todo = (rd->m_topic->m_ktopic == ktp) ? CHANGE : NOP; break; } case DDS_KIND_WRITER: { dds_writer *wr = (dds_writer *) e; - todo = (&wr->m_topic->m_entity == tp) ? CHANGE : NOP; + todo = (wr->m_topic->m_ktopic == ktp) ? CHANGE : NOP; break; } default: { @@ -677,10 +830,11 @@ static void pushdown_topic_qos (dds_entity *e, struct dds_entity *tp) break; case CHANGE: { /* may lock topic while holding reader/writer lock */ + struct dds_participant * const pp = dds_entity_participant (e); 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_lock (&pp->m_entity.m_mutex); + dds_set_qos_locked_impl (e, ktp->qos, QP_TOPIC_DATA); + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); ddsrt_mutex_unlock (&e->m_mutex); break; } @@ -697,7 +851,7 @@ static void pushdown_topic_qos (dds_entity *e, struct dds_entity *tp) 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); + pushdown_topic_qos (c, ktp); ddsrt_mutex_lock (&e->m_mutex); dds_entity_unpin (c); } @@ -740,7 +894,8 @@ dds_return_t dds_set_qos (dds_entity_t entity, const dds_qos_t *qos) assert (dds_entity_kind (e->m_parent) == DDS_KIND_PARTICIPANT); if (dds_entity_pin (e->m_parent->m_hdllink.hdl, &pp) == DDS_RETCODE_OK) { - pushdown_topic_qos (pp, e); + struct dds_topic *tp = (struct dds_topic *) e; + pushdown_topic_qos (pp, tp->m_ktopic); dds_entity_unpin (pp); } break; diff --git a/src/core/ddsc/src/dds_init.c b/src/core/ddsc/src/dds_init.c index 7444a26..05f0d2c 100644 --- a/src/core/ddsc/src/dds_init.c +++ b/src/core/ddsc/src/dds_init.c @@ -30,7 +30,7 @@ #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/ddsi/ddsi_domaingv.h" #include "dds/version.h" static void dds_close (struct dds_entity *e); diff --git a/src/core/ddsc/src/dds_instance.c b/src/core/ddsc/src/dds_instance.c index 74c2089..cf82de8 100644 --- a/src/core/ddsc/src/dds_instance.c +++ b/src/core/ddsc/src/dds_instance.c @@ -21,7 +21,7 @@ #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" dds_return_t dds_writedispose (dds_entity_t writer, const void *data) { diff --git a/src/core/ddsc/src/dds_matched.c b/src/core/ddsc/src/dds_matched.c index 4ca9cc2..d2cc6a9 100644 --- a/src/core/ddsc/src/dds_matched.c +++ b/src/core/ddsc/src/dds_matched.c @@ -15,7 +15,7 @@ #include "dds/dds.h" #include "dds/version.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_thread.h" @@ -135,7 +135,7 @@ static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_ 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)); + ddsi_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; diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c index e9cdacb..3cbb48d 100644 --- a/src/core/ddsc/src/dds_participant.c +++ b/src/core/ddsc/src/dds_participant.c @@ -10,14 +10,15 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include +#include #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/environ.h" #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/ddsi/ddsi_plist.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/version.h" #include "dds__init.h" @@ -30,6 +31,13 @@ DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_participant) #define DDS_PARTICIPANT_STATUS_MASK (0u) +static int cmp_ktopic_name (const void *a, const void *b) +{ + return strcmp (a, b); +} + +const ddsrt_avl_treedef_t participant_ktopics_treedef = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY(offsetof (struct dds_ktopic, pp_ktopics_avlnode), offsetof (struct dds_ktopic, name), cmp_ktopic_name, 0); + static dds_return_t dds_participant_status_validate (uint32_t mask) { return (mask & ~DDS_PARTICIPANT_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; @@ -42,6 +50,9 @@ static dds_return_t dds_participant_delete (dds_entity *e) dds_return_t ret; assert (dds_entity_kind (e) == DDS_KIND_PARTICIPANT); + /* ktopics & topics are children and therefore must all have been deleted by the time we get here */ + assert (ddsrt_avl_is_empty (&((struct dds_participant *) e)->m_ktopics)); + 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); @@ -58,8 +69,8 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos thread_state_awake (lookup_thread_state (), &e->m_domain->gv); if ((pp = entidx_lookup_participant_guid (e->m_domain->gv.entity_index, &e->m_guid)) != NULL) { - nn_plist_t plist; - nn_plist_init_empty (&plist); + ddsi_plist_t plist; + ddsi_plist_init_empty (&plist); plist.qos.present = plist.qos.aliased = qos->present; plist.qos = *qos; update_participant_plist (pp, &plist); @@ -83,7 +94,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ dds_entity_t ret; ddsi_guid_t guid; dds_participant * pp; - nn_plist_t plist; + ddsi_plist_t plist; dds_qos_t *new_qos = NULL; char *config = ""; @@ -98,19 +109,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ 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) + ddsi_xqos_mergein_missing (new_qos, qos, DDS_PARTICIPANT_QOS_MASK); + ddsi_xqos_mergein_missing (new_qos, &dom->gv.default_local_plist_pp.qos, ~(uint64_t)0); + if ((ret = ddsi_xqos_valid (&dom->gv.logconfig, new_qos)) < 0) goto err_qos_validation; /* Translate qos */ - nn_plist_init_empty (&plist); + ddsi_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); + ddsi_plist_fini (&plist); if (ret < 0) { ret = DDS_RETCODE_ERROR; @@ -125,6 +136,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ pp->m_entity.m_iid = get_entity_instance_id (&dom->gv, &guid); pp->m_entity.m_domain = dom; pp->m_builtin_subscriber = 0; + ddsrt_avl_init (&participant_ktopics_treedef, &pp->m_ktopics); /* Add participant to extent */ ddsrt_mutex_lock (&dom->m_entity.m_mutex); diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index ae20658..00ea520 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -15,10 +15,11 @@ #include "dds__listener.h" #include "dds__participant.h" #include "dds__publisher.h" +#include "dds__writer.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/ddsi/ddsi_domaingv.h" #include "dds/version.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_publisher) @@ -54,9 +55,9 @@ dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const 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) + ddsi_xqos_mergein_missing (new_qos, qos, DDS_PUBLISHER_QOS_MASK); + ddsi_xqos_mergein_missing (new_qos, &par->m_entity.m_domain->gv.default_xqos_pub, ~(uint64_t)0); + if ((ret = ddsi_xqos_valid (&par->m_entity.m_domain->gv.logconfig, new_qos)) != DDS_RETCODE_OK) { dds_participant_unlock (par); return ret; @@ -94,10 +95,33 @@ dds_return_t dds_resume (dds_entity_t publisher) dds_return_t dds_wait_for_acks (dds_entity_t publisher_or_writer, dds_duration_t timeout) { + dds_return_t ret; + dds_entity *p_or_w_ent; + if (timeout < 0) 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); + + if ((ret = dds_entity_pin (publisher_or_writer, &p_or_w_ent)) < 0) + return ret; + + const dds_time_t tnow = dds_time (); + const dds_time_t abstimeout = (DDS_INFINITY - timeout <= tnow) ? DDS_NEVER : (tnow + timeout); + switch (dds_entity_kind (p_or_w_ent)) + { + case DDS_KIND_PUBLISHER: + /* FIXME: wait_for_acks on all writers of the same publisher */ + dds_entity_unpin (p_or_w_ent); + return DDS_RETCODE_UNSUPPORTED; + + case DDS_KIND_WRITER: + ret = dds__writer_wait_for_acks ((struct dds_writer *) p_or_w_ent, abstimeout); + dds_entity_unpin (p_or_w_ent); + return ret; + + default: + dds_entity_unpin (p_or_w_ent); + return DDS_RETCODE_ILLEGAL_OPERATION; + } } dds_return_t dds_publisher_begin_coherent (dds_entity_t publisher) diff --git a/src/core/ddsc/src/dds_qos.c b/src/core/ddsc/src/dds_qos.c index d13eeeb..9f5f091 100644 --- a/src/core/ddsc/src/dds_qos.c +++ b/src/core/ddsc/src/dds_qos.c @@ -15,7 +15,7 @@ #include "dds/dds.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" static void dds_qos_data_copy_in (ddsi_octetseq_t *data, const void * __restrict value, size_t sz, bool overwrite) { @@ -51,7 +51,7 @@ static bool dds_qos_data_copy_out (const ddsi_octetseq_t *data, void **value, si dds_qos_t *dds_create_qos (void) { dds_qos_t *qos = ddsrt_malloc (sizeof (dds_qos_t)); - nn_xqos_init_empty (qos); + ddsi_xqos_init_empty (qos); return qos; } @@ -64,8 +64,8 @@ void dds_reset_qos (dds_qos_t * __restrict qos) { if (qos) { - nn_xqos_fini (qos); - nn_xqos_init_empty (qos); + ddsi_xqos_fini (qos); + ddsi_xqos_init_empty (qos); } } @@ -78,7 +78,7 @@ void dds_delete_qos (dds_qos_t * __restrict qos) { if (qos) { - nn_xqos_fini (qos); + ddsi_xqos_fini (qos); ddsrt_free (qos); } } @@ -92,7 +92,7 @@ dds_return_t dds_copy_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restr { if (src == NULL || dst == NULL) return DDS_RETCODE_BAD_PARAMETER; - nn_xqos_copy (dst, src); + ddsi_xqos_copy (dst, src); return DDS_RETCODE_OK; } @@ -105,7 +105,7 @@ 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); + ddsi_xqos_mergein_missing (dst, src, ~(uint64_t)0); } void dds_qos_merge (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) @@ -121,7 +121,7 @@ bool dds_qos_equal (const dds_qos_t * __restrict a, const dds_qos_t * __restrict else if (a == NULL || b == NULL) return false; else - return nn_xqos_delta (a, b, ~(uint64_t)0) == 0; + return ddsi_xqos_delta (a, b, ~(uint64_t)0) == 0; } void dds_qset_userdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) diff --git a/src/core/ddsc/src/dds_read.c b/src/core/ddsc/src/dds_read.c index 56047f3..394b7e4 100644 --- a/src/core/ddsc/src/dds_read.c +++ b/src/core/ddsc/src/dds_read.c @@ -18,7 +18,7 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_sertopic.h" /* @@ -283,7 +283,7 @@ dds_return_t dds_read_instance_mask (dds_entity_t rd_or_cnd, void **buf, dds_sam { lock = false; /* FIXME: Fix the interface. */ - maxs = 100; + maxs = (uint32_t)bufsz; } return dds_read_impl (false, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); } @@ -422,7 +422,7 @@ dds_return_t dds_take_instance_mask (dds_entity_t rd_or_cnd, void **buf, dds_sam { lock = false; /* FIXME: Fix the interface. */ - maxs = 100; + maxs = (uint32_t)bufsz; } return dds_read_impl(true, rd_or_cnd, buf, bufsz, maxs, si, mask, handle, lock, false); } diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index 93e8ae7..2bd7995 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -14,6 +14,7 @@ #include "dds/dds.h" #include "dds/version.h" #include "dds/ddsrt/static_assert.h" +#include "dds__participant.h" #include "dds__subscriber.h" #include "dds__reader.h" #include "dds__listener.h" @@ -25,7 +26,7 @@ #include "dds__qos.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds__builtin.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_entity_index.h" @@ -71,9 +72,23 @@ static dds_return_t dds_reader_delete (dds_entity *e) return DDS_RETCODE_OK; } +static dds_return_t validate_reader_qos (const dds_qos_t *rqos) +{ +#ifndef DDSI_INCLUDE_DEADLINE_MISSED + if (rqos != NULL && (rqos->present & QP_DEADLINE) && rqos->deadline.deadline != DDS_INFINITY) + return DDS_RETCODE_BAD_PARAMETER; +#else + DDSRT_UNUSED_ARG (rqos); +#endif + return DDS_RETCODE_OK; +} + 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 */ + dds_return_t ret; + if ((ret = validate_reader_qos(qos)) != DDS_RETCODE_OK) + return ret; if (enabled) { struct reader *rd; @@ -240,9 +255,8 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) LIVELINESS_CHANGED_REMOVE_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_ALIVE && LIVELINESS_CHANGED_REMOVE_ALIVE < LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE && LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE < LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE && - LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE < LIVELINESS_CHANGED_TWITCH && - (uint32_t) LIVELINESS_CHANGED_TWITCH < UINT32_MAX); - assert (data->extra <= (uint32_t) LIVELINESS_CHANGED_TWITCH); + (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE < UINT32_MAX); + assert (data->extra <= (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE); switch ((enum liveliness_changed_data_extra) data->extra) { case LIVELINESS_CHANGED_ADD_ALIVE: @@ -273,8 +287,6 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data) st->alive_count++; st->alive_count_change++; break; - case LIVELINESS_CHANGED_TWITCH: - break; } st->last_publication_handle = data->handle; invoke = (lst->on_liveliness_changed != 0); @@ -348,32 +360,34 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe { dds_qos_t *rqos; dds_subscriber *sub = NULL; - dds_participant *pp; 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; + dds_return_t rc; + dds_entity_t pseudo_topic = 0; + bool created_implicit_sub = false; switch (topic) { - case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: case DDS_BUILTIN_TOPIC_DCPSTOPIC: + /* not implemented yet */ + return DDS_RETCODE_BAD_PARAMETER; + + case DDS_BUILTIN_TOPIC_DCPSPARTICIPANT: case DDS_BUILTIN_TOPIC_DCPSPUBLICATION: case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION: - internal_topic = true; - subscriber = dds__get_builtin_subscriber (participant_or_subscriber); - if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK) - return ret; - t = dds__get_builtin_topic (subscriber, topic); + /* translate provided pseudo-topic to a real one */ + pseudo_topic = topic; + if ((subscriber = dds__get_builtin_subscriber (participant_or_subscriber)) < 0) + return subscriber; + if ((rc = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK) + return rc; + topic = dds__get_builtin_topic (subscriber, topic); break; default: { dds_entity *p_or_s; - if ((ret = dds_entity_lock (participant_or_subscriber, DDS_KIND_DONTCARE, &p_or_s)) != DDS_RETCODE_OK) - return ret; + if ((rc = dds_entity_lock (participant_or_subscriber, DDS_KIND_DONTCARE, &p_or_s)) != DDS_RETCODE_OK) + return rc; switch (dds_entity_kind (p_or_s)) { case DDS_KIND_SUBSCRIBER: @@ -381,65 +395,70 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe sub = (dds_subscriber *) p_or_s; break; case DDS_KIND_PARTICIPANT: + created_implicit_sub = true; subscriber = dds__create_subscriber_l ((dds_participant *) p_or_s, true, qos, NULL); dds_entity_unlock (p_or_s); - if ((ret = dds_subscriber_lock (subscriber, &sub)) < 0) - return ret; + if ((rc = dds_subscriber_lock (subscriber, &sub)) < 0) + return rc; break; default: dds_entity_unlock (p_or_s); return DDS_RETCODE_ILLEGAL_OPERATION; } - internal_topic = false; - t = topic; break; } } - if ((ret = dds_topic_lock (t, &tp)) != DDS_RETCODE_OK) - { - reader = ret; - goto err_tp_lock; - } + if ((rc = dds_topic_pin (topic, &tp)) < 0) + goto err_pin_topic; assert (tp->m_stopic); - pp = dds_entity_participant (&sub->m_entity); - if (pp != dds_entity_participant (&tp->m_entity)) + if (dds_entity_participant (&sub->m_entity) != dds_entity_participant (&tp->m_entity)) { - reader = DDS_RETCODE_BAD_PARAMETER; + rc = DDS_RETCODE_BAD_PARAMETER; goto err_pp_mismatch; } + /* Prevent set_qos on the topic until reader has been created and registered: we can't + allow a TOPIC_DATA change to ccur before the reader has been created because that + change would then not be published in the discovery/built-in topics. + + Don't keep the participant (which protects the topic's QoS) locked because that + can cause deadlocks for applications creating a reader/writer from within a + subscription matched listener (whether the restrictions on what one can do in + listeners are reasonable or not, it used to work so it can be broken arbitrarily). */ + dds_topic_defer_set_qos (tp); + /* 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); + ddsi_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); + ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); + if (tp->m_ktopic->qos) + ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0); + ddsi_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0); - if ((ret = nn_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) != DDS_RETCODE_OK) + if ((rc = ddsi_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) < 0 || + (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK) { dds_delete_qos (rqos); - reader = ret; goto err_bad_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)) + if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos)) { dds_delete_qos (rqos); - reader = DDS_RETCODE_INCONSISTENT_POLICY; + rc = DDS_RETCODE_INCONSISTENT_POLICY; goto err_bad_qos; } /* Create reader and associated read cache (if not provided by caller) */ - rd = dds_alloc (sizeof (*rd)); - reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); + struct dds_reader * const rd = dds_alloc (sizeof (*rd)); + const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; rd->m_topic = tp; rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic); @@ -456,25 +475,27 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe dds_entity_init_complete (&rd->m_entity); 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, &pp->m_entity.m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); - assert (ret == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ + rc = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, dds_entity_participant_guid (&sub->m_entity), tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); + assert (rc == 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); - dds_topic_unlock (tp); + dds_topic_allow_set_qos (tp); + dds_topic_unpin (tp); dds_subscriber_unlock (sub); return reader; err_bad_qos: + dds_topic_allow_set_qos (tp); err_pp_mismatch: - dds_topic_unlock (tp); -err_tp_lock: + dds_topic_unpin (tp); +err_pin_topic: dds_subscriber_unlock (sub); - if ((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0) + if (created_implicit_sub) (void) dds_delete (subscriber); - return reader; + return rc; } void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb, void *cbarg) diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c index a3922cb..7c68b68 100644 --- a/src/core/ddsc/src/dds_rhc_default.c +++ b/src/core/ddsc/src/dds_rhc_default.c @@ -30,11 +30,12 @@ #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsrt/hopscotch.h" #include "dds/ddsrt/avl.h" +#include "dds/ddsrt/circlist.h" #include "dds/ddsi/ddsi_rhc.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_radmin.h" /* sampleinfo */ #include "dds/ddsi/q_entity.h" /* proxy_writer_info */ #include "dds/ddsi/ddsi_serdata.h" @@ -42,6 +43,9 @@ #ifdef DDSI_INCLUDE_LIFESPAN #include "dds/ddsi/ddsi_lifespan.h" #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +#include "dds/ddsi/ddsi_deadline.h" +#endif #include "dds/ddsi/sysdeps.h" /* INSTANCE MANAGEMENT @@ -269,11 +273,13 @@ struct rhc_instance { uint32_t disposed_gen; /* bloody generation counters - worst invention of mankind */ uint32_t no_writers_gen; /* __/ */ int32_t strength; /* "current" ownership strength */ - ddsi_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */ + ddsi_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 ddsrt_circlist_elem nonempty_list; /* links non-empty instances in arbitrary ordering */ +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + struct deadline_elem deadline; /* element in deadline missed administration */ +#endif + struct ddsi_tkmap_instance *tk;/* backref into TK for unref'ing */ struct rhc_sample a_sample; /* pre-allocated storage for 1 sample */ }; @@ -286,7 +292,7 @@ typedef enum rhc_store_result { 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 ddsrt_circlist 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 */ @@ -312,7 +318,7 @@ struct dds_rhc_default { 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 */ + struct ddsi_domaingv *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 */ @@ -325,6 +331,9 @@ struct dds_rhc_default { #ifdef DDSI_INCLUDE_LIFESPAN struct lifespan_adm lifespan; /* Lifespan administration */ #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + struct deadline_adm deadline; /* Deadline missed administration */ +#endif }; struct trigger_info_cmn { @@ -494,57 +503,33 @@ static int instance_iid_eq (const void *va, const void *vb) 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; + ddsrt_circlist_append (&rhc->nonempty_instances, &inst->nonempty_list); 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; - } + ddsrt_circlist_remove (&rhc->nonempty_instances, &inst->nonempty_list); assert (rhc->n_nonempty_instances > 0); rhc->n_nonempty_instances--; } +static struct rhc_instance *oldest_nonempty_instance (const struct dds_rhc_default *rhc) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, ddsrt_circlist_oldest (&rhc->nonempty_instances)); +} + +static struct rhc_instance *latest_nonempty_instance (const struct dds_rhc_default *rhc) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, ddsrt_circlist_latest (&rhc->nonempty_instances)); +} + +static struct rhc_instance *next_nonempty_instance (const struct rhc_instance *inst) +{ + return DDSRT_FROM_CIRCLIST (struct rhc_instance, nonempty_list, inst->nonempty_list.next); +} + #ifdef DDSI_INCLUDE_LIFESPAN static void drop_expired_samples (struct dds_rhc_default *rhc, struct rhc_sample *sample) { @@ -622,7 +607,37 @@ nn_mtime_t dds_rhc_default_sample_expired_cb(void *hc, nn_mtime_t tnow) } #endif /* DDSI_INCLUDE_LIFESPAN */ -struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_globals *gv, const struct ddsi_sertopic *topic, bool xchecks) +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +nn_mtime_t dds_rhc_default_deadline_missed_cb(void *hc, nn_mtime_t tnow) +{ + struct dds_rhc_default *rhc = hc; + void *vinst; + nn_mtime_t tnext; + ddsrt_mutex_lock (&rhc->lock); + while ((tnext = deadline_next_missed_locked (&rhc->deadline, tnow, &vinst)).v == 0) + { + struct rhc_instance *inst = vinst; + deadline_reregister_instance_locked (&rhc->deadline, &inst->deadline, tnow); + + inst->wr_iid_islive = 0; + + status_cb_data_t cb_data; + cb_data.raw_status_id = (int) DDS_REQUESTED_DEADLINE_MISSED_STATUS_ID; + cb_data.extra = 0; + cb_data.handle = inst->iid; + cb_data.add = true; + ddsrt_mutex_unlock (&rhc->lock); + dds_reader_status_cb (&rhc->reader->m_entity, &cb_data); + ddsrt_mutex_lock (&rhc->lock); + + tnow = now_mt (); + } + ddsrt_mutex_unlock (&rhc->lock); + return tnext; +} +#endif /* DDSI_INCLUDE_DEADLINE_MISSED */ + +struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct ddsi_domaingv *gv, const struct ddsi_sertopic *topic, bool xchecks) { struct dds_rhc_default *rhc = ddsrt_malloc (sizeof (*rhc)); memset (rhc, 0, sizeof (*rhc)); @@ -631,6 +646,7 @@ struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_global lwregs_init (&rhc->registrations); ddsrt_mutex_init (&rhc->lock); rhc->instances = ddsrt_hh_new (1, instance_iid_hash, instance_iid_eq); + ddsrt_circlist_init (&rhc->nonempty_instances); rhc->topic = topic; rhc->reader = reader; rhc->tkmap = gv->m_tkmap; @@ -641,6 +657,11 @@ struct dds_rhc *dds_rhc_default_new_xchecks (dds_reader *reader, struct q_global lifespan_init (gv, &rhc->lifespan, offsetof(struct dds_rhc_default, lifespan), offsetof(struct rhc_sample, lifespan), dds_rhc_default_sample_expired_cb); #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + rhc->deadline.dur = (reader != NULL) ? reader->m_entity.m_qos->deadline.deadline : DDS_INFINITY; + deadline_init (gv, &rhc->deadline, offsetof(struct dds_rhc_default, deadline), offsetof(struct rhc_instance, deadline), dds_rhc_default_deadline_missed_cb); +#endif + return &rhc->common; } @@ -661,6 +682,8 @@ static void dds_rhc_default_set_qos (struct dds_rhc_default * rhc, const dds_qos 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; + /* FIXME: updating deadline duration not yet supported + rhc->deadline.dur = qos->deadline.deadline; */ } static bool eval_predicate_sample (const struct dds_rhc_default *rhc, const struct ddsi_serdata *sample, bool (*pred) (const void *sample)) @@ -758,6 +781,10 @@ static void free_empty_instance (struct rhc_instance *inst, struct dds_rhc_defau { assert (inst_is_empty (inst)); ddsi_tkmap_instance_unref (rhc->tkmap, inst->tk); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (!inst->isdisposed) + deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); +#endif ddsrt_free (inst); } @@ -812,9 +839,15 @@ static void dds_rhc_default_free (struct dds_rhc_default *rhc) #ifdef DDSI_INCLUDE_LIFESPAN dds_rhc_default_sample_expired_cb (rhc, NN_MTIME_NEVER); lifespan_fini (&rhc->lifespan); +#endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_stop (&rhc->deadline); #endif ddsrt_hh_enum (rhc->instances, free_instance_rhc_free_wrap, rhc); - assert (rhc->nonempty_instances == NULL); + assert (ddsrt_circlist_isempty (&rhc->nonempty_instances)); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_fini (&rhc->deadline); +#endif ddsrt_hh_free (rhc->instances); lwregs_fini (&rhc->registrations); if (rhc->qcond_eval_samplebuf != NULL) @@ -886,7 +919,6 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, { /* 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; @@ -908,7 +940,6 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, 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; @@ -919,7 +950,6 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, } /* 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; @@ -930,7 +960,6 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, } /* add new latest sample */ - s = alloc_sample (inst); inst_clear_invsample_if_exists (rhc, inst, trig_qc); if (inst->latest == NULL) @@ -956,6 +985,11 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, s->lifespan.t_expire = wrinfo->lifespan_exp; lifespan_register_sample_locked (&rhc->lifespan, &s->lifespan); #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + /* Only renew the deadline missed counter in case the sample is actually stored in the rhc */ + if (!inst->isdisposed) + deadline_renew_instance_locked (&rhc->deadline, &inst->deadline); +#endif s->conds = 0; if (rhc->nqconds != 0) @@ -1317,7 +1351,7 @@ static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance return notify_data_available; } -static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) +static struct rhc_instance *alloc_new_instance (struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { struct rhc_instance *inst; @@ -1348,6 +1382,11 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh } } +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (!inst->isdisposed) + deadline_register_instance_locked (&rhc->deadline, &inst->deadline, now_mt ()); +#endif + return inst; } @@ -1508,8 +1547,6 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons cb_data.handle = 0; cb_data.add = true; goto error_or_nochange; - - /* FIXME: deadline (and other) QoS? */ } else { @@ -1559,11 +1596,19 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons TRACE (" disposed->notdisposed"); inst->isdisposed = 0; inst->disposed_gen++; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (!is_dispose) + deadline_register_instance_locked (&rhc->deadline, &inst->deadline, now_mt ()); +#endif } if (is_dispose) { inst->isdisposed = 1; inst_became_disposed = !old_isdisposed; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (inst_became_disposed) + deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); +#endif TRACE (" dispose(%d)", inst_became_disposed); } @@ -1579,9 +1624,24 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons /* 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--; + if (!inst->isdisposed) + { + inst->isdisposed = 1; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); +#endif + } + } + else if (inst->isdisposed) + { + inst->isdisposed = 0; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_register_instance_locked (&rhc->deadline, &inst->deadline, now_mt ()); +#endif + } goto error_or_nochange; } notify_data_available = true; @@ -1718,6 +1778,9 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r if (auto_dispose && !inst->isdisposed) { inst->isdisposed = 1; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); +#endif /* Set invalid sample for disposing it (unregister may also set it for unregistering) */ if (inst->latest) @@ -1966,10 +2029,10 @@ static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** 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) + if (!ddsrt_circlist_isempty (&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 * inst = oldest_nonempty_instance (rhc); struct rhc_instance * const end = inst; do { @@ -2055,7 +2118,7 @@ static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** break; } } - inst = inst->next; + inst = next_nonempty_instance (inst); } while (inst != end && n < max_samples); } @@ -2083,14 +2146,14 @@ static int dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void ** 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) + if (!ddsrt_circlist_isempty (&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 *inst = oldest_nonempty_instance (rhc); unsigned n_insts = rhc->n_nonempty_instances; while (n_insts-- > 0 && n < max_samples) { - struct rhc_instance * const inst1 = inst->next; + struct rhc_instance * const inst1 = next_nonempty_instance (inst); iid = inst->iid; if (handle == DDS_HANDLE_NIL || iid == handle) { @@ -2238,14 +2301,14 @@ static int dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, stru 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) + if (!ddsrt_circlist_isempty (&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 *inst = oldest_nonempty_instance (rhc); unsigned n_insts = rhc->n_nonempty_instances; while (n_insts-- > 0 && n < max_samples) { - struct rhc_instance * const inst1 = inst->next; + struct rhc_instance * const inst1 = next_nonempty_instance (inst); iid = inst->iid; if (handle == DDS_HANDLE_NIL || iid == handle) { @@ -2454,13 +2517,14 @@ static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_ { /* 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) + if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { - struct rhc_instance *inst = rhc->nonempty_instances; + struct rhc_instance *inst = latest_nonempty_instance (rhc); + struct rhc_instance const * const end = inst; do { trigger += rhc_get_cond_trigger (inst, cond); - inst = inst->next; - } while (inst != rhc->nonempty_instances); + inst = next_nonempty_instance (inst); + } while (inst != end); } } else @@ -2904,26 +2968,25 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond { 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); + assert (ddsrt_circlist_isempty (&rhc->nonempty_instances)); } else { - struct rhc_instance *prev, *end; - assert (rhc->nonempty_instances != NULL); - prev = rhc->nonempty_instances->prev; - end = rhc->nonempty_instances; - inst = rhc->nonempty_instances; + assert (!ddsrt_circlist_isempty (&rhc->nonempty_instances)); + struct ddsrt_circlist_elem const *prev = rhc->nonempty_instances.latest->prev; + inst = latest_nonempty_instance (rhc); + struct rhc_instance const * const end = inst; n_nonempty_instances = 0; do { assert (!inst_is_empty (inst)); - assert (prev->next == inst); - assert (inst->prev == prev); - prev = inst; - inst = inst->next; + assert (prev->next == &inst->nonempty_list); + assert (inst->nonempty_list.prev == prev); + prev = &inst->nonempty_list; + inst = next_nonempty_instance (inst); n_nonempty_instances++; } while (inst != end); assert (rhc->n_nonempty_instances == n_nonempty_instances); diff --git a/src/core/ddsc/src/dds_serdata_builtintopic.c b/src/core/ddsc/src/dds_serdata_builtintopic.c index 6f450c8..84063f0 100644 --- a/src/core/ddsc/src/dds_serdata_builtintopic.c +++ b/src/core/ddsc/src/dds_serdata_builtintopic.c @@ -19,8 +19,7 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" -#include "dds/ddsi/q_plist.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds__serdata_builtintopic.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/q_entity.h" @@ -60,7 +59,7 @@ static void serdata_builtin_free(struct ddsi_serdata *dcmn) { struct ddsi_serdata_builtintopic *d = (struct ddsi_serdata_builtintopic *)dcmn; if (d->c.kind == SDK_DATA) - nn_xqos_fini (&d->xqos); + ddsi_xqos_fini (&d->xqos); ddsrt_free (d); } @@ -73,13 +72,13 @@ static struct ddsi_serdata_builtintopic *serdata_builtin_new(const struct ddsi_s static void from_entity_pp (struct ddsi_serdata_builtintopic *d, const struct participant *pp) { - nn_xqos_copy(&d->xqos, &pp->plist->qos); + ddsi_xqos_copy(&d->xqos, &pp->plist->qos); d->pphandle = pp->e.iid; } static void from_entity_proxypp (struct ddsi_serdata_builtintopic *d, const struct proxy_participant *proxypp) { - nn_xqos_copy(&d->xqos, &proxypp->plist->qos); + ddsi_xqos_copy(&d->xqos, &proxypp->plist->qos); d->pphandle = proxypp->e.iid; } @@ -100,14 +99,14 @@ static void set_topic_type_from_sertopic (struct ddsi_serdata_builtintopic *d, c static void from_entity_rd (struct ddsi_serdata_builtintopic *d, const struct reader *rd) { d->pphandle = rd->c.pp->e.iid; - nn_xqos_copy(&d->xqos, rd->xqos); + ddsi_xqos_copy(&d->xqos, rd->xqos); set_topic_type_from_sertopic(d, rd->topic); } static void from_entity_prd (struct ddsi_serdata_builtintopic *d, const struct proxy_reader *prd) { d->pphandle = prd->c.proxypp->e.iid; - nn_xqos_copy(&d->xqos, prd->c.xqos); + ddsi_xqos_copy(&d->xqos, prd->c.xqos); assert (d->xqos.present & QP_TOPIC_NAME); assert (d->xqos.present & QP_TYPE_NAME); } @@ -115,14 +114,14 @@ static void from_entity_prd (struct ddsi_serdata_builtintopic *d, const struct p static void from_entity_wr (struct ddsi_serdata_builtintopic *d, const struct writer *wr) { d->pphandle = wr->c.pp->e.iid; - nn_xqos_copy(&d->xqos, wr->xqos); + ddsi_xqos_copy(&d->xqos, wr->xqos); set_topic_type_from_sertopic(d, wr->topic); } static void from_entity_pwr (struct ddsi_serdata_builtintopic *d, const struct proxy_writer *pwr) { d->pphandle = pwr->c.proxypp->e.iid; - nn_xqos_copy(&d->xqos, pwr->c.xqos); + ddsi_xqos_copy(&d->xqos, pwr->c.xqos); assert (d->xqos.present & QP_TOPIC_NAME); assert (d->xqos.present & QP_TYPE_NAME); } @@ -132,7 +131,7 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi /* 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) */ - struct entity_common *entity = entidx_lookup_guid_untyped (tp->gv->entity_index, (const ddsi_guid_t *) keyhash->value); + struct entity_common *entity = entidx_lookup_guid_untyped (tp->c.gv->entity_index, (const ddsi_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) @@ -196,10 +195,10 @@ static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const dds_qos_t *src) old = ddsrt_malloc (sizeof (*old)); else { - nn_xqos_fini (old); + ddsi_xqos_fini (old); } - nn_xqos_init_empty (old); - nn_xqos_mergein_missing (old, src, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); + ddsi_xqos_init_empty (old); + ddsi_xqos_mergein_missing (old, src, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); return old; } @@ -288,6 +287,7 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = { .eqkey = serdata_builtin_eqkey, .free = serdata_builtin_free, .from_ser = 0, + .from_ser_iov = 0, .from_keyhash = ddsi_serdata_builtin_from_keyhash, .from_sample = 0, .to_ser = serdata_builtin_to_ser, diff --git a/src/core/ddsc/src/dds_sertopic_builtintopic.c b/src/core/ddsc/src/dds_sertopic_builtintopic.c index 07f730c..6c9b843 100644 --- a/src/core/ddsc/src/dds_sertopic_builtintopic.c +++ b/src/core/ddsc/src/dds_sertopic_builtintopic.c @@ -25,12 +25,11 @@ /* 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 q_globals *gv) +struct ddsi_sertopic *new_sertopic_builtintopic (enum ddsi_sertopic_builtintopic_type type, const char *name, const char *typename) { struct ddsi_sertopic_builtintopic *tp = ddsrt_malloc (sizeof (*tp)); 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; } @@ -40,6 +39,19 @@ static void sertopic_builtin_free (struct ddsi_sertopic *tp) ddsrt_free (tp); } +static bool sertopic_builtin_equal (const struct ddsi_sertopic *acmn, const struct ddsi_sertopic *bcmn) +{ + const struct ddsi_sertopic_builtintopic *a = (struct ddsi_sertopic_builtintopic *) acmn; + const struct ddsi_sertopic_builtintopic *b = (struct ddsi_sertopic_builtintopic *) bcmn; + return a->type == b->type; +} + +static uint32_t sertopic_builtin_hash (const struct ddsi_sertopic *tpcmn) +{ + const struct ddsi_sertopic_builtintopic *tp = (struct ddsi_sertopic_builtintopic *) tpcmn; + return (uint32_t) tp->type; +} + static void free_pp (void *vsample) { dds_builtintopic_participant_t *sample = vsample; @@ -131,6 +143,8 @@ static void sertopic_builtin_free_samples (const struct ddsi_sertopic *sertopic_ } const struct ddsi_sertopic_ops ddsi_sertopic_ops_builtintopic = { + .equal = sertopic_builtin_equal, + .hash = sertopic_builtin_hash, .free = sertopic_builtin_free, .zero_samples = sertopic_builtin_zero_samples, .realloc_samples = sertopic_builtin_realloc_samples, diff --git a/src/core/ddsc/src/dds_subscriber.c b/src/core/ddsc/src/dds_subscriber.c index 0729064..e501f5b 100644 --- a/src/core/ddsc/src/dds_subscriber.c +++ b/src/core/ddsc/src/dds_subscriber.c @@ -16,7 +16,7 @@ #include "dds__qos.h" #include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsrt/heap.h" #include "dds/version.h" @@ -55,9 +55,9 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implic 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) + ddsi_xqos_mergein_missing (new_qos, qos, DDS_SUBSCRIBER_QOS_MASK); + ddsi_xqos_mergein_missing (new_qos, &participant->m_entity.m_domain->gv.default_xqos_sub, ~(uint64_t)0); + if ((ret = ddsi_xqos_valid (&participant->m_entity.m_domain->gv.logconfig, new_qos)) != DDS_RETCODE_OK) { dds_delete_qos (new_qos); return ret; diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index 4796703..d85eb91 100644 --- a/src/core/ddsc/src/dds_topic.c +++ b/src/core/ddsc/src/dds_topic.c @@ -19,7 +19,6 @@ #include "dds__topic.h" #include "dds__listener.h" #include "dds__participant.h" -#include "dds__stream.h" #include "dds__init.h" #include "dds__domain.h" #include "dds__get_status.h" @@ -30,8 +29,9 @@ #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" +#include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds__serdata_builtintopic.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic) @@ -45,15 +45,6 @@ struct topic_sertopic_node { const struct ddsi_sertopic *st; }; -static int topic_sertopic_node_cmp (const void *va, const void *vb) -{ - 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 bool is_valid_name (const char *name) ddsrt_nonnull_all; static bool is_valid_name (const char *name) @@ -112,164 +103,88 @@ static void dds_topic_status_cb (struct dds_topic *tp) } #endif -struct ddsi_sertopic *dds_topic_lookup (dds_domain *domain, const char *name) +dds_return_t dds_topic_pin (dds_entity_t handle, struct dds_topic **tp) { - 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; -} - -static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_entity_t topic, const char *name) -{ - dds_topic *tp; - if (dds_topic_lock (topic, &tp) != DDS_RETCODE_OK) - return false; - - bool ret; - if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0) - ret = false; - else - { - /* Simply return the same topic, though that is different to the spirit - of the DDS specification, which gives you a unique copy. Giving that - unique copy means there potentially many versions of exactly the same - topic around, and that two entities can be dealing with the same data - even though they have different topics objects (though with the same - name). That I find a confusing model. - - As far as I can tell, the only benefit is the ability to set different - listeners on the various copies of the topic. And that seems to be a - really small benefit. */ - ret = true; - } - dds_topic_unlock (tp); - return ret; -} - -dds_entity_t dds_find_topic (dds_entity_t participant, const char *name) -{ - dds_entity *pe; + struct dds_entity *e; dds_return_t ret; - dds_entity_t topic; - - if (name == NULL) - return DDS_RETCODE_BAD_PARAMETER; - - /* 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) + if ((ret = dds_entity_pin (handle, &e)) < 0) return ret; - if (dds_entity_kind (pe) != DDS_KIND_PARTICIPANT) + if (dds_entity_kind (e) != DDS_KIND_TOPIC) { - dds_entity_unpin (pe); + dds_entity_unpin (e); return DDS_RETCODE_ILLEGAL_OPERATION; } + *tp = (struct dds_topic *) e; + return DDS_RETCODE_OK; +} - 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); - } - } while (topic > 0 && !dds_find_topic_check_and_add_ref (participant, topic, name)); +void dds_topic_unpin (struct dds_topic *tp) +{ + dds_entity_unpin (&tp->m_entity); +} - dds_entity_unpin (pe); - return topic; +void dds_topic_defer_set_qos (struct dds_topic *tp) +{ + struct dds_ktopic * const ktp = tp->m_ktopic; + struct dds_participant * const pp = dds_entity_participant (&tp->m_entity); + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + ++ktp->defer_set_qos; + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); +} + +void dds_topic_allow_set_qos (struct dds_topic *tp) +{ + struct dds_ktopic * const ktp = tp->m_ktopic; + struct dds_participant * const pp = dds_entity_participant (&tp->m_entity); + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + assert (ktp->defer_set_qos > 0); + if (--ktp->defer_set_qos == 0) + ddsrt_cond_broadcast (&pp->m_entity.m_cond); + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); } static dds_return_t dds_topic_delete (dds_entity *e) ddsrt_nonnull_all; static dds_return_t dds_topic_delete (dds_entity *e) { - 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); - } - + struct dds_topic * const tp = (dds_topic *) e; + struct dds_ktopic * const ktp = tp->m_ktopic; + assert (dds_entity_kind (e->m_parent) == DDS_KIND_PARTICIPANT); + dds_participant * const pp = (dds_participant *) e->m_parent; ddsi_sertopic_unref (tp->m_stopic); - ddsrt_mutex_unlock (&dds_global.m_mutex); + + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + if (--ktp->refc == 0) + { + ddsrt_avl_delete (&participant_ktopics_treedef, &pp->m_ktopics, ktp); + dds_delete_qos (ktp->qos); + ddsrt_free (ktp->name); + ddsrt_free (ktp->type_name); + dds_free (ktp); + } + ddsrt_mutex_unlock (&pp->m_entity.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 */ + /* We never actually set the qos of a struct dds_topic and really shouldn't be here, + but the code to check whether set_qos is supported uses the entity's qos_set + function as a proxy. One of the weird things about the topic's set_qos is that + this is called with e == NULL. */ (void) e; (void) qos; (void) enabled; + assert (e == NULL); return DDS_RETCODE_OK; } -static bool dupdef_qos_ok (const dds_qos_t *qos, const dds_topic *tp) +static bool dupdef_qos_ok (const dds_qos_t *qos, const dds_ktopic *ktp) { - if ((qos == NULL) != (tp->m_entity.m_qos == NULL)) + if ((qos == NULL) != (ktp->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) -{ - if (strcmp (a->name_type_name, b->name_type_name) != 0) - return false; - if (a->serdata_basehash != b->serdata_basehash) - return false; - if (a->ops != b->ops) - return false; - if (a->serdata_ops != b->serdata_ops) - return false; - return true; -} - -static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos) -{ - dds_topic *tp; - dds_return_t ret; - - if (dds_topic_lock (topic, &tp) < 0) - return DDS_RETCODE_NOT_FOUND; - - if (dds_entity_participant (&tp->m_entity)->m_entity.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 - { - /* See dds_find_topic_check_and_add_ref */ - ret = DDS_RETCODE_OK; - } - dds_topic_unlock (tp); - return ret; + return dds_qos_equal (ktp->qos, qos); } const struct dds_entity_deriver dds_entity_deriver_topic = { @@ -280,192 +195,192 @@ const struct dds_entity_deriver dds_entity_deriver_topic = { .validate_status = dds_topic_status_validate }; -dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const nn_plist_t *sedp_plist) +/** +* @brief Checks whether a ktopic with the same name exists in the participant, +* and if so, whether it's QoS matches or not. +* +* The set of ktopics is stored in the participant, protected by the participant's +* mutex and the internal state of these ktopics (including the QoS) is also +* protected by that mutex. +* +* @param[out] ktp_out matching ktopic if call was successful, or NULL if no +* ktopic with this name exists +* @param[in] pp pinned & locked participant +* @param[in] name topic name to look for +* @param[in] type_name type name the topic must have +* @param[in] new_qos QoS for the new topic (can be NULL) +* +* @returns success + ktopic, success + NULL or error. +* +* @retval DDS_RETCODE_OK +* ktp_out is either NULL (first attempt at creating this topic), or +* the matching ktopic entity +* @retval DDS_RETCODE_INCONSISTENT_POLICY +* a ktopic exists with differing QoS +* @retval DDS_RETCODE_PRECONDITION_NOT_MET +* a ktopic exists with a different type name +*/ +static dds_return_t lookup_and_check_ktopic (struct dds_ktopic **ktp_out, dds_participant *pp, const char *name, const char *type_name, const dds_qos_t *new_qos) +{ + struct ddsi_domaingv * const gv = &pp->m_entity.m_domain->gv; + struct dds_ktopic *ktp; + if ((ktp = *ktp_out = ddsrt_avl_lookup (&participant_ktopics_treedef, &pp->m_ktopics, name)) == NULL) + { + GVTRACE ("lookup_and_check_ktopic_may_unlock_pp: no such ktopic\n"); + return DDS_RETCODE_OK; + } + else if (strcmp (ktp->type_name, type_name) != 0) + { + GVTRACE ("lookup_and_check_ktopic_may_unlock_pp: ktp %p typename %s mismatch\n", (void *) ktp, ktp->type_name); + return DDS_RETCODE_PRECONDITION_NOT_MET; + } + else if (!dupdef_qos_ok (new_qos, ktp)) + { + GVTRACE ("lookup_and_check_ktopic_may_unlock_pp: ktp %p qos mismatch\n", (void *) ktp); + return DDS_RETCODE_INCONSISTENT_POLICY; + } + else + { + GVTRACE ("lookup_and_check_ktopic_may_unlock_pp: ktp %p reuse\n", (void *) ktp); + return DDS_RETCODE_OK; + } +} + +static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct dds_ktopic *ktp, bool implicit, struct ddsi_sertopic *sertopic_registered, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) +{ + dds_entity_t hdl; + dds_topic *tp = dds_alloc (sizeof (*tp)); + hdl = dds_entity_init (&tp->m_entity, &pp->m_entity, DDS_KIND_TOPIC, implicit, NULL, listener, DDS_TOPIC_STATUS_MASK); + tp->m_entity.m_iid = ddsi_iid_gen (); + dds_entity_register_child (&pp->m_entity, &tp->m_entity); + tp->m_ktopic = ktp; + tp->m_stopic = sertopic_registered; + + /* Publish Topic */ + if (sedp_plist) + { + struct participant *ddsi_pp; + ddsi_plist_t plist; + + thread_state_awake (lookup_thread_state (), &pp->m_entity.m_domain->gv); + ddsi_pp = entidx_lookup_participant_guid (pp->m_entity.m_domain->gv.entity_index, &pp->m_entity.m_guid); + assert (ddsi_pp); + + ddsi_plist_init_empty (&plist); + ddsi_plist_mergein_missing (&plist, sedp_plist, ~(uint64_t)0, ~(uint64_t)0); + ddsi_xqos_mergein_missing (&plist.qos, ktp->qos, ~(uint64_t)0); + sedp_write_topic (ddsi_pp, &plist); + ddsi_plist_fini (&plist); + thread_state_asleep (lookup_thread_state ()); + } + + dds_entity_init_complete (&tp->m_entity); + return hdl; +} + +dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) { dds_return_t rc; - dds_participant *par; - dds_entity *par_ent; - dds_topic *top; + dds_participant *pp; dds_qos_t *new_qos = NULL; dds_entity_t hdl; - struct participant *ddsi_pp; + struct ddsi_sertopic *sertopic_registered; 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; - /* Verify that we've been given a participant, not strictly necessary - because dds_participant_lock below checks it, but this is more - obvious */ - if (dds_entity_kind (par_ent) != DDS_KIND_PARTICIPANT) { - dds_entity_unpin (par_ent); - return DDS_RETCODE_ILLEGAL_OPERATION; + dds_entity *par_ent; + if ((rc = dds_entity_pin (participant, &par_ent)) < 0) + return rc; + if (dds_entity_kind (par_ent) != DDS_KIND_PARTICIPANT) + { + dds_entity_unpin (par_ent); + return DDS_RETCODE_ILLEGAL_OPERATION; + } + pp = (struct dds_participant *) par_ent; } new_qos = dds_create_qos (); if (qos) - nn_xqos_mergein_missing (new_qos, qos, DDS_TOPIC_QOS_MASK); + ddsi_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); + * ddsi_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 + * but the crazy defaults of the DDS specification has a default setting + * for reliability that is 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; - } - } - 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); - - rc = create_topic_topic_arbitrary_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: 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 ddsi_domaingv * const gv = &pp->m_entity.m_domain->gv; + if ((rc = ddsi_xqos_valid (&gv->logconfig, new_qos)) != DDS_RETCODE_OK) { - struct dds_domain *domain = par->m_entity.m_domain; - - ddsrt_avl_ipath_t ip; - struct topic_sertopic_node *stn; - - ddsrt_mutex_lock (&dds_global.m_mutex); - - 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; - } + dds_delete_qos (new_qos); + dds_entity_unpin (&pp->m_entity); + return rc; } - /* Create topic */ - top = dds_alloc (sizeof (*top)); + /* See if we're allowed to create the topic; ktp is returned pinned & locked + so we can be sure it doesn't disappear and its QoS can't change */ + GVTRACE ("dds_create_topic_arbitrary (pp %p "PGUIDFMT" sertopic %p reg?%s refc %"PRIu32" %s/%s)\n", + (void *) pp, PGUID (pp->m_entity.m_guid), (void *) sertopic, sertopic->gv ? "yes" : "no", + ddsrt_atomic_ld32 (&sertopic->refc), sertopic->name, sertopic->type_name); + ddsrt_mutex_lock (&pp->m_entity.m_mutex); + struct dds_ktopic *ktp; + if ((rc = lookup_and_check_ktopic (&ktp, pp, sertopic->name, sertopic->type_name, new_qos)) != DDS_RETCODE_OK) + { + GVTRACE ("dds_create_topic_arbitrary: failed after compatibility check: %s\n", dds_strretcode (rc)); + dds_participant_unlock (pp); + dds_delete_qos (new_qos); + return rc; + } + + /* Create a ktopic if it doesn't exist yet, else reference existing one and delete the + unneeded "new_qos". */ + if (ktp == NULL) + { + ktp = dds_alloc (sizeof (*ktp)); + ktp->refc = 1; + ktp->defer_set_qos = 0; + ktp->qos = new_qos; + /* have to copy these because the ktopic can outlast any specific sertopic */ + ktp->name = ddsrt_strdup (sertopic->name); + ktp->type_name = ddsrt_strdup (sertopic->type_name); + ddsrt_avl_insert (&participant_ktopics_treedef, &pp->m_ktopics, ktp); + GVTRACE ("create_and_lock_ktopic: ktp %p\n", (void *) ktp); + } + else + { + ktp->refc++; + dds_delete_qos (new_qos); + } + + /* Sertopic: re-use a previously registered one if possible, else register this one */ + { + ddsrt_mutex_lock (&gv->sertopics_lock); + if ((sertopic_registered = ddsi_sertopic_lookup_locked (gv, sertopic)) != NULL) + GVTRACE ("dds_create_topic_arbitrary: reuse sertopic %p\n", (void *) sertopic_registered); + else + { + GVTRACE ("dds_create_topic_arbitrary: register new sertopic %p\n", (void *) sertopic); + ddsi_sertopic_register_locked (gv, sertopic); + sertopic_registered = sertopic; + } + ddsrt_mutex_unlock (&gv->sertopics_lock); + } + + /* Create topic referencing ktopic & sertopic_registered */ /* FIXME: setting "implicit" based on sertopic->ops is a hack */ - hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, (sertopic->ops == &ddsi_sertopic_ops_builtintopic), 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; - - /* Publish Topic */ - thread_state_awake (lookup_thread_state (), &par->m_entity.m_domain->gv); - ddsi_pp = entidx_lookup_participant_guid (par->m_entity.m_domain->gv.entity_index, &par->m_entity.m_guid); - assert (ddsi_pp); - if (sedp_plist) - { - nn_plist_t plist; - nn_plist_init_empty (&plist); - 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_entity_init_complete (&top->m_entity); - dds_participant_unlock (par); - dds_entity_unpin (par_ent); + hdl = create_topic_pp_locked (pp, ktp, (sertopic_registered->ops == &ddsi_sertopic_ops_builtintopic), sertopic_registered, listener, sedp_plist); + dds_participant_unlock (pp); + GVTRACE ("dds_create_topic_arbitrary: new topic %"PRId32"\n", hdl); 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; } -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_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 ddsi_plist_t *sedp_plist) { assert(sertopic); assert(sertopic->name); @@ -477,7 +392,7 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s 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) { struct ddsi_sertopic_default *st; - nn_plist_t plist; + ddsi_plist_t plist; dds_entity_t hdl; struct dds_entity *ppent; dds_return_t ret; @@ -493,17 +408,23 @@ dds_entity_t dds_create_topic (dds_entity_t participant, const dds_topic_descrip 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; + st->type.m_size = desc->m_size; + st->type.m_align = desc->m_align; + st->type.m_flagset = desc->m_flagset; + st->type.m_nkeys = desc->m_nkeys; + st->type.m_keys = ddsrt_malloc (st->type.m_nkeys * sizeof (*st->type.m_keys)); + for (uint32_t i = 0; i < st->type.m_nkeys; i++) + st->type.m_keys[i] = desc->m_keys[i].m_index; + st->type.m_nops = dds_stream_countops (desc->m_ops); + st->type.m_ops = ddsrt_memdup (desc->m_ops, st->type.m_nops * sizeof (*st->type.m_ops)); /* Check if topic cannot be optimised (memcpy marshal) */ - if (!(desc->m_flagset & DDS_TOPIC_NO_OPTIMIZE)) { - st->opt_size = dds_stream_check_optimize (desc); + if (!(st->type.m_flagset & DDS_TOPIC_NO_OPTIMIZE)) { + st->opt_size = dds_stream_check_optimize (&st->type); 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); + ddsi_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); @@ -526,10 +447,51 @@ dds_entity_t dds_create_topic (dds_entity_t participant, const dds_topic_descrip hdl = dds_create_topic_arbitrary (participant, &st->c, qos, listener, &plist); ddsi_sertopic_unref (&st->c); dds_entity_unpin (ppent); - nn_plist_fini (&plist); + ddsi_plist_fini (&plist); return hdl; } +dds_entity_t dds_find_topic (dds_entity_t participant, const char *name) +{ + dds_participant *pp; + dds_return_t rc; + + if (name == NULL) + return DDS_RETCODE_BAD_PARAMETER; + + if ((rc = dds_participant_lock (participant, &pp)) < 0) + return rc; + + ddsrt_avl_iter_t it; + for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &pp->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it)) + { + if (dds_entity_kind (e) != DDS_KIND_TOPIC) + continue; + + struct dds_entity *x; + if (dds_entity_pin (e->m_hdllink.hdl, &x) != DDS_RETCODE_OK) + continue; + + struct dds_topic * const tp = (struct dds_topic *) e; + if (x != e || strcmp (tp->m_ktopic->name, name) != 0) + { + dds_entity_unpin (x); + continue; + } + + struct ddsi_sertopic * const sertopic = ddsi_sertopic_ref (tp->m_stopic); + struct dds_ktopic * const ktp = tp->m_ktopic; + ktp->refc++; + dds_entity_unpin (x); + + dds_entity_t hdl = create_topic_pp_locked (pp, ktp, false, sertopic, NULL, NULL); + dds_participant_unlock (pp); + return hdl; + } + dds_participant_unlock (pp); + return DDS_RETCODE_PRECONDITION_NOT_MET; +} + static bool dds_topic_chaining_filter (const void *sample, void *ctx) { dds_topic_filter_fn realf = (dds_topic_filter_fn) ctx; @@ -602,10 +564,10 @@ dds_return_t dds_get_name (dds_entity_t topic, char *name, size_t size) if (size <= 0 || name == NULL) return DDS_RETCODE_BAD_PARAMETER; name[0] = '\0'; - if ((ret = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) + if ((ret = dds_topic_pin (topic, &t)) != DDS_RETCODE_OK) return ret; (void) snprintf (name, size, "%s", t->m_stopic->name); - dds_topic_unlock (t); + dds_topic_unpin (t); return DDS_RETCODE_OK; } @@ -616,10 +578,10 @@ dds_return_t dds_get_type_name (dds_entity_t topic, char *name, size_t size) if (size <= 0 || name == NULL) return DDS_RETCODE_BAD_PARAMETER; name[0] = '\0'; - if ((ret = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) + if ((ret = dds_topic_pin (topic, &t)) != DDS_RETCODE_OK) return ret; (void) snprintf (name, size, "%s", t->m_stopic->type_name); - dds_topic_unlock (t); + dds_topic_unpin (t); return DDS_RETCODE_OK; } diff --git a/src/core/ddsc/src/dds_whc.c b/src/core/ddsc/src/dds_whc.c index 3634ca7..9451abd 100644 --- a/src/core/ddsc/src/dds_whc.c +++ b/src/core/ddsc/src/dds_whc.c @@ -22,14 +22,20 @@ #ifdef DDSI_INCLUDE_LIFESPAN #include "dds/ddsi/ddsi_lifespan.h" #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +#include "dds/ddsi/ddsi_deadline.h" +#endif #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_freelist.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_entity.h" #include "dds__whc.h" +#include "dds__entity.h" +#include "dds__writer.h" #define USE_EHH 0 @@ -42,7 +48,7 @@ struct whc_node { seqno_t seq; uint64_t total_bytes; /* cumulative number of bytes up to and including this node */ size_t size; - struct nn_plist *plist; /* 0 if nothing special */ + struct ddsi_plist *plist; /* 0 if nothing special */ 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; @@ -66,6 +72,9 @@ struct whc_idxnode { seqno_t prune_seq; struct ddsi_tkmap_instance *tk; uint32_t headidx; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + struct deadline_elem deadline; /* list element for deadline missed */ +#endif struct whc_node *hist[]; }; @@ -76,6 +85,15 @@ struct whc_seq_entry { }; #endif +struct whc_writer_info { + dds_writer * writer; /* can be NULL, eg in case of whc for built-in writers */ + unsigned is_transient_local: 1; + unsigned has_deadline: 1; + 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) */ +}; + struct whc_impl { struct whc common; ddsrt_mutex_t lock; @@ -84,13 +102,10 @@ struct whc_impl { size_t sample_overhead; uint32_t fragment_size; uint64_t total_bytes; /* total number of bytes pushed in */ - unsigned is_transient_local: 1; unsigned xchecks: 1; - struct q_globals *gv; + struct ddsi_domaingv *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) */ + struct whc_writer_info wrinfo; 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 */ @@ -104,6 +119,9 @@ struct whc_impl { #ifdef DDSI_INCLUDE_LIFESPAN struct lifespan_adm lifespan; /* Lifespan administration */ #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + struct deadline_adm deadline; /* Deadline missed administration */ +#endif }; struct whc_sample_iter_impl { @@ -137,7 +155,7 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se 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 int whc_default_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); +static int whc_default_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_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); @@ -373,45 +391,91 @@ static nn_mtime_t whc_sample_expired_cb(void *hc, nn_mtime_t tnow) } #endif -struct whc *whc_new (struct q_globals *gv, int is_transient_local, uint32_t hdepth, uint32_t tldepth) +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +static nn_mtime_t whc_deadline_missed_cb(void *hc, nn_mtime_t tnow) +{ + struct whc_impl *whc = hc; + void *vidxnode; + nn_mtime_t tnext; + ddsrt_mutex_lock (&whc->lock); + while ((tnext = deadline_next_missed_locked (&whc->deadline, tnow, &vidxnode)).v == 0) + { + struct whc_idxnode *idxnode = vidxnode; + deadline_reregister_instance_locked (&whc->deadline, &idxnode->deadline, tnow); + + status_cb_data_t cb_data; + cb_data.raw_status_id = (int) DDS_OFFERED_DEADLINE_MISSED_STATUS_ID; + cb_data.extra = 0; + cb_data.handle = 0; + cb_data.add = true; + ddsrt_mutex_unlock (&whc->lock); + dds_writer_status_cb (&whc->wrinfo.writer->m_entity, &cb_data); + ddsrt_mutex_lock (&whc->lock); + + tnow = now_mt (); + } + ddsrt_mutex_unlock (&whc->lock); + return tnext; +} +#endif + +struct whc_writer_info *whc_make_wrinfo (struct dds_writer *wr, const dds_qos_t *qos) +{ + struct whc_writer_info *wrinfo = ddsrt_malloc (sizeof (*wrinfo)); + wrinfo->writer = wr; + wrinfo->is_transient_local = (qos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); + wrinfo->has_deadline = (qos->deadline.deadline != DDS_INFINITY); + wrinfo->hdepth = (qos->history.kind == DDS_HISTORY_KEEP_ALL) ? 0 : (unsigned) qos->history.depth; + if (!wrinfo->is_transient_local) + wrinfo->tldepth = 0; + else + wrinfo->tldepth = (qos->durability_service.history.kind == DDS_HISTORY_KEEP_ALL) ? 0 : (unsigned) qos->durability_service.history.depth; + wrinfo->idxdepth = wrinfo->hdepth > wrinfo->tldepth ? wrinfo->hdepth : wrinfo->tldepth; + return wrinfo; +} + +void whc_free_wrinfo (struct whc_writer_info *wrinfo) +{ + ddsrt_free (wrinfo); +} + +struct whc *whc_new (struct ddsi_domaingv *gv, const struct whc_writer_info *wrinfo) { 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 ((wrinfo->hdepth == 0 || wrinfo->tldepth <= wrinfo->hdepth) || wrinfo->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; + memcpy (&whc->wrinfo, wrinfo, sizeof (*wrinfo)); whc->seq_size = 0; whc->max_drop_seq = 0; whc->unacked_bytes = 0; whc->total_bytes = 0; whc->sample_overhead = sample_overhead; whc->fragment_size = gv->config.fragment_size; + whc->idx_hash = ddsrt_hh_new (1, whc_idxnode_hash_key, whc_idxnode_eq_key); #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 (1, whc_node_hash, whc_node_eq); #endif - if (whc->idxdepth > 0) - whc->idx_hash = ddsrt_hh_new (1, whc_idxnode_hash_key, whc_idxnode_eq_key); - else - whc->idx_hash = NULL; - #ifdef DDSI_INCLUDE_LIFESPAN lifespan_init (gv, &whc->lifespan, offsetof(struct whc_impl, lifespan), offsetof(struct whc_node, lifespan), whc_sample_expired_cb); #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + whc->deadline.dur = (wrinfo->writer != NULL) ? wrinfo->writer->m_entity.m_qos->deadline.deadline : DDS_INFINITY; + deadline_init (gv, &whc->deadline, offsetof(struct whc_impl, deadline), offsetof(struct whc_idxnode, deadline), whc_deadline_missed_cb); +#endif + /* seq interval tree: always has an "open" node */ ddsrt_avl_init (&whc_seq_treedef, &whc->seq); intv = ddsrt_malloc (sizeof (*intv)); @@ -434,7 +498,7 @@ static void free_whc_node_contents (struct whc_node *whcn) { ddsi_serdata_unref (whcn->serdata); if (whcn->plist) { - nn_plist_fini (whcn->plist); + ddsi_plist_fini (whcn->plist); ddsrt_free (whcn->plist); } } @@ -450,14 +514,19 @@ void whc_default_free (struct whc *whc_generic) lifespan_fini (&whc->lifespan); #endif - if (whc->idx_hash) - { - 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); - } +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_stop (&whc->deadline); + ddsrt_mutex_lock (&whc->lock); + deadline_clear (&whc->deadline); + ddsrt_mutex_unlock (&whc->lock); + deadline_fini (&whc->deadline); +#endif + + struct ddsrt_hh_iter it; + struct whc_idxnode *idxn; + for (idxn = ddsrt_hh_iter_first (whc->idx_hash, &it); idxn != NULL; idxn = ddsrt_hh_iter_next (&it)) + ddsrt_free (idxn); + ddsrt_hh_free (whc->idx_hash); { struct whc_node *whcn = whc->maxseq_node; @@ -577,31 +646,19 @@ static seqno_t whc_default_next_seq (const struct whc *whc_generic, seqno_t seq) return nseq; } -static void delete_one_sample_from_idx (struct whc_impl *whc, struct whc_node *whcn) +static void delete_one_sample_from_idx (struct whc_node *whcn) { struct whc_idxnode * const idxn = whcn->idxnode; assert (idxn != NULL); assert (idxn->hist[idxn->headidx] != NULL); assert (idxn->hist[whcn->idxnode_pos] == whcn); - if (whcn->idxnode_pos != idxn->headidx) - idxn->hist[whcn->idxnode_pos] = NULL; - else - { -#ifndef NDEBUG - 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 (whc->tkmap, idxn->tk); - ddsrt_free (idxn); - } + idxn->hist[whcn->idxnode_pos] = NULL; whcn->idxnode = NULL; } static void free_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop_seq, struct whc_idxnode *idxn) { - for (uint32_t i = 0; i < whc->idxdepth; i++) + for (uint32_t i = 0; i < whc->wrinfo.idxdepth; i++) { if (idxn->hist[i]) { @@ -622,6 +679,9 @@ static void delete_one_instance_from_idx (struct whc_impl *whc, seqno_t max_drop { if (!ddsrt_hh_remove (whc->idx_hash, idxn)) assert (0); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_unregister_instance_locked (&whc->deadline, &idxn->deadline); +#endif free_one_instance_from_idx (whc, max_drop_seq, idxn); } @@ -631,9 +691,9 @@ static int whcn_in_tlidx (const struct whc_impl *whc, const struct whc_idxnode * return 0; else { - uint32_t d = (idxn->headidx + (pos > idxn->headidx ? whc->idxdepth : 0)) - pos; - assert (d < whc->idxdepth); - return d < whc->tldepth; + uint32_t d = (idxn->headidx + (pos > idxn->headidx ? whc->wrinfo.idxdepth : 0)) - pos; + assert (d < whc->wrinfo.idxdepth); + return d < whc->wrinfo.tldepth; } } @@ -649,7 +709,7 @@ static uint32_t whc_default_downgrade_to_volatile (struct whc *whc_generic, stru ddsrt_mutex_lock (&whc->lock); check_whc (whc); - if (whc->idxdepth == 0) + if (whc->wrinfo.idxdepth == 0) { /* if not maintaining an index at all, this is nonsense */ get_state_locked (whc, st); @@ -657,19 +717,24 @@ static uint32_t whc_default_downgrade_to_volatile (struct whc *whc_generic, stru return 0; } - assert (!whc->is_transient_local); - if (whc->tldepth > 0) + assert (!whc->wrinfo.is_transient_local); + if (whc->wrinfo.tldepth > 0) { - assert (whc->hdepth == 0 || whc->tldepth <= whc->hdepth); - whc->tldepth = 0; - if (whc->hdepth == 0) + assert (whc->wrinfo.hdepth == 0 || whc->wrinfo.tldepth <= whc->wrinfo.hdepth); + whc->wrinfo.tldepth = 0; + if (whc->wrinfo.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)) - free_one_instance_from_idx (whc, 0, n); + struct whc_idxnode *idxn; + for (idxn = ddsrt_hh_iter_first (whc->idx_hash, &it); idxn != NULL; idxn = ddsrt_hh_iter_next (&it)) + { +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_unregister_instance_locked (&whc->deadline, &idxn->deadline); +#endif + free_one_instance_from_idx (whc, 0, idxn); + } ddsrt_hh_free (whc->idx_hash); - whc->idxdepth = 0; + whc->wrinfo.idxdepth = 0; whc->idx_hash = NULL; } } @@ -711,7 +776,7 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i /* If it is in the tlidx, take it out. Transient-local data never gets here */ if (whcn->idxnode) - delete_one_sample_from_idx (whc, whcn); + delete_one_sample_from_idx (whcn); if (whcn->unacked) { assert (whc->unacked_bytes >= whcn->size); @@ -927,15 +992,27 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se struct whc_node deferred_list_head, *last_to_free = &deferred_list_head; uint32_t ndropped = 0; - if (whc->is_transient_local && whc->tldepth == 0) + whcn = find_nextseq_intv (&intv, whc, whc->max_drop_seq); + if (whc->wrinfo.is_transient_local && whc->wrinfo.tldepth == 0) { - /* KEEP_ALL on transient local, so we can never ever delete anything */ - TRACE (" KEEP_ALL transient-local: do nothing\n"); + /* KEEP_ALL on transient local, so we can never ever delete anything, but + we have to ack the data in whc */ + TRACE (" KEEP_ALL transient-local: ack data\n"); + while (whcn && whcn->seq <= max_drop_seq) + { + if (whcn->unacked) + { + assert (whc->unacked_bytes >= whcn->size); + whc->unacked_bytes -= whcn->size; + whcn->unacked = 0; + } + whcn = whcn->next_seq; + } + whc->max_drop_seq = max_drop_seq; *deferred_free_list = NULL; return 0; } - whcn = find_nextseq_intv (&intv, whc, whc->max_drop_seq); deferred_list_head.next_seq = NULL; prev_seq = whcn ? whcn->prev_seq : NULL; while (whcn && whcn->seq <= max_drop_seq) @@ -982,10 +1059,10 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se 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) + if (whc->wrinfo.tldepth > 0 && whc->wrinfo.idxdepth > whc->wrinfo.tldepth) { - assert (whc->hdepth == whc->idxdepth); - TRACE (" idxdepth %"PRIu32" > tldepth %"PRIu32" > 0 -- must prune\n", whc->idxdepth, whc->tldepth); + assert (whc->wrinfo.hdepth == whc->wrinfo.idxdepth); + TRACE (" idxdepth %"PRIu32" > tldepth %"PRIu32" > 0 -- must prune\n", whc->wrinfo.idxdepth, whc->wrinfo.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 @@ -1010,11 +1087,11 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se idxn->prune_seq = max_drop_seq; idx = idxn->headidx; - cnt = whc->idxdepth - whc->tldepth; + cnt = whc->wrinfo.idxdepth - whc->wrinfo.tldepth; while (cnt--) { struct whc_node *oldn; - if (++idx == whc->idxdepth) + if (++idx == whc->wrinfo.idxdepth) idx = 0; if ((oldn = idxn->hist[idx]) != NULL) { @@ -1061,12 +1138,16 @@ static uint32_t whc_default_remove_acked_messages (struct whc *whc_generic, seqn 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); + tmp.min_seq, tmp.max_seq, whc->max_drop_seq, whc->wrinfo.hdepth, whc->wrinfo.tldepth); } check_whc (whc); - if (whc->idxdepth == 0) + /* In case a deadline is set, a sample may be added to whc temporarily, which could be + stored in acked state. The _noidx variant of removing messages assumes that unacked + data exists in whc. So in case of a deadline, the _full variant is used instead, + even when index depth is 0 */ + if (whc->wrinfo.idxdepth == 0 && !whc->wrinfo.has_deadline && !whc->wrinfo.is_transient_local) 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); @@ -1075,13 +1156,11 @@ static uint32_t whc_default_remove_acked_messages (struct whc *whc_generic, seqn return cnt; } -static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata) +static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata) { struct whc_node *newn = NULL; #ifndef DDSI_INCLUDE_LIFESPAN - /* FIXME: the 'exp' arg is used for lifespan, refactor this parameter to a struct 'writer info' - that contains both lifespan and deadline info of the writer */ DDSRT_UNUSED_ARG (exp); #endif @@ -1149,7 +1228,7 @@ static struct whc_node *whc_default_insert_seq (struct whc_impl *whc, seqno_t ma return newn; } -static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) +static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { struct whc_impl * const whc = (struct whc_impl *)whc_generic; struct whc_node *newn = NULL; @@ -1172,7 +1251,7 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se TRACE ("whc_default_insert(%p max_drop_seq %"PRId64" seq %"PRId64" exp %"PRId64" plist %p serdata %p:%"PRIx32")\n", (void *) whc, max_drop_seq, seq, exp.v, (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); + whcst.min_seq, whcst.max_seq, whc->max_drop_seq, whc->wrinfo.hdepth, whc->wrinfo.tldepth); } assert (max_drop_seq < MAX_SEQ_NUMBER); @@ -1189,7 +1268,7 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se 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) + if (serdata->kind == SDK_EMPTY) { TRACE (" empty or no hist\n"); ddsrt_mutex_unlock (&whc->lock); @@ -1215,42 +1294,50 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se } else { - struct whc_node *oldn; - if (++idxn->headidx == whc->idxdepth) - idxn->headidx = 0; - if ((oldn = idxn->hist[idxn->headidx]) != NULL) +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_renew_instance_locked (&whc->deadline, &idxn->deadline); +#endif + if (whc->wrinfo.idxdepth > 0) { - TRACE (" overwrite whcn %p", (void *)oldn); - oldn->idxnode = NULL; - } - idxn->hist[idxn->headidx] = newn; - newn->idxnode = idxn; - newn->idxnode_pos = idxn->headidx; - - if (oldn && (whc->hdepth > 0 || oldn->seq <= max_drop_seq)) - { - 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). */ - if (seq <= max_drop_seq && whc->tldepth > 0 && 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) + struct whc_node *oldn; + if (++idxn->headidx == whc->wrinfo.idxdepth) + idxn->headidx = 0; + if ((oldn = idxn->hist[idxn->headidx]) != NULL) { - TRACE (" prune tl whcn %p", (void *)oldn); - assert (oldn != whc->maxseq_node); - whc_delete_one (whc, oldn); + TRACE (" overwrite whcn %p", (void *)oldn); + oldn->idxnode = NULL; } + idxn->hist[idxn->headidx] = newn; + newn->idxnode = idxn; + newn->idxnode_pos = idxn->headidx; + + if (oldn && (whc->wrinfo.hdepth > 0 || oldn->seq <= max_drop_seq) && whc->wrinfo.tldepth > 0) + { + TRACE (" prune whcn %p", (void *)oldn); + assert (oldn != whc->maxseq_node || whc->wrinfo.has_deadline); + whc_delete_one (whc, oldn); + if (oldn == whc->maxseq_node) + whc->maxseq_node = whc_findmax_procedurally (whc); + } + + /* 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). */ + if (seq <= max_drop_seq && whc->wrinfo.tldepth > 0 && whc->wrinfo.idxdepth > whc->wrinfo.tldepth) + { + uint32_t pos = idxn->headidx + whc->wrinfo.idxdepth - whc->wrinfo.tldepth; + if (pos >= whc->wrinfo.idxdepth) + pos -= whc->wrinfo.idxdepth; + if ((oldn = idxn->hist[pos]) != NULL) + { + TRACE (" prune tl whcn %p", (void *)oldn); + assert (oldn != whc->maxseq_node); + whc_delete_one (whc, oldn); + } + } + TRACE ("\n"); } - TRACE ("\n"); } } else @@ -1259,20 +1346,26 @@ static int whc_default_insert (struct whc *whc_generic, seqno_t max_drop_seq, se /* Ignore unregisters, but insert everything else */ if (!(serdata->statusinfo & NN_STATUSINFO_UNREGISTER)) { - idxn = ddsrt_malloc (sizeof (*idxn) + whc->idxdepth * sizeof (idxn->hist[0])); + idxn = ddsrt_malloc (sizeof (*idxn) + whc->wrinfo.idxdepth * sizeof (idxn->hist[0])); 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 (uint32_t i = 1; i < whc->idxdepth; i++) - idxn->hist[i] = NULL; - newn->idxnode = idxn; - newn->idxnode_pos = 0; + if (whc->wrinfo.idxdepth > 0) + { + idxn->hist[0] = newn; + for (uint32_t i = 1; i < whc->wrinfo.idxdepth; i++) + idxn->hist[i] = NULL; + newn->idxnode = idxn; + newn->idxnode_pos = 0; + } if (!ddsrt_hh_add (whc->idx_hash, idxn)) assert (0); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + deadline_register_instance_locked (&whc->deadline, &idxn->deadline, now_mt ()); +#endif } else { @@ -1346,7 +1439,7 @@ static void return_sample_locked (struct whc_impl *whc, struct whc_borrowed_samp ddsi_serdata_unref (sample->serdata); if (sample->plist) { - nn_plist_fini (sample->plist); + ddsi_plist_fini (sample->plist); ddsrt_free (sample->plist); } } diff --git a/src/core/ddsc/src/dds_whc_builtintopic.c b/src/core/ddsc/src/dds_whc_builtintopic.c index 36a27f0..361f515 100644 --- a/src/core/ddsc/src/dds_whc_builtintopic.c +++ b/src/core/ddsc/src/dds_whc_builtintopic.c @@ -19,7 +19,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__serdata_builtintopic.h" #include "dds__whc_builtintopic.h" @@ -143,7 +143,7 @@ static void bwhc_get_state (const struct whc *whc, struct whc_state *st) st->unacked_bytes = 0; } -static int bwhc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) +static int bwhc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { (void)whc; (void)max_drop_seq; diff --git a/src/core/ddsc/src/dds_write.c b/src/core/ddsc/src/dds_write.c index 0f65cc6..7519548 100644 --- a/src/core/ddsc/src/dds_write.c +++ b/src/core/ddsc/src/dds_write.c @@ -18,13 +18,14 @@ #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/ddsi_rhc.h" #include "dds/ddsi/ddsi_serdata.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/ddsi_entity_index.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" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_deliver_locally.h" dds_return_t dds_write (dds_entity_t writer, const void *data) { @@ -71,80 +72,103 @@ dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t tim return ret; } -static dds_return_t try_store (struct ddsi_rhc *rhc, const struct ddsi_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms) +static struct reader *writer_first_in_sync_reader (struct entity_index *entity_index, struct entity_common *wrcmn, ddsrt_avl_iter_t *it) { - while (! ddsi_rhc_store (rhc, pwr_info, payload, tk)) + assert (wrcmn->kind == EK_WRITER); + struct writer *wr = (struct writer *) wrcmn; + struct wr_rd_match *m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->local_readers, it); + return m ? entidx_lookup_reader_guid (entity_index, &m->rd_guid) : NULL; +} + +static struct reader *writer_next_in_sync_reader (struct entity_index *entity_index, ddsrt_avl_iter_t *it) +{ + struct wr_rd_match *m = ddsrt_avl_iter_next (it); + return m ? entidx_lookup_reader_guid (entity_index, &m->rd_guid) : NULL; +} + +struct local_sourceinfo { + const struct ddsi_sertopic *src_topic; + struct ddsi_serdata *src_payload; + struct ddsi_tkmap_instance *src_tk; + nn_mtime_t timeout; +}; + +static struct ddsi_serdata *local_make_sample (struct ddsi_tkmap_instance **tk, struct ddsi_domaingv *gv, struct ddsi_sertopic const * const topic, void *vsourceinfo) +{ + struct local_sourceinfo *si = vsourceinfo; + if (topic == si->src_topic) { - if (*max_block_ms > 0) + *tk = si->src_tk; + /* FIXME: see if this pair of refc increments can't be avoided + They're needed because free_sample_after_delivery will always be called, but + in the common case of a local writer and a single sertopic, make_sample doesn't + actually create a sample, and so free_sample_after_delivery doesn't actually + have to free anything */ + ddsi_tkmap_instance_ref (si->src_tk); + return ddsi_serdata_ref (si->src_payload); + } + else + { + /* ouch ... convert a serdata from one sertopic to another ... */ + ddsrt_iovec_t iov; + uint32_t size = ddsi_serdata_size (si->src_payload); + (void) ddsi_serdata_to_ser_ref (si->src_payload, 0, size, &iov); + struct ddsi_serdata *d = ddsi_serdata_from_ser_iov (topic, si->src_payload->kind, 1, &iov, size); + ddsi_serdata_to_ser_unref (si->src_payload, &iov); + if (d) { - dds_sleepfor (DDS_HEADBANG_TIMEOUT); - *max_block_ms -= DDS_HEADBANG_TIMEOUT; + d->statusinfo = si->src_payload->statusinfo; + d->timestamp = si->src_payload->timestamp; + *tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, d); } else { - return DDS_RETCODE_TIMEOUT; + DDS_CWARNING (&gv->logconfig, "local: deserialization %s/%s failed in topic type conversion\n", topic->name, topic->type_name); } + return d; + } +} + +static dds_return_t local_on_delivery_failure_fastpath (struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, void *vsourceinfo) +{ + (void) fastpath_rdary; + (void) source_entity_locked; + assert (source_entity->kind == EK_WRITER); + struct writer *wr = (struct writer *) source_entity; + struct local_sourceinfo *si = vsourceinfo; + nn_mtime_t tnow = now_mt (); + if (si->timeout.v == 0) + si->timeout = add_duration_to_mtime (tnow, wr->xqos->reliability.max_blocking_time); + if (tnow.v >= si->timeout.v) + return DDS_RETCODE_TIMEOUT; + else + { + dds_sleepfor (DDS_HEADBANG_TIMEOUT); + return DDS_RETCODE_OK; } - return DDS_RETCODE_OK; } static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk) { - dds_return_t ret = DDS_RETCODE_OK; - ddsrt_mutex_lock (&wr->rdary.rdary_lock); - if (wr->rdary.fastpath_ok) - { - struct reader ** const rdary = wr->rdary.rdary; - if (rdary[0]) - { - dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time; - struct ddsi_writer_info pwr_info; - ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos, payload->statusinfo); - 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; - } - } - ddsrt_mutex_unlock (&wr->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; - struct ddsi_writer_info wrinfo; - const struct entity_index *gh = wr->e.gv->entity_index; - dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time; - ddsrt_mutex_unlock (&wr->rdary.rdary_lock); - ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos, payload->statusinfo); - 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 = entidx_lookup_reader_guid (gh, &m->rd_guid)) != NULL) - { - 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, &wrinfo, payload, tk, &max_block_ms)) != DDS_RETCODE_OK) - break; - } - } - ddsrt_mutex_unlock (&wr->e.lock); - } - - if (ret == DDS_RETCODE_TIMEOUT) - { + static const struct deliver_locally_ops deliver_locally_ops = { + .makesample = local_make_sample, + .first_reader = writer_first_in_sync_reader, + .next_reader = writer_next_in_sync_reader, + .on_failure_fastpath = local_on_delivery_failure_fastpath + }; + struct local_sourceinfo sourceinfo = { + .src_topic = wr->topic, + .src_payload = payload, + .src_tk = tk, + .timeout = { 0 }, + }; + dds_return_t rc; + struct ddsi_writer_info wrinfo; + ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos, payload->statusinfo); + rc = deliver_locally_allinsync (wr->e.gv, &wr->e, false, &wr->rdary, &wrinfo, &deliver_locally_ops, &sourceinfo); + if (rc == 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; + return rc; } dds_return_t dds_write_impl (dds_writer *wr, const void * data, dds_time_t tstamp, dds_write_action action) diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index 0dbe254..a2e341f 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -15,7 +15,7 @@ #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/ddsi_domaingv.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_xmsg.h" @@ -50,9 +50,9 @@ static dds_return_t dds_writer_status_validate (uint32_t mask) then status conditions is not triggered. */ -static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data) +void dds_writer_status_cb (void *entity, const struct status_cb_data *data) { - dds_writer * const wr = ventity; + dds_writer * const wr = entity; /* When data is NULL, it means that the DDSI reader is deleted. */ if (data == NULL) @@ -181,7 +181,7 @@ static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all; static void dds_writer_interrupt (dds_entity *e) { - struct q_globals * const gv = &e->m_domain->gv; + struct ddsi_domaingv * const gv = &e->m_domain->gv; thread_state_awake (lookup_thread_state (), gv); unblock_throttled_writer (gv, &e->m_guid); thread_state_asleep (lookup_thread_state ()); @@ -192,7 +192,7 @@ static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all; static void dds_writer_close (dds_entity *e) { struct dds_writer * const wr = (struct dds_writer *) e; - struct q_globals * const gv = &e->m_domain->gv; + struct ddsi_domaingv * const gv = &e->m_domain->gv; struct thread_state1 * const ts1 = lookup_thread_state (); thread_state_awake (ts1, gv); nn_xpack_send (wr->m_xp, false); @@ -223,7 +223,12 @@ static dds_return_t validate_writer_qos (const dds_qos_t *wqos) #ifndef DDSI_INCLUDE_LIFESPAN if (wqos != NULL && (wqos->present & QP_LIFESPAN) && wqos->lifespan.duration != DDS_INFINITY) return DDS_RETCODE_BAD_PARAMETER; -#else +#endif +#ifndef DDSI_INCLUDE_DEADLINE_MISSED + if (wqos != NULL && (wqos->present & QP_DEADLINE) && wqos->deadline.deadline != DDS_INFINITY) + return DDS_RETCODE_BAD_PARAMETER; +#endif +#if defined(DDSI_INCLUDE_LIFESPAN) && defined(DDSI_INCLUDE_DEADLINE_MISSED) DDSRT_UNUSED_ARG (wqos); #endif return DDS_RETCODE_OK; @@ -246,30 +251,6 @@ static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, boo return DDS_RETCODE_OK; } -static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos) -{ - bool handle_as_transient_local; - 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 == 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) - tldepth = 0; - else - { - if (qos->durability_service.history.kind == DDS_HISTORY_KEEP_ALL) - tldepth = 0; - else - tldepth = (unsigned) qos->durability_service.history.depth; - } - return whc_new (&dom->gv, handle_as_transient_local, hdepth, tldepth); -} - const struct dds_entity_deriver dds_entity_deriver_writer = { .interrupt = dds_writer_interrupt, .close = dds_writer_close, @@ -282,12 +263,11 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit { dds_return_t rc; dds_qos_t *wqos; - dds_writer *wr; - dds_entity_t writer; dds_publisher *pub = NULL; - dds_participant *pp; dds_topic *tp; dds_entity_t publisher; + struct whc_writer_info *wrinfo; + bool created_implicit_pub = false; { dds_entity *p_or_p; @@ -304,6 +284,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_entity_unlock (p_or_p); if ((rc = dds_publisher_lock (publisher, &pub)) < 0) return rc; + created_implicit_pub = true; break; default: dds_entity_unlock (p_or_p); @@ -313,28 +294,36 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.data_conn_uc; - if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK) - goto err_tp_lock; + if ((rc = dds_topic_pin (topic, &tp)) != DDS_RETCODE_OK) + goto err_pin_topic; assert (tp->m_stopic); - - pp = dds_entity_participant (&pub->m_entity); - if (pp != dds_entity_participant (&tp->m_entity)) + if (dds_entity_participant (&pub->m_entity) != dds_entity_participant (&tp->m_entity)) { rc = DDS_RETCODE_BAD_PARAMETER; goto err_pp_mismatch; } + /* Prevent set_qos on the topic until writer has been created and registered: we can't + allow a TOPIC_DATA change to ccur before the writer has been created because that + change would then not be published in the discovery/built-in topics. + + Don't keep the participant (which protects the topic's QoS) locked because that + can cause deadlocks for applications creating a reader/writer from within a + publication matched listener (whether the restrictions on what one can do in + listeners are reasonable or not, it used to work so it can be broken arbitrarily). */ + dds_topic_defer_set_qos (tp); + /* Merge Topic & Publisher qos */ wqos = dds_create_qos (); if (qos) - nn_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK); + ddsi_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); + ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); + if (tp->m_ktopic->qos) + ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0); + ddsi_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0); - if ((rc = nn_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 || + if ((rc = ddsi_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) { dds_delete_qos(wqos); @@ -342,17 +331,18 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit } /* Create writer */ - wr = dds_alloc (sizeof (*wr)); - writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK); - + struct dds_writer * const wr = dds_alloc (sizeof (*wr)); + const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, 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); + wrinfo = whc_make_wrinfo (wr, wqos); + wr->m_whc = whc_new (&pub->m_entity.m_domain->gv, wrinfo); + whc_free_wrinfo (wrinfo); wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch; 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, &pp->m_entity.m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); + rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, dds_entity_participant_guid (&pub->m_entity), tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); assert(rc == DDS_RETCODE_OK); thread_state_asleep (lookup_thread_state ()); @@ -360,16 +350,19 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_entity_register_child (&pub->m_entity, &wr->m_entity); dds_entity_init_complete (&wr->m_entity); - dds_topic_unlock (tp); + + dds_topic_allow_set_qos (tp); + dds_topic_unpin (tp); dds_publisher_unlock (pub); return writer; err_bad_qos: + dds_topic_allow_set_qos (tp); err_pp_mismatch: - dds_topic_unlock (tp); -err_tp_lock: + dds_topic_unpin (tp); +err_pin_topic: dds_publisher_unlock (pub); - if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0) + if (created_implicit_pub) (void) dds_delete (publisher); return rc; } @@ -395,6 +388,16 @@ dds_entity_t dds_get_publisher (dds_entity_t writer) } } +dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout) +{ + /* during lifetime of the writer m_wr is constant, it is only during deletion that it + gets erased at some point */ + if (wr->m_wr == NULL) + return DDS_RETCODE_OK; + else + return writer_wait_for_acks (wr->m_wr, abstimeout); +} + 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) diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index 3365bb0..4a234eb 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -30,6 +30,7 @@ set(ddsc_test_sources "instance_get_key.c" "listener.c" "liveliness.c" + "multi_sertopic.c" "participant.c" "publisher.c" "qos.c" @@ -51,6 +52,7 @@ set(ddsc_test_sources "unsupported.c" "waitset.c" "waitset_torture.c" + "whc.c" "write.c" "write_various_types.c" "writer.c") @@ -59,6 +61,10 @@ if(ENABLE_LIFESPAN) list(APPEND ddsc_test_sources "lifespan.c") endif() +if(ENABLE_DEADLINE_MISSED) + list(APPEND ddsc_test_sources "deadline.c") +endif() + add_cunit_executable(cunit_ddsc ${ddsc_test_sources}) target_include_directories( cunit_ddsc PRIVATE diff --git a/src/core/ddsc/tests/Space.idl b/src/core/ddsc/tests/Space.idl index 3ebbc48..d4d0149 100644 --- a/src/core/ddsc/tests/Space.idl +++ b/src/core/ddsc/tests/Space.idl @@ -22,6 +22,12 @@ module Space { long long_3; }; #pragma keylist Type2 long_1 + struct Type3 { + long long_1; + long long_2; + long long_3; + }; +#pragma keylist Type3 struct simpletypes { long l; diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c index bb82d85..a7d2bec 100644 --- a/src/core/ddsc/tests/config.c +++ b/src/core/ddsc/tests/config.c @@ -20,7 +20,7 @@ #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_misc.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #define FORCE_ENV diff --git a/src/core/ddsc/tests/deadline.c b/src/core/ddsc/tests/deadline.c new file mode 100644 index 0000000..818847a --- /dev/null +++ b/src/core/ddsc/tests/deadline.c @@ -0,0 +1,484 @@ +/* + * 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/dds.h" +#include "CUnit/Theory.h" +#include "Space.h" + +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_whc.h" +#include "dds__entity.h" + +#define MAX_RUNS 4 +#define WRITER_DEADLINE DDS_MSECS(50) + +#define DDS_DOMAINID_PUB 0 +#define DDS_DOMAINID_SUB 1 +#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" + +static dds_entity_t g_domain = 0; +static dds_entity_t g_participant = 0; +static dds_entity_t g_subscriber = 0; +static dds_entity_t g_publisher = 0; +static dds_entity_t g_topic = 0; +static dds_qos_t *g_qos; +static dds_entity_t g_remote_domain = 0; +static dds_entity_t g_remote_participant = 0; +static dds_entity_t g_remote_subscriber = 0; +static dds_entity_t g_remote_topic = 0; + + +static char * create_topic_name(const char *prefix, char *name, size_t size) +{ + ddsrt_pid_t pid = ddsrt_getpid(); + ddsrt_tid_t tid = ddsrt_gettid(); + (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); + return name; +} + +static void sync_reader_writer(dds_entity_t participant, dds_entity_t reader, dds_entity_t writer) +{ + dds_attach_t triggered; + dds_return_t ret; + dds_entity_t waitset_rd = dds_create_waitset(participant); + CU_ASSERT_FATAL(waitset_rd > 0); + dds_entity_t waitset_wr = dds_create_waitset(g_participant); + CU_ASSERT_FATAL(waitset_wr > 0); + + /* Sync reader to writer. */ + ret = dds_set_status_mask(reader, DDS_SUBSCRIPTION_MATCHED_STATUS); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_waitset_attach(waitset_rd, reader, reader); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_waitset_wait(waitset_rd, &triggered, 1, DDS_SECS(1)); + CU_ASSERT_EQUAL_FATAL(ret, 1); + CU_ASSERT_EQUAL_FATAL(reader, (dds_entity_t)(intptr_t)triggered); + ret = dds_waitset_detach(waitset_rd, reader); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete(waitset_rd); + + /* Sync writer to reader. */ + ret = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_waitset_attach(waitset_wr, writer, writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_waitset_wait(waitset_wr, &triggered, 1, DDS_SECS(1)); + CU_ASSERT_EQUAL_FATAL(ret, 1); + CU_ASSERT_EQUAL_FATAL(writer, (dds_entity_t)(intptr_t)triggered); + ret = dds_waitset_detach(waitset_wr, writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete(waitset_wr); +} + +static dds_entity_t create_and_sync_reader(dds_entity_t participant, dds_entity_t subscriber, dds_entity_t topic, dds_qos_t *qos, dds_entity_t writer) +{ + dds_entity_t reader = dds_create_reader(subscriber, topic, qos, NULL); + CU_ASSERT_FATAL(reader > 0); + sync_reader_writer (participant, reader, writer); + dds_return_t ret = dds_set_status_mask(reader, DDS_REQUESTED_DEADLINE_MISSED_STATUS); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + return reader; +} + +static void deadline_init(void) +{ + char name[100]; + + /* Domains for pub and sub use a different domain id, but the portgain setting + * in configuration is 0, so that both domains will map to the same port number. + * This allows to create two domains in a single test process. */ + char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB); + char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB); + g_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub); + g_remote_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub); + dds_free(conf_pub); + dds_free(conf_sub); + + g_qos = dds_create_qos(); + CU_ASSERT_PTR_NOT_NULL_FATAL(g_qos); + + g_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL); + CU_ASSERT_FATAL(g_participant > 0); + g_remote_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL); + CU_ASSERT_FATAL(g_remote_participant > 0); + + g_subscriber = dds_create_subscriber(g_participant, NULL, NULL); + CU_ASSERT_FATAL(g_subscriber > 0); + + g_remote_subscriber = dds_create_subscriber(g_remote_participant, NULL, NULL); + CU_ASSERT_FATAL(g_remote_subscriber > 0); + + g_publisher = dds_create_publisher(g_participant, NULL, NULL); + CU_ASSERT_FATAL(g_publisher > 0); + + create_topic_name("ddsc_qos_deadline_test", name, sizeof name); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, name, NULL, NULL); + CU_ASSERT_FATAL(g_topic > 0); + g_remote_topic = dds_create_topic(g_remote_participant, &Space_Type1_desc, name, NULL, NULL); + CU_ASSERT_FATAL(g_remote_topic > 0); + + dds_qset_history(g_qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED); + dds_qset_durability(g_qos, DDS_DURABILITY_TRANSIENT_LOCAL); + dds_qset_reliability(g_qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); +} + +static void deadline_fini(void) +{ + dds_delete_qos(g_qos); + dds_delete(g_subscriber); + dds_delete(g_remote_subscriber); + dds_delete(g_publisher); + dds_delete(g_topic); + dds_delete(g_participant); + dds_delete(g_remote_participant); + dds_delete(g_domain); + dds_delete(g_remote_domain); +} + +static void msg(const char *msg, ...) +{ + va_list args; + dds_time_t t; + t = dds_time(); + printf("%d.%06d ", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000); + va_start(args, msg); + vprintf(msg, args); + va_end(args); + printf("\n"); +} + +static void sleepfor(dds_duration_t sleep_dur) +{ + dds_sleepfor (sleep_dur); + msg("after sleeping %"PRId64, sleep_dur); +} + +static bool check_missed_deadline_reader(dds_entity_t reader, uint32_t exp_missed_total, int32_t exp_missed_change) +{ + struct dds_requested_deadline_missed_status dstatus; + dds_return_t ret = dds_get_requested_deadline_missed_status(reader, &dstatus); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + msg("- check reader total actual %u == expected %u / change actual %d == expected %d", dstatus.total_count, exp_missed_total, dstatus.total_count_change, exp_missed_change); + return dstatus.total_count == exp_missed_total && dstatus.total_count_change == exp_missed_change; +} + +static bool check_missed_deadline_writer(dds_entity_t writer, uint32_t exp_missed_total, int32_t exp_missed_change) +{ + struct dds_offered_deadline_missed_status dstatus; + dds_return_t ret = dds_get_offered_deadline_missed_status(writer, &dstatus); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + msg("- check writer total actual %u == expected %u / change actual %d == expected %d", dstatus.total_count, exp_missed_total, dstatus.total_count_change, exp_missed_change); + return dstatus.total_count == exp_missed_total && dstatus.total_count_change == exp_missed_change; +} + +CU_Test(ddsc_deadline, basic, .init=deadline_init, .fini=deadline_fini) +{ + Space_Type1 sample = { 0, 0, 0 }; + dds_entity_t reader, reader_remote, reader_dl, reader_dl_remote, writer; + dds_return_t ret; + dds_duration_t deadline_dur = WRITER_DEADLINE; + uint32_t run = 1; + bool test_finished = false; + + do + { + msg("deadline test: duration %"PRId64, deadline_dur); + + dds_qset_deadline(g_qos, deadline_dur); + writer = dds_create_writer(g_publisher, g_topic, g_qos, NULL); + CU_ASSERT_FATAL(writer > 0); + + reader_dl = create_and_sync_reader(g_participant, g_subscriber, g_topic, g_qos, writer); + reader_dl_remote = create_and_sync_reader(g_remote_participant, g_remote_subscriber, g_remote_topic, g_qos, writer); + + dds_qset_deadline(g_qos, DDS_INFINITY); + reader = create_and_sync_reader(g_participant, g_subscriber, g_topic, g_qos, writer); + reader_remote = create_and_sync_reader(g_remote_participant, g_remote_subscriber, g_remote_topic, g_qos, writer); + + ret = dds_set_status_mask(writer, DDS_OFFERED_DEADLINE_MISSED_STATUS); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + /* Write first sample */ + msg("write sample 1"); + ret = dds_write (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + + /* Sleep 0.5 * deadline_dur: expect no missed deadlines for reader and writer */ + sleepfor(deadline_dur / 2); + if (!check_missed_deadline_reader(reader, 0, 0) || + !check_missed_deadline_reader(reader_remote, 0, 0) || + !check_missed_deadline_reader(reader_dl, 0, 0) || + !check_missed_deadline_reader(reader_dl_remote, 0, 0) || + !check_missed_deadline_writer(writer, 0, 0)) + deadline_dur *= 10 / (run + 1); + else + { + /* Write another sample */ + msg("write sample 2"); + ret = dds_write (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + + /* Sleep 0.5 * deadline_dur: expect no missed deadlines for reader and writer */ + sleepfor(deadline_dur / 2); + if (!check_missed_deadline_reader(reader, 0, 0) || + !check_missed_deadline_reader(reader_remote, 0, 0) || + !check_missed_deadline_reader(reader_dl, 0, 0) || + !check_missed_deadline_reader(reader_dl_remote, 0, 0) || + !check_missed_deadline_writer(writer, 0, 0)) + deadline_dur *= 10 / (run + 1); + else + { + /* Sleep deadline_dur: expect deadline reader to have 1 missed deadline */ + sleepfor(deadline_dur); + if (!check_missed_deadline_reader(reader, 0, 0) || + !check_missed_deadline_reader(reader_remote, 0, 0) || + !check_missed_deadline_reader(reader_dl, 1, 1) || + !check_missed_deadline_reader(reader_dl_remote, 1, 1) || + !check_missed_deadline_writer(writer, 1, 1)) + deadline_dur *= 10 / (run + 1); + else + { + /* Sleep another 2 * deadline_duration: expect 2 new triggers for missed deadline for both reader and writer */ + sleepfor(2 * deadline_dur); + if (!check_missed_deadline_reader(reader, 0, 0) || + !check_missed_deadline_reader(reader_remote, 0, 0) || + !check_missed_deadline_reader(reader_dl, 3, 2) || + !check_missed_deadline_reader(reader_dl_remote, 3, 2) || + !check_missed_deadline_writer(writer, 3, 2)) + deadline_dur *= 10 / (run + 1); + else + test_finished = true; + } + } + } + + dds_delete(reader); + dds_delete(writer); + + if (!test_finished) + { + if (++run > MAX_RUNS) + { + msg("run limit reached, test failed"); + CU_FAIL_FATAL("Run limit reached"); + test_finished = true; + } + else + { + msg("restarting test with deadline duration %"PRId64, deadline_dur); + sleepfor(deadline_dur); + } + } + } while (!test_finished); +} + +#define V DDS_DURABILITY_VOLATILE +#define TL DDS_DURABILITY_TRANSIENT_LOCAL +#define R DDS_RELIABILITY_RELIABLE +#define BE DDS_RELIABILITY_BEST_EFFORT +#define KA DDS_HISTORY_KEEP_ALL +#define KL DDS_HISTORY_KEEP_LAST +CU_TheoryDataPoints(ddsc_deadline, writer_types) = { + CU_DataPoints(dds_durability_kind_t, V, V, V, V, TL, TL, TL, TL), + CU_DataPoints(dds_reliability_kind_t, BE, BE, R, R, BE, BE, R, R), + CU_DataPoints(dds_history_kind_t, KA, KL, KA, KL, KA, KL, KA, KL) +}; +#undef V +#undef TL +#undef R +#undef BE +#undef KA +#undef KL +CU_Theory((dds_durability_kind_t dur_kind, dds_reliability_kind_t rel_kind, dds_history_kind_t hist_kind), ddsc_deadline, writer_types, .init = deadline_init, .fini = deadline_fini) +{ + Space_Type1 sample = { 0, 0, 0 }; + dds_entity_t reader, writer; + dds_qos_t *qos; + dds_return_t ret; + void * samples[1]; + dds_sample_info_t info; + Space_Type1 rd_sample; + samples[0] = &rd_sample; + struct dds_offered_deadline_missed_status dstatus; + uint32_t run = 1; + dds_duration_t deadline_dur = WRITER_DEADLINE; + bool test_finished = false; + + do + { + msg("deadline test: duration %"PRId64", writer type %d %d %s", deadline_dur, dur_kind, rel_kind, hist_kind == DDS_HISTORY_KEEP_ALL ? "all" : "1"); + + qos = dds_create_qos(); + CU_ASSERT_PTR_NOT_NULL_FATAL(qos); + dds_qset_durability(qos, dur_kind); + dds_qset_reliability(qos, rel_kind, DDS_INFINITY); + dds_qset_history(qos, hist_kind, (hist_kind == DDS_HISTORY_KEEP_ALL) ? 0 : 1); + dds_qset_deadline(qos, deadline_dur); + writer = dds_create_writer(g_publisher, g_topic, qos, NULL); + CU_ASSERT_FATAL(writer > 0); + reader = create_and_sync_reader(g_participant, g_subscriber, g_topic, qos, writer); + + /* Set status mask on writer to get offered deadline missed status */ + ret = dds_set_status_mask(writer, DDS_OFFERED_DEADLINE_MISSED_STATUS); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + /* Write sample */ + ret = dds_write (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + + /* Take sample */ + ret = dds_take (reader, samples, &info, 1, 1); + CU_ASSERT_EQUAL_FATAL (ret, 1); + + /* Sleep 2 * deadline_dur: expect missed deadlines for writer */ + sleepfor(2 * deadline_dur); + ret = dds_get_offered_deadline_missed_status(writer, &dstatus); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + msg("- check writer total actual %u > 0 / change actual %d > 0", dstatus.total_count, dstatus.total_count_change); + if (dstatus.total_count == 0 || dstatus.total_count_change == 0) + deadline_dur *= 10 / (run + 1); + else + { + uint32_t prev_cnt = dstatus.total_count; + + /* Sleep 3 * deadline_dur: expect more missed deadlines for writer */ + sleepfor(3 * deadline_dur); + ret = dds_get_offered_deadline_missed_status(writer, &dstatus); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + msg("- check reader total actual %u > expected %u / change actual %d > 0", dstatus.total_count, prev_cnt, dstatus.total_count_change); + if (dstatus.total_count <= prev_cnt || dstatus.total_count_change == 0) + deadline_dur *= 10 / (run + 1); + else + test_finished = true; + } + + dds_delete_qos(qos); + dds_delete(reader); + dds_delete(writer); + + if (!test_finished) + { + if (++run > MAX_RUNS) + { + msg("run limit reached, test failed"); + CU_FAIL_FATAL("Run limit reached"); + test_finished = true; + } + else + { + msg("restarting test with deadline duration %"PRId64, deadline_dur); + sleepfor(deadline_dur); + } + } + } while (!test_finished); +} + +CU_TheoryDataPoints(ddsc_deadline, instances) = { + CU_DataPoints(int32_t, 1, 10, 10, 100), /* instance count */ + CU_DataPoints(uint8_t, 0, 0, 4, 10), /* unregister every n-th instance */ + CU_DataPoints(uint8_t, 0, 0, 5, 20), /* dispose every n-th instance */ +}; +CU_Theory((int32_t n_inst, uint8_t unreg_nth, uint8_t dispose_nth), ddsc_deadline, instances, .init = deadline_init, .fini = deadline_fini, .timeout = 60) +{ + Space_Type1 sample = { 0, 0, 0 }; + dds_entity_t reader_dl, writer; + dds_return_t ret; + int32_t n, n_unreg, n_dispose, n_alive, run = 1; + bool test_finished = false; + dds_duration_t deadline_dur = WRITER_DEADLINE; + + do + { + msg("deadline test: duration %"PRId64", instance count %d, unreg %dth, dispose %dth", deadline_dur, n_inst, unreg_nth, dispose_nth); + dds_qset_deadline(g_qos, deadline_dur); + CU_ASSERT_PTR_NOT_NULL_FATAL(g_qos); + + writer = dds_create_writer(g_publisher, g_topic, g_qos, NULL); + CU_ASSERT_FATAL(writer > 0); + reader_dl = create_and_sync_reader(g_participant, g_subscriber, g_topic, g_qos, writer); + + /* Write first sample for each instance */ + n_unreg = n_dispose = 0; + for (n = 1; n <= n_inst; n++) + { + sample.long_1 = n; + ret = dds_write (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + if (unreg_nth && n % unreg_nth == 0) + { + ret = dds_unregister_instance (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + n_unreg++; + } + else if (dispose_nth && n % dispose_nth == 0) + { + ret = dds_dispose (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + n_dispose++; + } + } + n_alive = n_inst - n_dispose - n_unreg; + + /* Sleep deadline_dur + 50% and check missed deadline count */ + sleepfor(3 * deadline_dur / 2); + if (!check_missed_deadline_reader(reader_dl, (uint32_t)n_alive, n_alive)) + deadline_dur *= 10 / (run + 1); + else + { + /* Sleep another deadline_dur: expect new trigger for missed deadline for all non-disposed instances */ + sleepfor(deadline_dur); + if (!check_missed_deadline_reader(reader_dl, 2 * (uint32_t)n_alive, n_alive)) + deadline_dur *= 10 / (run + 1); + else + { + /* Write second sample for all (including disposed) instances */ + for (n = 1; n <= n_inst; n++) + { + sample.long_1 = n; + ret = dds_write (writer, &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + + /* Sleep deadline_dur + 25%: expect new trigger for missed deadline for non-disposed instances */ + sleepfor(5 * deadline_dur / 4); + if (!check_missed_deadline_reader(reader_dl, 2 * (uint32_t)n_alive + (uint32_t)n_inst, n_inst)) + deadline_dur *= 10 / (run + 1); + else + test_finished = true; + } + } + + dds_delete(reader_dl); + dds_delete(writer); + + if (!test_finished) + { + if (++run > MAX_RUNS) + { + msg("run limit reached, test failed"); + CU_FAIL_FATAL("Run limit reached"); + test_finished = true; + } + else + { + msg("restarting test with deadline duration %"PRId64, deadline_dur); + sleepfor(deadline_dur); + } + } + } while (!test_finished); +} diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c index 0976c5f..a11e5ea 100644 --- a/src/core/ddsc/tests/liveliness.c +++ b/src/core/ddsc/tests/liveliness.c @@ -153,10 +153,11 @@ CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = { #undef MT #undef MP #undef A -CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30) + +static void test_pmd_count(dds_liveliness_kind_t kind, uint32_t ldur, double mult, bool remote_reader) { dds_entity_t pub_topic; - dds_entity_t sub_topic; + dds_entity_t sub_topic = 0; dds_entity_t reader; dds_entity_t writer; seqno_t start_seqno, end_seqno; @@ -169,9 +170,9 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin dds_time_t t; t = dds_time(); - printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n", + printf("%d.%06d running test: kind %s, lease duration %d, delay %d, %s reader\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, - kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur)); + kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur), remote_reader ? "remote" : "local"); /* wait for initial PMD to be sent by the participant */ while (get_pmd_seqno(g_pub_participant) < 1) @@ -180,17 +181,18 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin /* topics */ create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); /* waitset on reader */ - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); /* writer */ @@ -216,17 +218,24 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin /* End-start should be mult - 1 under ideal circumstances, but consider the test successful when at least 50% of the expected PMD's was sent. This checks that the frequency for sending PMDs was increased when the writer was added. */ - CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0)) + CU_ASSERT_FATAL(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0)) if (kind != DDS_LIVELINESS_AUTOMATIC) - CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult) + CU_ASSERT_FATAL(get_pmd_seqno(g_pub_participant) - start_seqno < mult) /* cleanup */ - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); } +CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30) +{ + test_pmd_count(kind, ldur, mult, false); + test_pmd_count(kind, ldur, mult, true); +} + /** * Test that the expected number of proxy writers expires (set to not-alive) * after a certain delay for various combinations of writers with different @@ -239,10 +248,11 @@ CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = { CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */ CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */ }; -CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120) + +static void test_expire_liveliness_kinds(uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp, bool remote_reader) { dds_entity_t pub_topic; - dds_entity_t sub_topic; + dds_entity_t sub_topic = 0; dds_entity_t reader; dds_entity_t *writers; dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp; @@ -257,19 +267,20 @@ CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man do { tstart = dds_time(); - printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n", + printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n, %s reader", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000, - ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp); + ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, remote_reader ? "remote" : "local"); /* topics */ create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); @@ -281,7 +292,7 @@ CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL); dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur)); - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); writers = dds_alloc(wr_cnt * sizeof(dds_entity_t)); @@ -347,7 +358,8 @@ CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man for (n = 0; n < wr_cnt; n++) CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK); dds_free(writers); - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); @@ -369,14 +381,21 @@ CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man } while (!test_finished); } -static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader) +CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120) +{ + test_expire_liveliness_kinds (ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, false); + test_expire_liveliness_kinds (ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, true); +} + + +static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader, bool remote_reader) { dds_entity_t waitset; dds_qos_t *wqos; dds_attach_t triggered; uint32_t status; - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL); @@ -409,7 +428,7 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli uint32_t n; /* topics */ - create_topic_name("ddsc_liveliness_ldur", 1, name, sizeof name); + create_topic_name("ddsc_liveliness_ldur", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -424,22 +443,22 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant)); /* create writers and check pmd interval in publishing participant */ - add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000)); - add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000)); - add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000)); - add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500)); - add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500)); - add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader, true); CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500)); /* cleanup */ @@ -454,10 +473,10 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli /** * Check that the correct lease duration is set in the matched * publications in the readers. */ -CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini) +static void test_lease_duration_pwr(bool remote_reader) { dds_entity_t pub_topic; - dds_entity_t sub_topic; + dds_entity_t sub_topic = 0; dds_entity_t reader; dds_entity_t writer; char name[100]; @@ -467,15 +486,18 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li uint32_t status; dds_duration_t ldur; + printf("running test lease_duration_pwr: %s reader\n", remote_reader ? "remote" : "local"); + /* topics */ - create_topic_name("ddsc_liveliness_ldurpwr", 1, name, sizeof name); + create_topic_name("ddsc_liveliness_ldurpwr", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); @@ -486,7 +508,7 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0); /* wait for writer to be alive */ - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1); CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); @@ -509,11 +531,18 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); } +CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini) +{ + test_lease_duration_pwr(false); + test_lease_duration_pwr(true); +} + /** * Create a relative large number of writers with liveliness kinds automatic and * manual-by-participant and with decreasing lease duration, and check that all @@ -521,10 +550,11 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li * is deleted immediately after creating. */ #define MAX_WRITERS 100 -CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 15) + +static void test_create_delete_writer_stress(bool remote_reader) { dds_entity_t pub_topic; - dds_entity_t sub_topic; + dds_entity_t sub_topic = 0; dds_entity_t reader; dds_entity_t writers[MAX_WRITERS]; dds_entity_t waitset; @@ -538,18 +568,21 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, . Space_Type1 sample = {0, 0, 0}; int64_t ldur = 1000; + printf("running test create_delete_writer_stress: %s reader\n", remote_reader ? "remote" : "local"); + /* topics */ - create_topic_name("ddsc_liveliness_wr_stress", 1, name, sizeof name); + create_topic_name("ddsc_liveliness_wr_stress", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader and waitset */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); /* create 1st writer and wait for it to become alive */ @@ -604,42 +637,53 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, . CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); } + +CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 15) +{ + test_create_delete_writer_stress(false); + test_create_delete_writer_stress(true); +} #undef MAX_WRITERS /** * Check the counts in liveliness_changed_status result. */ -CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini) +static void test_status_counts(bool remote_reader) { dds_entity_t pub_topic; - dds_entity_t sub_topic; + dds_entity_t sub_topic = 0; dds_entity_t reader; dds_entity_t writer; dds_entity_t waitset; dds_qos_t *rqos; dds_qos_t *wqos; dds_attach_t triggered; - struct dds_liveliness_changed_status lstatus; + struct dds_liveliness_changed_status lcstatus; + struct dds_liveliness_lost_status llstatus; struct dds_subscription_matched_status sstatus; char name[100]; dds_duration_t ldur = DDS_MSECS(500); Space_Type1 sample = {1, 0, 0}; + printf("running test status_counts: %s reader\n", remote_reader ? "remote" : "local"); + /* topics */ create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); - CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0); + CU_ASSERT_FATAL((waitset = dds_create_waitset(remote_reader ? g_sub_participant : g_pub_participant)) > 0); CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK); /* writer */ @@ -647,56 +691,72 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur); CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0); dds_delete_qos(wqos); + CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(writer, DDS_LIVELINESS_LOST_STATUS), DDS_RETCODE_OK); /* wait for writer to be alive */ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1); /* check status counts before proxy writer is expired */ - dds_get_liveliness_changed_status(reader, &lstatus); - CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1); + dds_get_liveliness_changed_status(reader, &lcstatus); + CU_ASSERT_EQUAL_FATAL(lcstatus.alive_count, 1); dds_get_subscription_matched_status(reader, &sstatus); CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1); + dds_get_liveliness_lost_status(writer, &llstatus); + CU_ASSERT_EQUAL_FATAL(llstatus.total_count, 0); /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */ dds_sleepfor(ldur + DDS_MSECS(100)); CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1); - dds_get_liveliness_changed_status(reader, &lstatus); - CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0); + dds_get_liveliness_changed_status(reader, &lcstatus); + CU_ASSERT_EQUAL_FATAL(lcstatus.alive_count, 0); dds_get_subscription_matched_status(reader, &sstatus); CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1); + dds_get_liveliness_lost_status(writer, &llstatus); + CU_ASSERT_EQUAL_FATAL(llstatus.total_count, 1); + CU_ASSERT_EQUAL_FATAL(llstatus.total_count_change, 1); /* write sample and re-check status counts */ dds_write(writer, &sample); CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1); - dds_get_liveliness_changed_status(reader, &lstatus); - CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1); + dds_get_liveliness_changed_status(reader, &lcstatus); + CU_ASSERT_EQUAL_FATAL(lcstatus.alive_count, 1); dds_get_subscription_matched_status(reader, &sstatus); CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1); + dds_get_liveliness_lost_status(writer, &llstatus); + CU_ASSERT_EQUAL_FATAL(llstatus.total_count_change, 0); /* cleanup */ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); } +CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini) +{ + test_status_counts(false); + test_status_counts(true); +} + /** * Test that dds_assert_liveliness works as expected for liveliness * kinds manual-by-participant and manual-by-topic. */ #define MAX_WRITERS 100 CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = { - CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */ - CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */ - CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */ + CU_DataPoints(uint32_t, 1, 0, 0, 1, 0, 1, 2), /* number of writers with automatic liveliness */ + CU_DataPoints(uint32_t, 0, 1, 0, 1, 1, 0, 2), /* number of writers with manual-by-participant liveliness */ + CU_DataPoints(uint32_t, 0, 0, 1, 1, 2, 2, 0), /* number of writers with manual-by-topic liveliness */ }; -CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60) + +static void test_assert_liveliness(uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp, bool remote_reader) { - dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS]; + dds_entity_t pub_topic, sub_topic = 0, reader, writers[MAX_WRITERS]; dds_qos_t *rqos; struct dds_liveliness_changed_status lstatus; char name[100]; @@ -708,29 +768,30 @@ CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp) { wr_cnt = 0; assert(wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS); - printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n", - wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur); + printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d, %s reader\n", + wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur, remote_reader ? "remote" : "local"); /* topics */ create_topic_name("ddsc_liveliness_assert", g_topic_nr++, name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); - CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); + if (remote_reader) + CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); /* reader */ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL); dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); - CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0); + CU_ASSERT_FATAL((reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, rqos, NULL)) > 0); dds_delete_qos(rqos); CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK); /* writers */ for (size_t n = 0; n < wr_cnt_auto; n++) - add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader, remote_reader); tstart = dds_time(); for (size_t n = 0; n < wr_cnt_man_pp; n++) - add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader, remote_reader); for (size_t n = 0; n < wr_cnt_man_tp; n++) - add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader); + add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader, remote_reader); t = dds_time(); if (t - tstart > DDS_MSECS(0.5 * ldur)) { @@ -750,13 +811,13 @@ CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp) stopped = 0; do { - for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++) - dds_assert_liveliness(writers[n]); + for (size_t n = wr_cnt_auto; n < wr_cnt; n++) + CU_ASSERT_EQUAL_FATAL(dds_assert_liveliness(writers[n]), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK); stopped += (uint32_t)lstatus.not_alive_count_change; dds_sleepfor(DDS_MSECS(50)); } while (dds_time() < tstop); - dds_get_liveliness_changed_status(reader, &lstatus); + CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK); printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped); if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0) { @@ -795,7 +856,8 @@ CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp) CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK); for (size_t n = 0; n < wr_cnt; n++) CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); + if (remote_reader) + CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK); CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK); if (!test_finished) @@ -813,4 +875,319 @@ CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp) } } while (!test_finished); } + +CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60) +{ + test_assert_liveliness(wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, false); + test_assert_liveliness(wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, true); +} #undef MAX_WRITERS + +/** + * Check that manual-by-participant/topic writers with lease duration 0ns and 1ns work. + */ +struct liveliness_changed_state { + ddsrt_mutex_t lock; + dds_instance_handle_t w0_handle; + bool weirdness; + uint32_t w0_alive, w0_not_alive; +}; + +static void liveliness_changed_listener (dds_entity_t rd, const dds_liveliness_changed_status_t status, void *arg) +{ + struct liveliness_changed_state *st = arg; + (void) rd; + + ddsrt_mutex_lock (&st->lock); + if (status.last_publication_handle != st->w0_handle) + { + if (st->w0_handle == 0) + { + printf ("liveliness_changed_listener: w0 = %"PRIx64"\n", status.last_publication_handle); + st->w0_handle = status.last_publication_handle; + } + else + { + printf ("liveliness_changed_listener: too many writer handles\n"); + st->weirdness = true; + } + } + + if (status.alive_count_change != 0 || status.not_alive_count_change != 0) + { + switch (status.alive_count_change) + { + case -1: + break; + case 1: + if (status.last_publication_handle == st->w0_handle) + st->w0_alive++; + else + { + printf ("liveliness_changed_listener: alive_count_change = %d: unrecognized writer\n", status.alive_count_change); + st->weirdness = true; + } + break; + default: + printf ("liveliness_changed_listener: alive_count_change = %d\n", status.alive_count_change); + st->weirdness = true; + } + + switch (status.not_alive_count_change) + { + case -1: + break; + case 1: + if (status.last_publication_handle == st->w0_handle) + st->w0_not_alive++; + else + { + printf ("liveliness_changed_listener: not_alive_count_change = %d: unrecognized writer\n", status.not_alive_count_change); + st->weirdness = true; + } + break; + default: + printf ("liveliness_changed_listener: not_alive_count_change = %d\n", status.not_alive_count_change); + st->weirdness = true; + } + } + else + { + printf ("liveliness_changed_listener: alive_count_change = 0 && not_alive_count_change = 0\n"); + st->weirdness = true; + } + ddsrt_mutex_unlock (&st->lock); +} + +#define STATUS_UNSYNCED 0 +#define STATUS_SYNCED 1 +#define STATUS_DATA 2 +static unsigned get_and_check_status (dds_entity_t reader, dds_entity_t writer_active) +{ + struct dds_liveliness_changed_status lstatus; + struct dds_subscription_matched_status sstatus; + struct dds_publication_matched_status pstatus; + uint32_t dstatus; + uint32_t result = STATUS_UNSYNCED; + dds_return_t rc; + rc = dds_get_subscription_matched_status(reader, &sstatus); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_get_liveliness_changed_status(reader, &lstatus); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_take_status(reader, &dstatus, DDS_DATA_AVAILABLE_STATUS); + CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK); + rc = dds_get_publication_matched_status(writer_active, &pstatus); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + CU_ASSERT_FATAL(lstatus.alive_count + lstatus.not_alive_count <= 2); + printf ("sub %d | alive %d | not-alive %d | pub %d | data %d\n", (int)sstatus.current_count, (int)lstatus.alive_count, (int)lstatus.not_alive_count, (int)pstatus.current_count, dstatus != 0); + if (dstatus) + result |= STATUS_DATA; + if (sstatus.current_count == 2 && lstatus.not_alive_count == 2 && pstatus.current_count == 1) + result |= STATUS_SYNCED; + return result; +} + +static void lease_duration_zero_or_one_impl (dds_duration_t sleep, dds_liveliness_kind_t lkind, dds_duration_t ldur, bool remote_reader) +{ + const uint32_t nsamples = (sleep <= DDS_MSECS(10)) ? 50 : 5; + dds_entity_t pub_topic; + dds_entity_t sub_topic = 0; + dds_entity_t reader; + dds_entity_t writer_active; /* writing */ + dds_entity_t writer_inactive; /* not writing, liveliness should still toggle */ + dds_entity_t waitset; + dds_listener_t *listener; + dds_qos_t *qos; + dds_return_t rc; + struct dds_liveliness_changed_status lstatus; + char name[100]; + Space_Type1 sample = {1, 0, 0}; + struct liveliness_changed_state listener_state = { + .weirdness = false, + .w0_handle = 0, + .w0_alive = 0, + .w0_not_alive = 0, + }; + ddsrt_mutex_init (&listener_state.lock); + + waitset = dds_create_waitset(DDS_CYCLONEDDS_HANDLE); + CU_ASSERT_FATAL(waitset > 0); + + qos = dds_create_qos(); + CU_ASSERT_FATAL(qos != NULL); + dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_history(qos, DDS_HISTORY_KEEP_ALL, 0); + + create_topic_name("ddsc_liveliness_lease_duration_zero", g_topic_nr++, name, sizeof name); + pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, qos, NULL); + CU_ASSERT_FATAL(pub_topic > 0); + if (remote_reader) + { + sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, qos, NULL); + CU_ASSERT_FATAL(sub_topic > 0); + } + + /* reader liveliness is always automatic/infinity */ + dds_qset_liveliness(qos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY); + reader = dds_create_reader(remote_reader ? g_sub_participant : g_pub_participant, remote_reader ? sub_topic : pub_topic, qos, NULL); + CU_ASSERT_FATAL(reader > 0); + rc = dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS | DDS_DATA_AVAILABLE_STATUS); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_waitset_attach(waitset, reader, reader); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + + /* writer liveliness varies */ + dds_qset_liveliness(qos, lkind, ldur); + writer_active = dds_create_writer(g_pub_participant, pub_topic, qos, NULL); + CU_ASSERT_FATAL(writer_active > 0); + writer_inactive = dds_create_writer(g_pub_participant, pub_topic, qos, NULL); + CU_ASSERT_FATAL(writer_inactive > 0); + rc = dds_set_status_mask(writer_active, DDS_PUBLICATION_MATCHED_STATUS); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_waitset_attach(waitset, writer_active, writer_active); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + + dds_delete_qos(qos); + + /* wait for writers to be discovered and to have lost their liveliness, and for + writer_active to have discovered the reader */ + unsigned status = STATUS_UNSYNCED; + bool initial_sample_written = false, initial_sample_received = false; + do + { + status = get_and_check_status (reader, writer_active); + if (status & STATUS_DATA) + initial_sample_received = true; + if (status & STATUS_SYNCED && !initial_sample_written) + { + rc = dds_write(writer_active, &sample); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + initial_sample_written = true; + } + if (status & STATUS_SYNCED && initial_sample_received) + break; + + rc = dds_waitset_wait(waitset, NULL, 0, DDS_SECS(5)); + if (rc < 1) + { + get_and_check_status (reader, writer_active); + CU_ASSERT_FATAL(rc >= 1); + } + } while (1); + + /* switch to using a listener: those allow us to observe all events */ + listener = dds_create_listener (&listener_state); + dds_lset_liveliness_changed(listener, liveliness_changed_listener); + rc = dds_set_listener (reader, listener); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + dds_delete_listener (listener); + + /* write as fast as possible - we don't expect this to cause the writers + to gain and lose liveliness once for each sample, but it should have + become alive at least once and fall back to not alive afterward */ + for (uint32_t i = 0; i < nsamples; i++) + { + rc = dds_write(writer_active, &sample); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + if (sleep && i < nsamples - 1) + dds_sleepfor(sleep); + } + + rc = dds_wait_for_acks(writer_active, DDS_SECS(5)); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + + /* verify the reader received all samples */ + void *raw[] = { &sample }; + dds_sample_info_t si; + uint32_t cnt = 0; + do + { + rc = dds_waitset_wait(waitset, NULL, 0, DDS_SECS(5)); + CU_ASSERT_FATAL(rc >= 1); + while (dds_take(reader, raw, &si, 1, 1) == 1 && si.valid_data) + cnt++; + } + while (cnt < nsamples + 1); + CU_ASSERT_FATAL(cnt == nsamples + 1); + + /* transition to not alive is not necessarily immediate */ + { + int retries = 100; + rc = dds_get_liveliness_changed_status(reader, &lstatus); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + printf("early liveliness changed status: alive %"PRId32" not-alive %"PRId32"\n", lstatus.alive_count, lstatus.not_alive_count); + + ddsrt_mutex_lock (&listener_state.lock); + printf("early w0 %"PRIx64" alive %"PRId32" not-alive %"PRId32"\n", listener_state.w0_handle, listener_state.w0_alive, listener_state.w0_not_alive); + CU_ASSERT_FATAL(!listener_state.weirdness); + CU_ASSERT_FATAL(listener_state.w0_handle != 0); + while (listener_state.w0_not_alive < listener_state.w0_alive && retries-- > 0) + { + ddsrt_mutex_unlock(&listener_state.lock); + dds_sleepfor(DDS_MSECS(10)); + rc = dds_get_liveliness_changed_status(reader, &lstatus); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + ddsrt_mutex_lock(&listener_state.lock); + } + + printf("late liveliness changed status: alive %"PRId32" not-alive %"PRId32"\n", lstatus.alive_count, lstatus.not_alive_count); + printf("final w0 %"PRIx64" alive %"PRId32" not-alive %"PRId32"\n", listener_state.w0_handle, listener_state.w0_alive, listener_state.w0_not_alive); + CU_ASSERT_FATAL(listener_state.w0_alive == listener_state.w0_not_alive); + uint32_t exp_alive; + if (sleep == 0) + exp_alive = 1; /* if not sleeping, it's ok if the transition happens only once */ + else if (sleep <= DDS_MSECS(10)) + exp_alive = nsamples / 3; /* if sleeping briefly, expect the a good number of writes to toggle liveliness */ + else + exp_alive = nsamples - nsamples / 5; /* if sleeping, expect the vast majority (80%) of the writes to toggle liveliness */ + printf("check w0_alive %d >= %d\n", listener_state.w0_alive, exp_alive); + CU_ASSERT_FATAL(listener_state.w0_alive >= exp_alive); + ddsrt_mutex_unlock(&listener_state.lock); + } + + /* cleanup */ + rc = dds_delete(waitset); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_delete(reader); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_delete(writer_active); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + rc = dds_delete(writer_inactive); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + if (remote_reader) + { + rc = dds_delete(sub_topic); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + } + rc = dds_delete(pub_topic); + CU_ASSERT_FATAL(rc == DDS_RETCODE_OK); + + ddsrt_mutex_destroy(&listener_state.lock); +} + +CU_Test(ddsc_liveliness, lease_duration_zero_or_one, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30) +{ + static const bool remote_rd[] = { false, true }; + static const dds_duration_t sleep[] = { 0, DDS_MSECS(10), DDS_MSECS(100) }; + static const dds_liveliness_kind_t lkind[] = { DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_LIVELINESS_MANUAL_BY_TOPIC }; + static const dds_duration_t ldur[] = { 0, 1 }; + for (size_t remote_rd_idx = 0; remote_rd_idx < sizeof (remote_rd) / sizeof (remote_rd[0]); remote_rd_idx++) + { + for (size_t sleep_idx = 0; sleep_idx < sizeof (sleep) / sizeof (sleep[0]); sleep_idx++) + { + for (size_t lkind_idx = 0; lkind_idx < sizeof (lkind) / sizeof (lkind[0]); lkind_idx++) + { + for (size_t ldur_idx = 0; ldur_idx < sizeof (ldur) / sizeof (ldur[0]); ldur_idx++) + { + bool rrd = remote_rd[remote_rd_idx]; + dds_duration_t s = sleep[sleep_idx]; + dds_liveliness_kind_t k = lkind[lkind_idx]; + dds_duration_t d = ldur[ldur_idx]; + printf ("### lease_duration_zero_or_one: sleep = %"PRId64" lkind = %d ldur = %"PRId64" reader = %s\n", s, (int) k, d, rrd ? "remote" : "local"); + lease_duration_zero_or_one_impl (s, k, d, rrd); + printf ("\n"); + } + } + } + } +} diff --git a/src/core/ddsc/tests/multi_sertopic.c b/src/core/ddsc/tests/multi_sertopic.c new file mode 100644 index 0000000..1bbdfbf --- /dev/null +++ b/src/core/ddsc/tests/multi_sertopic.c @@ -0,0 +1,608 @@ +/* + * 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/dds.h" +#include "CUnit/Theory.h" +#include "Space.h" +#include "config_env.h" + +#include "dds/version.h" +#include "dds__entity.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/time.h" + +#define DDS_DOMAINID_PUB 0 +#define DDS_DOMAINID_SUB 1 +#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" +#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}cyclonedds_multi_sertopic_tests.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.logfinest0" + +/* IDL preprocessing is not really friendly towards creating multiple descriptors + for the same type name with different definitions, so we do it by hand. */ +struct uint32_seq { + uint32_t _maximum; + uint32_t _length; + uint32_t *_buffer; + bool _release; +}; + +struct two_uint32 { + uint32_t v[2]; +}; + +struct two_uint32_seq { + uint32_t _maximum; + uint32_t _length; + struct two_uint32 *_buffer; + bool _release; +}; + +struct type_seq { + struct uint32_seq x; +}; + +struct type_ary { + uint32_t x[4]; +}; + +struct type_uni { + uint32_t _d; + union + { + struct two_uint32_seq a; + uint32_t b[4]; + } _u; +}; + +static const dds_topic_descriptor_t type_seq_desc = +{ + .m_size = sizeof (struct type_seq), + .m_align = sizeof (void *), + .m_flagset = DDS_TOPIC_NO_OPTIMIZE, + .m_nkeys = 0, + .m_typename = "multi_sertopic_type", + .m_keys = NULL, + .m_nops = 2, + .m_ops = (const uint32_t[]) { + DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_4BY, offsetof (struct type_seq, x), + DDS_OP_RTS + }, + .m_meta = "" /* this is on its way out anyway */ +}; + +static const dds_topic_descriptor_t type_ary_desc = +{ + .m_size = sizeof (struct type_ary), + .m_align = 4u, + .m_flagset = DDS_TOPIC_NO_OPTIMIZE, + .m_nkeys = 0, + .m_typename = "multi_sertopic_type", + .m_keys = NULL, + .m_nops = 2, + .m_ops = (const uint32_t[]) { + DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_4BY, offsetof (struct type_ary, x), 4, + DDS_OP_RTS + }, + .m_meta = "" /* this is on its way out anyway */ +}; + +static const dds_topic_descriptor_t type_uni_desc = +{ + .m_size = sizeof (struct type_uni), + .m_align = sizeof (void *), + .m_flagset = DDS_TOPIC_NO_OPTIMIZE | DDS_TOPIC_CONTAINS_UNION, + .m_nkeys = 0, + .m_typename = "multi_sertopic_type", + .m_keys = NULL, + .m_nops = 8, + .m_ops = (const uint32_t[]) { + DDS_OP_ADR | DDS_OP_TYPE_UNI | DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_DEF, offsetof (struct type_uni, _d), 2u, (23u << 16) + 4u, + DDS_OP_JEQ | DDS_OP_TYPE_SEQ | 6, 3, offsetof (struct type_uni, _u.a), + DDS_OP_JEQ | DDS_OP_TYPE_ARR | 12, 0, offsetof (struct type_uni, _u.b), + DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, 0u, + sizeof (struct two_uint32), (8u << 16u) + 4u, + DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_4BY, offsetof (struct two_uint32, v), 2, + DDS_OP_RTS, + DDS_OP_RTS, + DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_4BY, 0u, 4, + DDS_OP_RTS, + DDS_OP_RTS + }, + .m_meta = "" /* this is on its way out anyway */ +}; + +/* The slow delivery path has a switchover at 4 sertopics (well, today it has ...) so it is better to + to test with > 4 different sertopics. That path (again, today) iterates over GUIDs in increasing + order, and as all readers are created in the participant and the entity ids are strictly + monotonically increasing for the first ~ 16M entities (again, today), creating additional + readers for these topics at the end means that "ary2" is the one that ends up in > 4 case. + Calling takecdr */ +static const dds_topic_descriptor_t type_ary1_desc = +{ + .m_size = sizeof (struct type_ary), + .m_align = 1u, + .m_flagset = DDS_TOPIC_NO_OPTIMIZE, + .m_nkeys = 0, + .m_typename = "multi_sertopic_type", + .m_keys = NULL, + .m_nops = 2, + .m_ops = (const uint32_t[]) { + DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_1BY, offsetof (struct type_ary, x), 16, + DDS_OP_RTS + }, + .m_meta = "" /* this is on its way out anyway */ +}; + +static const dds_topic_descriptor_t type_ary2_desc = +{ + .m_size = sizeof (struct type_ary), + .m_align = 2u, + .m_flagset = DDS_TOPIC_NO_OPTIMIZE, + .m_nkeys = 0, + .m_typename = "multi_sertopic_type", + .m_keys = NULL, + .m_nops = 2, + .m_ops = (const uint32_t[]) { + DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_2BY, offsetof (struct type_ary, x), 8, + DDS_OP_RTS + }, + .m_meta = "" /* this is on its way out anyway */ +}; + +static uint32_t g_topic_nr = 0; +static dds_entity_t g_pub_domain = 0; +static dds_entity_t g_pub_participant = 0; +static dds_entity_t g_pub_publisher = 0; + +static dds_entity_t g_sub_domain = 0; +static dds_entity_t g_sub_participant = 0; +static dds_entity_t g_sub_subscriber = 0; + +static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) +{ + /* Get unique g_topic name. */ + ddsrt_pid_t pid = ddsrt_getpid(); + ddsrt_tid_t tid = ddsrt_gettid(); + (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); + return name; +} + +static void multi_sertopic_init (void) +{ + /* Domains for pub and sub use a different domain id, but the portgain setting + * in configuration is 0, so that both domains will map to the same port number. + * This allows to create two domains in a single test process. */ + char *conf_pub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB); + char *conf_sub = ddsrt_expand_envvars (DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB); + g_pub_domain = dds_create_domain (DDS_DOMAINID_PUB, conf_pub); + g_sub_domain = dds_create_domain (DDS_DOMAINID_SUB, conf_sub); + dds_free (conf_pub); + dds_free (conf_sub); + + g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL); + CU_ASSERT_FATAL (g_pub_participant > 0); + g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL); + CU_ASSERT_FATAL (g_sub_participant > 0); + + g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL); + CU_ASSERT_FATAL (g_pub_publisher > 0); + g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL); + CU_ASSERT_FATAL (g_sub_subscriber > 0); +} + +static void multi_sertopic_fini (void) +{ + dds_delete (g_sub_subscriber); + dds_delete (g_pub_publisher); + dds_delete (g_sub_participant); + dds_delete (g_pub_participant); + dds_delete (g_sub_domain); + dds_delete (g_pub_domain); +} + +static bool get_and_check_writer_status (size_t nwr, const dds_entity_t *wrs, size_t nrd) +{ + dds_return_t rc; + struct dds_publication_matched_status x; + for (size_t i = 0; i < nwr; i++) + { + rc = dds_get_publication_matched_status (wrs[i], &x); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + if (x.current_count != nrd) + return false; + } + return true; +} + +static bool get_and_check_reader_status (size_t nrd, const dds_entity_t *rds, size_t nwr) +{ + dds_return_t rc; + struct dds_subscription_matched_status x; + for (size_t i = 0; i < nrd; i++) + { + rc = dds_get_subscription_matched_status (rds[i], &x); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + if (x.current_count != nwr) + return false; + } + return true; +} + +static void waitfor_or_reset_fastpath (dds_entity_t rdhandle, bool fastpath, size_t nwr) +{ + dds_return_t rc; + struct dds_entity *x; + + rc = dds_entity_pin (rdhandle, &x); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + CU_ASSERT_FATAL (dds_entity_kind (x) == DDS_KIND_READER); + + struct reader * const rd = ((struct dds_reader *) x)->m_rd; + struct rd_pwr_match *m; + ddsi_guid_t cursor; + size_t wrcount = 0; + thread_state_awake (lookup_thread_state (), rd->e.gv); + ddsrt_mutex_lock (&rd->e.lock); + + memset (&cursor, 0, sizeof (cursor)); + while ((m = ddsrt_avl_lookup_succ (&rd_writers_treedef, &rd->writers, &cursor)) != NULL) + { + cursor = m->pwr_guid; + ddsrt_mutex_unlock (&rd->e.lock); + struct proxy_writer * const pwr = entidx_lookup_proxy_writer_guid (rd->e.gv->entity_index, &cursor); + ddsrt_mutex_lock (&pwr->rdary.rdary_lock); + if (!fastpath) + pwr->rdary.fastpath_ok = false; + else + { + while (!pwr->rdary.fastpath_ok) + { + ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); + dds_sleepfor (DDS_MSECS (10)); + ddsrt_mutex_lock (&pwr->rdary.rdary_lock); + } + } + wrcount++; + ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); + ddsrt_mutex_lock (&rd->e.lock); + } + + memset (&cursor, 0, sizeof (cursor)); + while ((m = ddsrt_avl_lookup_succ (&rd_local_writers_treedef, &rd->local_writers, &cursor)) != NULL) + { + cursor = m->pwr_guid; + ddsrt_mutex_unlock (&rd->e.lock); + struct writer * const wr = entidx_lookup_writer_guid (rd->e.gv->entity_index, &cursor); + ddsrt_mutex_lock (&wr->rdary.rdary_lock); + if (!fastpath) + wr->rdary.fastpath_ok = fastpath; + else + { + while (!wr->rdary.fastpath_ok) + { + ddsrt_mutex_unlock (&wr->rdary.rdary_lock); + dds_sleepfor (DDS_MSECS (10)); + ddsrt_mutex_lock (&wr->rdary.rdary_lock); + } + } + wrcount++; + ddsrt_mutex_unlock (&wr->rdary.rdary_lock); + ddsrt_mutex_lock (&rd->e.lock); + } + ddsrt_mutex_unlock (&rd->e.lock); + thread_state_asleep (lookup_thread_state ()); + dds_entity_unpin (x); + + CU_ASSERT_FATAL (wrcount == nwr); +} + +static struct ddsi_sertopic *get_sertopic_from_reader (dds_entity_t reader) +{ + /* not refcounting the sertopic: so this presumes it is kept alive for other reasons */ + dds_return_t rc; + struct dds_entity *x; + struct dds_reader *rd; + struct ddsi_sertopic *sertopic; + rc = dds_entity_pin (reader, &x); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + CU_ASSERT_FATAL (dds_entity_kind (x) == DDS_KIND_READER); + rd = (struct dds_reader *) x; + sertopic = rd->m_topic->m_stopic; + dds_entity_unpin (x); + return sertopic; +} + +static void logsink (void *arg, const dds_log_data_t *msg) +{ + ddsrt_atomic_uint32_t *deser_fail = arg; + fputs (msg->message - msg->hdrsize, stderr); + if (strstr (msg->message, "deserialization") && strstr (msg->message, "failed")) + ddsrt_atomic_inc32 (deser_fail); +} + +static void ddsc_multi_sertopic_impl (dds_entity_t pp_pub, dds_entity_t pp_sub, bool fastpath) +{ +#define SEQ_IDX 0 +#define ARY_IDX 1 +#define UNI_IDX 2 + char name[100]; + static const dds_topic_descriptor_t *descs[] = { + &type_seq_desc, &type_ary_desc, &type_uni_desc, + &type_ary1_desc, &type_ary2_desc + }; + dds_entity_t pub_topics[3], writers[3]; + dds_entity_t sub_topics[5]; + dds_entity_t readers[15]; + dds_entity_t waitset; + dds_qos_t *qos; + dds_return_t rc; + + printf ("multi_sertopic: %s %s\n", (pp_pub == pp_sub) ? "local" : "remote", fastpath ? "fastpath" : "slowpath"); + + waitset = dds_create_waitset (DDS_CYCLONEDDS_HANDLE); + CU_ASSERT_FATAL (waitset > 0); + + qos = dds_create_qos (); + CU_ASSERT_FATAL (qos != NULL); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_destination_order (qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + + create_topic_name ("ddsc_multi_sertopic_lease_duration_zero", g_topic_nr++, name, sizeof name); + + for (size_t i = 0; i < sizeof (pub_topics) / sizeof (pub_topics[0]); i++) + { + pub_topics[i] = dds_create_topic (pp_pub, descs[i], name, qos, NULL); + CU_ASSERT_FATAL (pub_topics[i] > 0); + } + for (size_t i = 0; i < sizeof (writers) / sizeof (writers[0]); i++) + { + writers[i] = dds_create_writer (pp_pub, pub_topics[i], qos, NULL); + CU_ASSERT_FATAL (writers[i] > 0); + } + for (size_t i = 0; i < sizeof (sub_topics) / sizeof (sub_topics[0]); i++) + { + sub_topics[i] = dds_create_topic (pp_sub, descs[i], name, qos, NULL); + CU_ASSERT_FATAL (sub_topics[i] > 0); + } + DDSRT_STATIC_ASSERT (sizeof (readers) >= sizeof (sub_topics)); + DDSRT_STATIC_ASSERT ((sizeof (readers) % sizeof (sub_topics)) == 0); + for (size_t i = 0; i < sizeof (sub_topics) / sizeof (sub_topics[0]); i++) + { + readers[i] = dds_create_reader (pp_sub, sub_topics[i], qos, NULL); + CU_ASSERT_FATAL (readers[i] > 0); + } + for (size_t i = sizeof (sub_topics) / sizeof (sub_topics[0]); i < sizeof (readers) / sizeof (readers[0]); i++) + { + const size_t nrd = sizeof (readers) / sizeof (readers[0]); + const size_t ntp = sizeof (sub_topics) / sizeof (sub_topics[0]); + readers[i] = dds_create_reader (pp_sub, sub_topics[(i - ntp) / (nrd / ntp - 1)], qos, NULL); + CU_ASSERT_FATAL (readers[i] > 0); + } + + dds_delete_qos (qos); + + /* wait for discovery to complete */ + for (size_t i = 0; i < sizeof (writers) / sizeof (writers[0]); i++) + { + rc = dds_set_status_mask (writers[i], DDS_PUBLICATION_MATCHED_STATUS); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + rc = dds_waitset_attach (waitset, writers[i], -(dds_attach_t)i - 1); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + } + for (size_t i = 0; i < sizeof (readers) / sizeof (readers[0]); i++) + { + rc = dds_set_status_mask (readers[i], DDS_SUBSCRIPTION_MATCHED_STATUS | DDS_DATA_AVAILABLE_STATUS); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + rc = dds_waitset_attach (waitset, readers[i], (dds_attach_t)i); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + } + + printf ("wait for discovery, fastpath_ok; delete & recreate readers\n"); + while (!(get_and_check_writer_status (sizeof (writers) / sizeof (writers[0]), writers, sizeof (readers) / sizeof (readers[0])) && + get_and_check_reader_status (sizeof (readers) / sizeof (readers[0]), readers, sizeof (writers) / sizeof (writers[0])))) + { + rc = dds_waitset_wait (waitset, NULL, 0, DDS_SECS(5)); + CU_ASSERT_FATAL (rc >= 1); + } + + /* we want to check both the fast path and the slow path ... so first wait + for it to be set on all (proxy) writers, then possibly reset it */ + for (size_t i = 0; i < sizeof (readers) / sizeof (readers[0]); i++) + waitfor_or_reset_fastpath (readers[i], true, sizeof (writers) / sizeof (writers[0])); + if (!fastpath) + { + printf ("clear fastpath_ok\n"); + for (size_t i = 0; i < sizeof (readers) / sizeof (readers[0]); i++) + waitfor_or_reset_fastpath (readers[i], false, sizeof (writers) / sizeof (writers[0])); + } + + /* check the log output for deserialization failures */ + ddsrt_atomic_uint32_t deser_fail = DDSRT_ATOMIC_UINT32_INIT (0); + dds_set_log_sink (logsink, &deser_fail); + + /* Write one of each type: all of these samples result in the same serialised + form but interpreting the memory layout for type X as-if it were of type Y + wreaks havoc. */ + { + struct type_seq s = { + .x = { + ._length = 3, ._maximum = 3, ._release = false, ._buffer = (uint32_t[]) { 1, 4, 2 } + } + }; + struct type_ary a = { + .x = { 3, 1, 4, 2 } + }; + struct type_uni u = { + ._d = 3, + ._u = { .a = { + ._length = 1, ._maximum = 1, ._release = false, ._buffer = (struct two_uint32[]) { { { 4, 2 } } } + } } + }; + printf ("writing ...\n"); + rc = dds_write_ts (writers[SEQ_IDX], &s, 1); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + rc = dds_write_ts (writers[ARY_IDX], &a, 2); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + rc = dds_write_ts (writers[UNI_IDX], &u, 3); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + + /* Also write a sample that can't be deserialised by the other types */ + struct type_seq s1 = { + .x = { + ._length = 1, ._maximum = 1, ._release = false, ._buffer = (uint32_t[]) { 1 } + } + }; + rc = dds_write_ts (writers[SEQ_IDX], &s1, 4); + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + } + + /* All readers should have received three samples, and those that are of type seq + should have received one extra (whereas the others should cause deserialization + failure warnings) */ + printf ("reading\n"); + const size_t nexp = ((sizeof (writers) / sizeof (writers[0])) * + (sizeof (readers) / sizeof (readers[0])) + + ((sizeof (readers) / sizeof (readers[0])) / (sizeof (sub_topics) / sizeof (sub_topics[0])))); + /* expecting exactly as many deserialization failures as there are topics other than seq */ + const size_t nexp_fail = sizeof (sub_topics) / sizeof (sub_topics[0]) - 1; + uint32_t nseen = 0; + while (nseen < nexp) + { + dds_sample_info_t si; + + rc = dds_waitset_wait (waitset, NULL, 0, DDS_SECS (5)); + CU_ASSERT_FATAL (rc >= 1); + + { + struct type_seq s = { .x = { 0 } }; + void *raws[] = { &s }; + while (dds_take (readers[SEQ_IDX], raws, &si, 1, 1) == 1) + { + if (!si.valid_data) + continue; + printf ("recv: seq %"PRId64"\n", si.source_timestamp); + if (si.source_timestamp == 4) + { + CU_ASSERT_FATAL (s.x._length == 1); + CU_ASSERT_FATAL (s.x._buffer[0] == 1); + } + else + { + CU_ASSERT_FATAL (si.source_timestamp >= 1 && si.source_timestamp <= 3); + CU_ASSERT_FATAL (s.x._length == 3); + CU_ASSERT_FATAL (s.x._buffer[0] == 1); + CU_ASSERT_FATAL (s.x._buffer[1] == 4); + CU_ASSERT_FATAL (s.x._buffer[2] == 2); + } + nseen++; + } + dds_free (s.x._buffer); + } + + { + struct type_ary a; + void *rawa[] = { &a }; + while (dds_take (readers[ARY_IDX], rawa, &si, 1, 1) == 1) + { + if (!si.valid_data) + continue; + printf ("recv: ary %"PRId64"\n", si.source_timestamp); + CU_ASSERT_FATAL (si.source_timestamp >= 1 && si.source_timestamp <= 3); + CU_ASSERT_FATAL (a.x[0] == 3); + CU_ASSERT_FATAL (a.x[1] == 1); + CU_ASSERT_FATAL (a.x[2] == 4); + CU_ASSERT_FATAL (a.x[3] == 2); + nseen++; + } + } + + { + struct type_uni u = { ._u.a = { 0 } }; + void *rawu[] = { &u }; + while (dds_take (readers[UNI_IDX], rawu, &si, 1, 1) == 1) + { + if (!si.valid_data) + continue; + printf ("recv: uni %"PRId64"\n", si.source_timestamp); + CU_ASSERT_FATAL (si.source_timestamp >= 1 && si.source_timestamp <= 3); + CU_ASSERT_FATAL (u._d == 3); + CU_ASSERT_FATAL (u._u.a._length == 1); + assert (u._u.a._buffer != NULL); /* for Clang static analyzer */ + CU_ASSERT_FATAL (u._u.a._buffer[0].v[0] == 4); + CU_ASSERT_FATAL (u._u.a._buffer[0].v[1] == 2); + dds_free (u._u.a._buffer); + u._u.a._buffer = NULL; + nseen++; + } + } + + DDSRT_STATIC_ASSERT (((1u << SEQ_IDX) | (1u << ARY_IDX) | (1u << UNI_IDX)) == 7); + for (size_t i = 3; i < sizeof (readers) / sizeof (readers[0]); i++) + { + struct ddsi_serdata *sample; + while (dds_takecdr (readers[i], &sample, 1, &si, DDS_ANY_STATE) == 1) + { + if (!si.valid_data) + continue; + printf ("recv: reader %zu %"PRId64"\n", i, si.source_timestamp); + CU_ASSERT_FATAL (sample->topic == get_sertopic_from_reader (readers[i])); + ddsi_serdata_unref (sample); + nseen++; + } + } + } + CU_ASSERT_FATAL (nseen == nexp); + + /* data from remote writers can cause a deserialization failure after all + expected samples have been seen (becasue it is written last); so wait + for them */ + while (ddsrt_atomic_ld32 (&deser_fail) < nexp_fail) + dds_sleepfor (DDS_MSECS (10)); + CU_ASSERT_FATAL (ddsrt_atomic_ld32 (&deser_fail) == nexp_fail); + + /* deleting the waitset is important: it is bound to the library rather than to + a domain and consequently won't be deleted simply because all domains are */ + rc = dds_delete (waitset); + + CU_ASSERT_FATAL (rc == DDS_RETCODE_OK); + dds_set_log_sink (0, NULL); +} + +CU_Test(ddsc_multi_sertopic, local, .init = multi_sertopic_init, .fini = multi_sertopic_fini) +{ + ddsc_multi_sertopic_impl (g_pub_participant, g_pub_participant, true); +} + +CU_Test(ddsc_multi_sertopic, remote, .init = multi_sertopic_init, .fini = multi_sertopic_fini) +{ + ddsc_multi_sertopic_impl (g_pub_participant, g_sub_participant, true); +} + +CU_Test(ddsc_multi_sertopic, local_slowpath, .init = multi_sertopic_init, .fini = multi_sertopic_fini) +{ + ddsc_multi_sertopic_impl (g_pub_participant, g_pub_participant, false); +} + +CU_Test(ddsc_multi_sertopic, remote_slowpath, .init = multi_sertopic_init, .fini = multi_sertopic_fini) +{ + ddsc_multi_sertopic_impl (g_pub_participant, g_sub_participant, false); +} diff --git a/src/core/ddsc/tests/topic.c b/src/core/ddsc/tests/topic.c index 3707715..813d77f 100644 --- a/src/core/ddsc/tests/topic.c +++ b/src/core/ddsc/tests/topic.c @@ -130,8 +130,12 @@ CU_Test(ddsc_topic_create, duplicate, .init=ddsc_topic_init, .fini=ddsc_topic_fi /* Creating the same topic should succeed. */ topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, g_topicRtmDataTypeName, NULL, NULL); CU_ASSERT_FATAL(topic > 0); + CU_ASSERT_FATAL(topic != g_topicRtmDataType); ret = dds_delete(topic); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* Old topic entity should remain in existence */ + ret = dds_get_parent(g_topicRtmDataType); + CU_ASSERT(ret > 0); } /*************************************************************************************************/ @@ -201,7 +205,7 @@ CU_Test(ddsc_topic_find, valid, .init=ddsc_topic_init, .fini=ddsc_topic_fini) dds_return_t ret; topic = dds_find_topic(g_participant, g_topicRtmDataTypeName); - CU_ASSERT_EQUAL_FATAL(topic, g_topicRtmDataType); + CU_ASSERT_NOT_EQUAL_FATAL(topic, g_topicRtmDataType); ret = dds_delete(topic); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); diff --git a/src/core/ddsc/tests/unsupported.c b/src/core/ddsc/tests/unsupported.c index b7e63cb..9c538ce 100644 --- a/src/core/ddsc/tests/unsupported.c +++ b/src/core/ddsc/tests/unsupported.c @@ -84,21 +84,6 @@ CU_Test(ddsc_unsupported, dds_begin_end_coherent, .init = setup, .fini = teardow } } -CU_Test(ddsc_unsupported, dds_wait_for_acks, .init = setup, .fini = teardown) -{ - dds_return_t result; - static struct index_result pars[] = { - {PUB, DDS_RETCODE_UNSUPPORTED}, - {WRI, DDS_RETCODE_UNSUPPORTED}, - {BAD, DDS_RETCODE_BAD_PARAMETER} - }; - - 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(result, pars[i].exp_res); - } -} - CU_Test(ddsc_unsupported, dds_suspend_resume, .init = setup, .fini = teardown) { dds_return_t result; diff --git a/src/core/ddsc/tests/whc.c b/src/core/ddsc/tests/whc.c new file mode 100644 index 0000000..212c51a --- /dev/null +++ b/src/core/ddsc/tests/whc.c @@ -0,0 +1,279 @@ +/* + * 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/dds.h" +#include "CUnit/Theory.h" +#include "Space.h" + +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_whc.h" +#include "dds__entity.h" + +#define DDS_DOMAINID_PUB 0 +#define DDS_DOMAINID_SUB 1 +#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" +#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}cyclonedds_whc_test.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.logfinest0" + +#define SAMPLE_COUNT 5 +#define DEADLINE_DURATION DDS_MSECS(1) + +static uint32_t g_topic_nr = 0; +static dds_entity_t g_domain = 0; +static dds_entity_t g_participant = 0; +static dds_entity_t g_subscriber = 0; +static dds_entity_t g_publisher = 0; +static dds_qos_t *g_qos; +static dds_entity_t g_remote_domain = 0; +static dds_entity_t g_remote_participant = 0; +static dds_entity_t g_remote_subscriber = 0; + +static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) +{ + /* Get unique g_topic name. */ + ddsrt_pid_t pid = ddsrt_getpid (); + ddsrt_tid_t tid = ddsrt_gettid (); + (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); + return name; +} + +static void whc_init(void) +{ + /* Domains for pub and sub use a different domain id, but the portgain setting + * in configuration is 0, so that both domains will map to the same port number. + * This allows to create two domains in a single test process. */ + char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB); + char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB); + g_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub); + g_remote_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub); + dds_free(conf_pub); + dds_free(conf_sub); + + g_qos = dds_create_qos(); + CU_ASSERT_PTR_NOT_NULL_FATAL(g_qos); + + g_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL); + CU_ASSERT_FATAL(g_participant > 0); + g_remote_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL); + CU_ASSERT_FATAL(g_remote_participant > 0); + + g_subscriber = dds_create_subscriber(g_participant, NULL, NULL); + CU_ASSERT_FATAL(g_subscriber > 0); + + g_remote_subscriber = dds_create_subscriber(g_remote_participant, NULL, NULL); + CU_ASSERT_FATAL(g_remote_subscriber > 0); + + g_publisher = dds_create_publisher(g_participant, NULL, NULL); + CU_ASSERT_FATAL(g_publisher > 0); +} + +static void whc_fini (void) +{ + dds_delete_qos(g_qos); + dds_delete(g_subscriber); + dds_delete(g_remote_subscriber); + dds_delete(g_publisher); + dds_delete(g_participant); + dds_delete(g_remote_participant); + dds_delete(g_domain); + dds_delete(g_remote_domain); +} + +static dds_entity_t create_and_sync_reader(dds_entity_t subscriber, dds_entity_t topic, dds_qos_t *qos, dds_entity_t writer) +{ + dds_return_t ret; + dds_entity_t reader = dds_create_reader(subscriber, topic, qos, NULL); + CU_ASSERT_FATAL(reader > 0); + while (1) + { + dds_publication_matched_status_t st; + ret = dds_get_publication_matched_status (writer, &st); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + if (st.current_count_change == 1) + break; + dds_sleepfor (DDS_MSECS (1)); + } + return reader; +} + +static void check_whc_state(dds_entity_t writer, seqno_t exp_min, seqno_t exp_max) +{ + struct dds_entity *wr_entity; + struct writer *wr; + struct whc_state whcst; + CU_ASSERT_EQUAL_FATAL(dds_entity_pin(writer, &wr_entity), 0); + thread_state_awake(lookup_thread_state(), &wr_entity->m_domain->gv); + wr = entidx_lookup_writer_guid(wr_entity->m_domain->gv.entity_index, &wr_entity->m_guid); + CU_ASSERT_FATAL(wr != NULL); + assert(wr != NULL); /* for Clang's static analyzer */ + whc_get_state(wr->whc, &whcst); + thread_state_asleep(lookup_thread_state()); + dds_entity_unpin(wr_entity); + + printf(" -- final state: unacked: %zu; min %"PRId64" (exp %"PRId64"); max %"PRId64" (exp %"PRId64")\n", whcst.unacked_bytes, whcst.min_seq, exp_min, whcst.max_seq, exp_max); + CU_ASSERT_EQUAL_FATAL (whcst.unacked_bytes, 0); + CU_ASSERT_EQUAL_FATAL (whcst.min_seq, exp_min); + CU_ASSERT_EQUAL_FATAL (whcst.max_seq, exp_max); +} + + +#define V DDS_DURABILITY_VOLATILE +#define TL DDS_DURABILITY_TRANSIENT_LOCAL +#define R DDS_RELIABILITY_RELIABLE +#define BE DDS_RELIABILITY_BEST_EFFORT +#define KA DDS_HISTORY_KEEP_ALL +#define KL DDS_HISTORY_KEEP_LAST +static void test_whc_end_state(dds_durability_kind_t d, dds_reliability_kind_t r, dds_history_kind_t h, int32_t hd, dds_history_kind_t dh, + int32_t dhd, bool lrd, bool rrd, int32_t ni, bool k, bool dl) +{ + char name[100]; + Space_Type1 sample = { 0, 0, 0 }; + Space_Type3 sample_keyless = { 0, 0, 0 }; + dds_entity_t reader, reader_remote, writer; + dds_entity_t topic; + dds_entity_t remote_topic; + dds_return_t ret; + int32_t s, i; + + printf ("test_whc_end_state: %s, %s, %s(%d), durability %s(%d), readers: %u local, %u remote, instances: %u, key %u, deadline %"PRId64"\n", + d == V ? "volatile" : "TL", + r == BE ? "best-effort" : "reliable", + h == KA ? "keep-all" : "keep-last", h == KA ? 0 : hd, + dh == KA ? "keep-all" : "keep-last", dh == KA ? 0 : dhd, + lrd, rrd, ni, k, + dl ? DEADLINE_DURATION : INT64_C(-1)); + + dds_qset_durability (g_qos, d); + dds_qset_reliability (g_qos, r, DDS_INFINITY); + dds_qset_history (g_qos, h, h == KA ? 0 : hd); + dds_qset_deadline (g_qos, dl ? DEADLINE_DURATION : DDS_INFINITY); + dds_qset_durability_service (g_qos, 0, dh, dh == KA ? 0 : dhd, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED); + + create_topic_name ("ddsc_whc_end_state_test", g_topic_nr++, name, sizeof name); + topic = dds_create_topic (g_participant, k ? &Space_Type1_desc : &Space_Type3_desc, name, NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + remote_topic = dds_create_topic (g_remote_participant, k ? &Space_Type1_desc : &Space_Type3_desc, name, NULL, NULL); + CU_ASSERT_FATAL(remote_topic > 0); + + writer = dds_create_writer (g_publisher, topic, g_qos, NULL); + CU_ASSERT_FATAL(writer > 0); + ret = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK) + + reader = lrd ? create_and_sync_reader (g_subscriber, topic, g_qos, writer) : 0; + reader_remote = rrd ? create_and_sync_reader (g_remote_subscriber, remote_topic, g_qos, writer) : 0; + + for (s = 0; s < SAMPLE_COUNT; s++) + { + if (k) + for (i = 0; i < ni; i++) + { + sample.long_1 = (int32_t)i; + ret = dds_write (writer, &sample); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + } + else + { + ret = dds_write (writer, &sample_keyless); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + } + } + + /* delete readers, wait until no matching reader */ + if (rrd) + { + ret = dds_delete (reader_remote); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + } + if (lrd) + { + ret = dds_delete (reader); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + } + while (1) + { + dds_publication_matched_status_t st; + ret = dds_get_publication_matched_status (writer, &st); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + if (st.current_count == 0) + break; + dds_sleepfor (DDS_MSECS (1)); + } + + /* check whc state */ + int32_t exp_max = (d == TL) ? ni * SAMPLE_COUNT : -1; + int32_t exp_min = (d == TL) ? ((dh == KA) ? 1 : exp_max - dhd * ni + 1) : -1; + check_whc_state (writer, exp_min, exp_max); + + dds_delete (writer); + dds_delete (remote_topic); + dds_delete (topic); +} + +#define ARRAY_LEN(A) ((int32_t)(sizeof(A) / sizeof(A[0]))) +CU_Test(ddsc_whc, check_end_state, .init=whc_init, .fini=whc_fini, .timeout=30) +{ + dds_durability_kind_t dur[] = {V, TL}; + dds_reliability_kind_t rel[] = {BE, R}; + dds_history_kind_t hist[] = {KA, KL}; + dds_history_kind_t dhist[] = {KA, KL}; + int32_t hist_depth[] = {1, 3}; + int32_t dhist_depth[] = {1, 3}; + bool loc_rd[] = {false, true}; + bool rem_rd[] = {false, true}; + int32_t n_inst[] = {1, 3}; + bool keyed[] = {false, true}; +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + bool deadline[] = {false, true}; +#else + bool deadline[] = {false}; +#endif + int32_t i_d, i_r, i_h, i_hd, i_dh, i_dhd, i_lrd, i_rrd, i_ni, i_k, i_dl; + + for (i_d = 0; i_d < ARRAY_LEN(dur); i_d++) + for (i_r = 0; i_r < ARRAY_LEN(rel); i_r++) + for (i_h = 0; i_h < ARRAY_LEN(hist); i_h++) + for (i_hd = 0; i_hd < ARRAY_LEN(hist_depth); i_hd++) + for (i_dh = 0; i_dh < ARRAY_LEN(dhist); i_dh++) + for (i_dhd = 0; i_dhd < ARRAY_LEN(dhist_depth); i_dhd++) + for (i_lrd = 0; i_lrd < ARRAY_LEN(loc_rd); i_lrd++) + for (i_rrd = 0; i_rrd < ARRAY_LEN(rem_rd); i_rrd++) + for (i_ni = 0; i_ni < ARRAY_LEN(n_inst); i_ni++) + for (i_k = 0; i_k < ARRAY_LEN(keyed); i_k++) + for (i_dl = 0; i_dl < ARRAY_LEN(deadline); i_dl++) + { + if (rel[i_r] == BE && dur[i_d] == TL) + continue; + else if (hist[i_h] == KA && i_hd > 0) + continue; + else if (dhist[i_dh] == KA && i_dhd > 0) + continue; + else + { + test_whc_end_state (dur[i_d], rel[i_r], hist[i_h], hist_depth[i_hd], dhist[i_dh], dhist_depth[i_dhd], + loc_rd[i_lrd], rem_rd[i_rrd], keyed[i_k] ? n_inst[i_ni] : 1, keyed[i_k], deadline[i_dl]); + } + } +} + +#undef ARRAY_LEN +#undef V +#undef TL +#undef R +#undef BE +#undef KA +#undef KL diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index 75c2342..ddd07fd 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -32,6 +32,10 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" ddsi_rhc.c ddsi_pmd.c ddsi_entity_index.c + ddsi_deadline.c + ddsi_deliver_locally.c + ddsi_plist.c + ddsi_cdrstream.c q_addrset.c q_bitset_inlines.c q_bswap.c @@ -46,7 +50,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" q_misc.c q_nwif.c q_pcap.c - q_plist.c q_qosmatch.c q_radmin.c q_receive.c @@ -65,6 +68,10 @@ if(ENABLE_LIFESPAN) list(APPEND srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src/ddsi_lifespan.c") endif() +if(ENABLE_DEADLINE_MISSED) + list(APPEND srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src/ddsi_deadline.c") +endif() + # The includes should reside close to the code. As long as that's not the case, # pull them in from this CMakeLists.txt. PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" @@ -90,6 +97,12 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" ddsi_rhc.h ddsi_guid.h ddsi_entity_index.h + ddsi_deadline.h + ddsi_deliver_locally.h + ddsi_domaingv.h + ddsi_plist.h + ddsi_xqos.h + ddsi_cdrstream.h q_addrset.h q_bitset.h q_bswap.h @@ -100,7 +113,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_feature_check.h q_freelist.h q_gc.h - q_globals.h q_hbcontrol.h q_lat_estim.h q_lease.h @@ -108,7 +120,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_misc.h q_nwif.h q_pcap.h - q_plist.h q_protocol.h q_qosmatch.h q_radmin.h @@ -123,12 +134,14 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_whc.h q_xevent.h q_xmsg.h - q_xqos.h sysdeps.h ) if(ENABLE_LIFESPAN) list(APPEND hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi/ddsi_lifespan.h") endif() +if(ENABLE_DEADLINE_MISSED) + list(APPEND hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi/ddsi_deadline.h") +endif() target_sources(ddsc PRIVATE ${srcs_ddsi} ${hdrs_private_ddsi}) diff --git a/src/core/ddsc/src/dds__stream.h b/src/core/ddsi/include/dds/ddsi/ddsi_cdrstream.h similarity index 94% rename from src/core/ddsc/src/dds__stream.h rename to src/core/ddsi/include/dds/ddsi/ddsi_cdrstream.h index 7facf45..56ad225 100644 --- a/src/core/ddsc/src/dds__stream.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_cdrstream.h @@ -9,8 +9,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef _DDS_STREAM_H_ -#define _DDS_STREAM_H_ +#ifndef DDSI_CDRSTREAM_H +#define DDSI_CDRSTREAM_H #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_serdata_default.h" @@ -44,8 +44,10 @@ bool dds_stream_normalize (void * __restrict data, uint32_t size, bool bswap, co 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); +void dds_stream_free_sample (void *data, const uint32_t * ops); -size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc); +uint32_t dds_stream_countops (const uint32_t * __restrict ops); +size_t dds_stream_check_optimize (const struct ddsi_sertopic_default_desc * __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); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_deadline.h b/src/core/ddsi/include/dds/ddsi/ddsi_deadline.h new file mode 100644 index 0000000..4903eca --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_deadline.h @@ -0,0 +1,84 @@ +/* + * 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 + */ +#ifndef DDSI_DEADLINE_H +#define DDSI_DEADLINE_H + +#include "dds/ddsrt/circlist.h" +#include "dds/ddsi/q_time.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_xevent.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +typedef nn_mtime_t (*deadline_missed_cb_t)(void *hc, nn_mtime_t tnow); + +struct deadline_adm { + struct ddsrt_circlist list; /* linked list for deadline missed */ + struct xevent *evt; /* xevent that triggers when deadline expires for an instance */ + deadline_missed_cb_t deadline_missed_cb; /* callback for deadline missed; this cb can use deadline_next_missed_locked to get next instance that has a missed deadline */ + size_t list_offset; /* offset of deadline_adm element in whc or rhc */ + size_t elem_offset; /* offset of deadline_elem element in whc or rhc instance */ + dds_duration_t dur; /* deadline duration */ +}; + +struct deadline_elem { + struct ddsrt_circlist_elem e; + nn_mtime_t t_deadline; +}; + +DDS_EXPORT void deadline_init (const struct ddsi_domaingv *gv, struct deadline_adm *deadline_adm, size_t list_offset, size_t elem_offset, deadline_missed_cb_t deadline_missed_cb); +DDS_EXPORT void deadline_stop (const struct deadline_adm *deadline_adm); +DDS_EXPORT void deadline_clear (struct deadline_adm *deadline_adm); +DDS_EXPORT void deadline_fini (const struct deadline_adm *deadline_adm); +DDS_EXPORT nn_mtime_t deadline_next_missed_locked (struct deadline_adm *deadline_adm, nn_mtime_t tnow, void **instance); +DDS_EXPORT void deadline_register_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tprev, nn_mtime_t tnow); +DDS_EXPORT void deadline_unregister_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem); +DDS_EXPORT void deadline_renew_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem); + +inline void deadline_register_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tnow) +{ + if (deadline_adm->dur != T_NEVER) + deadline_register_instance_real (deadline_adm, elem, tnow, tnow); +} + +inline void deadline_reregister_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tnow) +{ + if (deadline_adm->dur != T_NEVER) + deadline_register_instance_real (deadline_adm, elem, elem->t_deadline, tnow); +} + +inline void deadline_unregister_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem) +{ + if (deadline_adm->dur != T_NEVER) + { + assert (elem->t_deadline.v != T_NEVER); + deadline_unregister_instance_real (deadline_adm, elem); + } +} + +inline void deadline_renew_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem) +{ + if (deadline_adm->dur != T_NEVER) + { + assert (elem->t_deadline.v != T_NEVER); + deadline_renew_instance_real (deadline_adm, elem); + } +} + +#if defined (__cplusplus) +} +#endif + +#endif /* DDSI_DEADLINE_H */ + diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_deliver_locally.h b/src/core/ddsi/include/dds/ddsi/ddsi_deliver_locally.h new file mode 100644 index 0000000..53d584e --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_deliver_locally.h @@ -0,0 +1,62 @@ +/* + * Copyright(c) 2020 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_DELIVER_LOCALLY_H +#define DDSI_DELIVER_LOCALLY_H + +#include +#include + +#include "dds/export.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/avl.h" +#include "dds/ddsi/ddsi_guid.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +struct ddsi_domaingv; +struct ddsi_tkmap_instance; +struct ddsi_sertopic; +struct ddsi_serdata; +struct entity_index; +struct reader; +struct entity_common; +struct ddsi_writer_info; +struct local_reader_ary; + +typedef struct ddsi_serdata * (*deliver_locally_makesample_t) (struct ddsi_tkmap_instance **tk, struct ddsi_domaingv *gv, struct ddsi_sertopic const * const topic, void *vsourceinfo); +typedef struct reader * (*deliver_locally_first_reader_t) (struct entity_index *entity_index, struct entity_common *source_entity, ddsrt_avl_iter_t *it); +typedef struct reader * (*deliver_locally_next_reader_t) (struct entity_index *entity_index, ddsrt_avl_iter_t *it); + +/** return: + - DDS_RETCODE_OK to try again immediately + - DDS_RETCODE_TRY_AGAIN to complete restart the operation later + - anything else: error to be returned from deliver_locally_xxx */ +typedef dds_return_t (*deliver_locally_on_failure_fastpath_t) (struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, void *vsourceinfo); + +struct deliver_locally_ops { + deliver_locally_makesample_t makesample; + deliver_locally_first_reader_t first_reader; + deliver_locally_next_reader_t next_reader; + deliver_locally_on_failure_fastpath_t on_failure_fastpath; +}; + +dds_return_t deliver_locally_one (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, const ddsi_guid_t *rdguid, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo); + +dds_return_t deliver_locally_allinsync (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo); + +#if defined (__cplusplus) +} +#endif + +#endif /* DDSI_DELIVER_LOCALLY_H */ diff --git a/src/core/ddsi/include/dds/ddsi/q_globals.h b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h similarity index 95% rename from src/core/ddsi/include/dds/ddsi/q_globals.h rename to src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h index e261652..17fc797 100644 --- a/src/core/ddsi/include/dds/ddsi/q_globals.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h @@ -9,8 +9,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef Q_GLOBALS_H -#define Q_GLOBALS_H +#ifndef DDSI_DOMAINGV_H +#define DDSI_DOMAINGV_H #include @@ -20,7 +20,7 @@ #include "dds/ddsrt/sync.h" #include "dds/ddsrt/fibheap.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_sockwaitset.h" @@ -69,7 +69,7 @@ enum recv_thread_mode { struct recv_thread_arg { enum recv_thread_mode mode; struct nn_rbufpool *rbpool; - struct q_globals *gv; + struct ddsi_domaingv *gv; union { struct { const nn_locator_t *loc; @@ -83,7 +83,7 @@ struct recv_thread_arg { struct deleted_participants_admin; -struct q_globals { +struct ddsi_domaingv { volatile int terminate; volatile int deaf; volatile int mute; @@ -226,8 +226,8 @@ struct q_globals { supplying values for missing QoS settings in incoming discovery packets); plus the actual QoSs needed for the builtin endpoints. */ - nn_plist_t default_plist_pp; - nn_plist_t default_local_plist_pp; + ddsi_plist_t default_plist_pp; + ddsi_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; @@ -277,11 +277,6 @@ struct q_globals { struct ddsi_sertopic *plist_topic; /* used for all discovery data */ struct ddsi_sertopic *rawcdr_topic; /* used for participant message data */ - /* Network ID needed by v_groupWrite -- FIXME: might as well pass it - to the receive thread instead of making it global (and that would - remove the need to include kernelModule.h) */ - uint32_t myNetworkId; - ddsrt_mutex_t sendq_lock; ddsrt_cond_t sendq_cond; unsigned sendq_length; @@ -298,6 +293,9 @@ struct q_globals { struct nn_group_membership *mship; + ddsrt_mutex_t sertopics_lock; + struct ddsrt_hh *sertopics; + /* security globals */ #ifdef DDSI_INCLUDE_SECURITY struct dds_security_context *security_context; @@ -308,4 +306,4 @@ struct q_globals { } #endif -#endif /* Q_GLOBALS_H */ +#endif /* DDSI_DOMAINGV_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h b/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h index 1566feb..bedf8e8 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h @@ -21,7 +21,7 @@ extern "C" { struct entity_index; struct ddsi_guid; -struct q_globals; +struct ddsi_domaingv; struct match_entities_range_key { union { @@ -63,7 +63,7 @@ struct entidx_enum at the protocol level slightly before the network reader can use it to transmit data. */ -struct entity_index *entity_index_new (struct q_globals *gv) ddsrt_nonnull_all; +struct entity_index *entity_index_new (struct ddsi_domaingv *gv) ddsrt_nonnull_all; void entity_index_free (struct entity_index *ei) ddsrt_nonnull_all; void entidx_insert_participant_guid (struct entity_index *ei, struct participant *pp) ddsrt_nonnull_all; diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h index 1aef76d..91300d4 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h @@ -37,7 +37,7 @@ enum ddsi_handshake_state { /* The handshake will not use the related handshake object after this callback * was executed. This means that it can be deleted in this callback. */ typedef void (*ddsi_handshake_end_cb_t)( - struct q_globals const * const gv, + struct ddsi_domaingv const * const gv, struct ddsi_handshake *handshake, const ddsi_guid_t *lpguid, /* Local participant */ const ddsi_guid_t *ppguid, /* Proxy participant */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h b/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h index 96257fa..392c41b 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_ipaddr.h @@ -18,11 +18,11 @@ extern "C" { #endif -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_nearby_address_result ddsi_ipaddr_is_nearby_address (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); -void ddsi_ipaddr_to_loc (nn_locator_t *dst, const struct sockaddr *src, int32_t kind); +char *ddsi_ipaddr_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port); +void ddsi_ipaddr_to_loc (const struct ddsi_tran_factory *tran, nn_locator_t *dst, const struct sockaddr *src, int32_t kind); void ddsi_ipaddr_from_loc (struct sockaddr_storage *dst, const nn_locator_t *src); #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_lifespan.h b/src/core/ddsi/include/dds/ddsi/ddsi_lifespan.h index 8ce3fee..7c1843c 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_lifespan.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_lifespan.h @@ -14,7 +14,7 @@ #include "dds/ddsrt/fibheap.h" #include "dds/ddsi/q_time.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #if defined (__cplusplus) extern "C" { @@ -35,7 +35,7 @@ struct lifespan_fhnode { nn_mtime_t t_expire; }; -DDS_EXPORT void lifespan_init (const struct q_globals *gv, struct lifespan_adm *lifespan_adm, size_t fh_offset, size_t fh_node_offset, sample_expired_cb_t sample_expired_cb); +DDS_EXPORT void lifespan_init (const struct ddsi_domaingv *gv, struct lifespan_adm *lifespan_adm, size_t fh_offset, size_t fh_node_offset, sample_expired_cb_t sample_expired_cb); DDS_EXPORT void lifespan_fini (const struct lifespan_adm *lifespan_adm); DDS_EXPORT nn_mtime_t lifespan_next_expired_locked (const struct lifespan_adm *lifespan_adm, nn_mtime_t tnow, void **sample); DDS_EXPORT void lifespan_register_sample_real (struct lifespan_adm *lifespan_adm, struct lifespan_fhnode *node); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h b/src/core/ddsi/include/dds/ddsi/ddsi_mcgroup.h index 37b403c..8a865ef 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 (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); +int ddsi_join_mc (const struct ddsi_domaingv *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 ddsi_domaingv *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); +int ddsi_rejoin_transferred_mcgroups (const struct ddsi_domaingv *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_plist.h b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h similarity index 86% rename from src/core/ddsi/include/dds/ddsi/q_plist.h rename to src/core/ddsi/include/dds/ddsi/ddsi_plist.h index d40ef75..c6f5a8d 100644 --- a/src/core/ddsi/include/dds/ddsi/q_plist.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h @@ -9,18 +9,17 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef NN_PLIST_H -#define NN_PLIST_H +#ifndef DDSI_PLIST_H +#define DDSI_PLIST_H #include "dds/ddsi/q_feature_check.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_tran.h" /* FIXME: eliminate */ #if defined (__cplusplus) extern "C" { #endif - #define PP_PROTOCOL_VERSION ((uint64_t)1 << 0) #define PP_VENDORID ((uint64_t)1 << 1) #define PP_UNICAST_LOCATOR ((uint64_t)1 << 2) @@ -47,24 +46,20 @@ extern "C" { #define PP_ORIGINAL_WRITER_INFO ((uint64_t)1 << 23) #define PP_ENDPOINT_GUID ((uint64_t)1 << 24) #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_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_TYPE_DESCRIPTION ((uint64_t)1 << 27) +#define PP_COHERENT_SET ((uint64_t)1 << 28) #ifdef DDSI_INCLUDE_SSM -#define PP_READER_FAVOURS_SSM ((uint64_t)1 << 39) +#define PP_READER_FAVOURS_SSM ((uint64_t)1 << 29) #endif -#define PP_DOMAIN_ID ((uint64_t)1 << 40) -#define PP_DOMAIN_TAG ((uint64_t)1 << 41) +#define PP_DOMAIN_ID ((uint64_t)1 << 30) +#define PP_DOMAIN_TAG ((uint64_t)1 << 31) /* Security extensions. */ -#define PP_IDENTITY_TOKEN ((uint64_t)1 << 42) -#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 43) -#define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 44) -#define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 45) -#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 46) -#define PP_DATA_TAGS ((uint64_t)1 << 47) +#define PP_IDENTITY_TOKEN ((uint64_t)1 << 32) +#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 33) +#define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 34) +#define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 35) +#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 36) +#define PP_DATA_TAGS ((uint64_t)1 << 37) /* Set for unrecognized parameters that are in the reserved space or in our own vendor-specific space that have the PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */ @@ -193,7 +188,7 @@ typedef struct nn_prismtech_eotgroup_tid { uint32_t transactionId; } nn_prismtech_eotgroup_tid_t; -typedef struct nn_plist { +typedef struct ddsi_plist { uint64_t present; uint64_t aliased; @@ -221,15 +216,11 @@ typedef struct nn_plist { nn_entityid_t group_entityid; #endif uint32_t builtin_endpoint_set; - uint32_t prismtech_builtin_endpoint_set; /* int type_max_size_serialized; */ char *entity_name; nn_keyhash_t keyhash; uint32_t statusinfo; nn_prismtech_participant_version_info_t prismtech_participant_version_info; - char *node_name; - char *exec_name; - uint32_t process_id; char *type_description; nn_sequence_number_t coherent_set_seqno; #ifdef DDSI_INCLUDE_SECURITY @@ -245,12 +236,12 @@ typedef struct nn_plist { #endif uint32_t domain_id; char *domain_tag; -} nn_plist_t; +} ddsi_plist_t; /***/ -typedef struct nn_plist_src { +typedef struct ddsi_plist_src { nn_protocol_version_t protocol_version; nn_vendorid_t vendorid; int encoding; @@ -259,16 +250,16 @@ typedef struct nn_plist_src { bool strict; ddsi_tran_factory_t factory; /* eliminate this */ struct ddsrt_log_cfg *logconfig; -} nn_plist_src_t; +} ddsi_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, 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); +void ddsi_plist_init_tables (void); +DDS_EXPORT void ddsi_plist_init_empty (ddsi_plist_t *dest); +DDS_EXPORT void ddsi_plist_mergein_missing (ddsi_plist_t *a, const ddsi_plist_t *b, uint64_t pmask, uint64_t qmask); +DDS_EXPORT void ddsi_plist_copy (ddsi_plist_t *dst, const ddsi_plist_t *src); +DDS_EXPORT ddsi_plist_t *ddsi_plist_dup (const ddsi_plist_t *src); /** - * @brief Initialize an nn_plist_t from a PL_CDR_{LE,BE} paylaod. + * @brief Initialize an ddsi_plist_t from a PL_CDR_{LE,BE} paylaod. * * @param[in] pwanted * PP_... flags indicating which non-QoS parameters are of interest, treated as @@ -293,8 +284,8 @@ DDS_EXPORT nn_plist_t *nn_plist_dup (const nn_plist_t *src); * 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. + * Generally, ddsi_plist_fini should be called when done with the parameter list, + * even when ddsi_plist_unlias or ddsi_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 @@ -313,21 +304,25 @@ DDS_EXPORT nn_plist_t *nn_plist_dup (const nn_plist_t *src); * 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 void nn_plist_init_default_participant (nn_plist_t *plist); +DDS_EXPORT dds_return_t ddsi_plist_init_frommsg (ddsi_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const ddsi_plist_src_t *src); +DDS_EXPORT void ddsi_plist_fini (ddsi_plist_t *ps); +DDS_EXPORT void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask); +DDS_EXPORT void ddsi_plist_unalias (ddsi_plist_t *plist); +DDS_EXPORT void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted); +DDS_EXPORT void ddsi_plist_init_default_participant (ddsi_plist_t *plist); +DDS_EXPORT void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask); +DDS_EXPORT void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist); +DDS_EXPORT size_t ddsi_plist_print (char * __restrict buf, size_t bufsize, const ddsi_plist_t *plist); struct nn_rmsg; struct nn_rsample_info; struct nn_rdata; -DDS_EXPORT unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const nn_plist_src_t *src); -DDS_EXPORT const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid); +DDS_EXPORT unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src); +DDS_EXPORT const unsigned char *ddsi_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid); #if defined (__cplusplus) } #endif -#endif /* NN_PLIST_H */ +#endif /* DDSI_PLIST_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h index c2638f2..a2b1daf 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h @@ -18,14 +18,14 @@ extern "C" { #endif -struct q_globals; +struct ddsi_domaingv; struct thread_state1; struct ddsi_guid; struct nn_xpack; struct participant; struct receiver_state; -void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind); +void write_pmd_message_guid (struct ddsi_domaingv * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind); void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind); void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h b/src/core/ddsi/include/dds/ddsi/ddsi_raweth.h index 54b4479..abd2857 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 (struct q_globals *gv); +int ddsi_raweth_init (struct ddsi_domaingv *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h index e8ced85..a35a43d 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h @@ -14,7 +14,7 @@ #ifdef DDSI_INCLUDE_SECURITY -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_guid.h" #include "dds/ddsrt/retcode.h" #include "dds/ddsi/ddsi_plist_generic.h" diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h index 220c29b..d6a36ea 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h @@ -12,9 +12,9 @@ #ifndef DDSI_OMG_SECURITY_H #define DDSI_OMG_SECURITY_H -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsrt/retcode.h" @@ -164,7 +164,7 @@ unsigned determine_publication_writer(const struct writer *wr); */ bool is_proxy_participant_deletion_allowed( - struct q_globals * const gv, + struct ddsi_domaingv * const gv, const struct ddsi_guid *guid, const ddsi_entityid_t pwr_entityid); @@ -210,7 +210,7 @@ q_omg_security_is_local_rtps_protected( void set_proxy_participant_security_info( struct proxy_participant *proxypp, - const nn_plist_t *plist); + const ddsi_plist_t *plist); /** * @brief Set security information, depending on plist and proxy participant, @@ -222,7 +222,7 @@ set_proxy_participant_security_info( void set_proxy_reader_security_info( struct proxy_reader *prd, - const nn_plist_t *plist); + const ddsi_plist_t *plist); /** * @brief Set security information, depending on plist and proxy participant, @@ -234,7 +234,7 @@ set_proxy_reader_security_info( void set_proxy_writer_security_info( struct proxy_writer *pwr, - const nn_plist_t *plist); + const ddsi_plist_t *plist); /** * @brief Encode RTPS message. @@ -311,7 +311,7 @@ encode_payload( */ bool decode_Data( - const struct q_globals *gv, + const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, @@ -339,7 +339,7 @@ decode_Data( */ bool decode_DataFrag( - const struct q_globals *gv, + const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, @@ -464,7 +464,7 @@ decode_SecPrefix( nn_rtps_msg_state_t decode_rtps_message( struct thread_state1 * const ts1, - struct q_globals *gv, + struct ddsi_domaingv *gv, struct nn_rmsg **rmsg, Header_t **hdr, unsigned char **buff, @@ -748,7 +748,7 @@ determine_publication_writer( inline bool is_proxy_participant_deletion_allowed( - UNUSED_ARG(struct q_globals * const gv), + UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const struct ddsi_guid *guid), UNUSED_ARG(const ddsi_entityid_t pwr_entityid)) { @@ -817,27 +817,27 @@ q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_rea inline void set_proxy_participant_security_info( UNUSED_ARG(struct proxy_participant *prd), - UNUSED_ARG(const nn_plist_t *plist)) + UNUSED_ARG(const ddsi_plist_t *plist)) { } inline void set_proxy_reader_security_info( UNUSED_ARG(struct proxy_reader *prd), - UNUSED_ARG(const nn_plist_t *plist)) + UNUSED_ARG(const ddsi_plist_t *plist)) { } inline void set_proxy_writer_security_info( UNUSED_ARG(struct proxy_writer *pwr), - UNUSED_ARG(const nn_plist_t *plist)) + UNUSED_ARG(const ddsi_plist_t *plist)) { } inline bool decode_Data( - UNUSED_ARG(const struct q_globals *gv), + UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rsample_info *sampleinfo), UNUSED_ARG(unsigned char *payloadp), UNUSED_ARG(uint32_t payloadsz), @@ -848,7 +848,7 @@ decode_Data( inline bool decode_DataFrag( - UNUSED_ARG(const struct q_globals *gv), + UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rsample_info *sampleinfo), UNUSED_ARG(unsigned char *payloadp), UNUSED_ARG(uint32_t payloadsz), @@ -902,7 +902,7 @@ decode_SecPrefix( inline nn_rtps_msg_state_t decode_rtps_message( UNUSED_ARG(struct thread_state1 * const ts1), - UNUSED_ARG(struct q_globals *gv), + UNUSED_ARG(struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rmsg **rmsg), UNUSED_ARG(Header_t **hdr), UNUSED_ARG(unsigned char **buff), diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h index 61a57e8..4ff9ff0 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h @@ -61,6 +61,9 @@ typedef void (*ddsi_serdata_free_t) (struct ddsi_serdata *d); - FIXME: get the encoding header out of the serialised data */ typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_t) (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size); +/* Exactly like ddsi_serdata_from_ser_t, but with the data in an iovec and guaranteed absence of overlap */ +typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_iov_t) (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size); + /* Construct a serdata from a keyhash (an SDK_KEY by definition) */ typedef struct ddsi_serdata * (*ddsi_serdata_from_keyhash_t) (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash); @@ -141,6 +144,7 @@ struct ddsi_serdata_ops { ddsi_serdata_eqkey_t eqkey; ddsi_serdata_size_t get_size; ddsi_serdata_from_ser_t from_ser; + ddsi_serdata_from_ser_iov_t from_ser_iov; ddsi_serdata_from_keyhash_t from_keyhash; ddsi_serdata_from_sample_t from_sample; ddsi_serdata_to_ser_t to_ser; @@ -155,6 +159,7 @@ struct ddsi_serdata_ops { }; #define DDSI_SERDATA_HAS_PRINT 1 +#define DDSI_SERDATA_HAS_FROM_SER_IOV 1 #define DDSI_SERDATA_HAS_ADD_KEYHASH 1 DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind); @@ -178,6 +183,10 @@ DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_ser (const struct ddsi_ return topic->serdata_ops->from_ser (topic, kind, fragchain, size); } +DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_ser_iov (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) { + return topic->serdata_ops->from_ser_iov (topic, kind, niov, iov, size); +} + DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash) { return topic->serdata_ops->from_keyhash (topic, keyhash); } 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 daa8a7b..0eed3d6 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h @@ -20,7 +20,6 @@ #include "dds/ddsi/ddsi_sertopic.h" #include "dds/dds.h" -#include "dds__topic.h" #if defined (__cplusplus) extern "C" { @@ -96,41 +95,28 @@ struct ddsi_serdata_default { #undef DDSI_SERDATA_DEFAULT_PREPAD #undef DDSI_SERDATA_DEFAULT_FIXED_FIELD -struct dds_key_descriptor; -struct dds_topic_descriptor; - #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 +/* Reduced version of dds_topic_descriptor_t */ +struct ddsi_sertopic_default_desc { + uint32_t m_size; /* Size of topic type */ + uint32_t m_align; /* Alignment of topic type */ + uint32_t m_flagset; /* Flags */ + uint32_t m_nkeys; /* Number of keys (can be 0) */ + uint32_t *m_keys; /* Key descriptors (NULL iff m_nkeys 0) */ + uint32_t m_nops; /* Number of words in m_ops (which >= number of ops stored in preproc output) */ + uint32_t *m_ops; /* Marshalling meta data */ +}; + 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; - - uint32_t flags; + struct ddsi_sertopic_default_desc type; size_t opt_size; - dds_topic_intern_filter_fn filter_fn; - void * filter_sample; - void * filter_ctx; - const struct dds_key_descriptor * keys; - - /* - Array of keys, represented as offset in the OpenSplice internal - format data blob. Keys must be stored in the order visited by - serializer (so that the serializer can simply compare the current - offset with the next key offset). Also: keys[nkeys].off =def= - ~0u, which won't equal any real offset so that there is no need - to test for the end of the array. - - Offsets work 'cos only primitive types, enums and strings are - accepted as keys. So there is no ambiguity if a key happens to - be inside a nested struct. - */ }; struct ddsi_plist_sample { diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h b/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h index e23333c..f259c02 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_sertopic.h @@ -23,17 +23,17 @@ extern "C" { struct ddsi_serdata; struct ddsi_serdata_ops; struct ddsi_sertopic_ops; +struct ddsi_domaingv; struct ddsi_sertopic { 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 */ + struct ddsi_domaingv *gv; + ddsrt_atomic_uint32_t refc; /* counts refs from entities (topic, reader, writer), not from data */ }; /* The old and the new happen to have the same memory layout on a 64-bit machine @@ -48,6 +48,27 @@ struct ddsi_sertopic { binary compatible. */ #define DDSI_SERTOPIC_HAS_TOPICKIND_NO_KEY 1 +/* Type changed: name_type_name and ii removed and gv added; and the set of + operations got extended by the a predicate for testing to sertopics (with the + same "ops") for equality ("equal") as well as a function for hashing the + non-generic part of the sertopic definition (via "hash"). These two operations + make it possible to intern sertopics without duplicates, which has become + relevant now that multiple ddsi_sertopics can be associated with a single topic + name. + + Testing for DDSI_SERTOPIC_HAS_EQUAL_AND_HASH allows one to have a single source + that can handle both variants, but there's no binary compatbility. */ +#define DDSI_SERTOPIC_HAS_EQUAL_AND_HASH 1 + +/* Called to compare two sertopics for equality, if it is already known that name, + type name, topickind_no_Key, and operations are all the same. (serdata_basehash + is computed from the set of operations.) */ +typedef bool (*ddsi_sertopic_equal_t) (const struct ddsi_sertopic *a, const struct ddsi_sertopic *b); + +/* Hash the custom components of a sertopic (this XOR'd with a hash computed from + the fields that are defined in struct ddsi_sertopic) */ +typedef uint32_t (*ddsi_sertopic_hash_t) (const struct ddsi_sertopic *tp); + /* Called when the refcount dropped to zero */ typedef void (*ddsi_sertopic_free_t) (struct ddsi_sertopic *tp); @@ -66,15 +87,22 @@ struct ddsi_sertopic_ops { ddsi_sertopic_zero_samples_t zero_samples; ddsi_sertopic_realloc_samples_t realloc_samples; ddsi_sertopic_free_samples_t free_samples; + ddsi_sertopic_equal_t equal; + ddsi_sertopic_hash_t hash; }; +struct ddsi_sertopic *ddsi_sertopic_lookup_locked (struct ddsi_domaingv *gv, const struct ddsi_sertopic *sertopic_template); +void ddsi_sertopic_register_locked (struct ddsi_domaingv *gv, struct ddsi_sertopic *sertopic); + 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); +DDS_EXPORT bool ddsi_sertopic_equal (const struct ddsi_sertopic *a, const struct ddsi_sertopic *b); +DDS_EXPORT uint32_t ddsi_sertopic_hash (const struct ddsi_sertopic *tp); + DDS_EXPORT inline void ddsi_sertopic_free (struct ddsi_sertopic *tp) { tp->ops->free (tp); } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h b/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h index d6d5eb7..cf92a45 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tcp.h @@ -24,15 +24,15 @@ extern "C" { struct ddsi_ssl_plugins { - bool (*init) (struct q_globals *gv); + bool (*init) (struct ddsi_domaingv *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_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); + SSL * (*connect) (const struct ddsi_domaingv *gv, ddsrt_socket_t sock); BIO * (*listen) (ddsrt_socket_t sock); - SSL * (*accept) (const struct q_globals *gv, BIO *bio, ddsrt_socket_t *sock); + SSL * (*accept) (const struct ddsi_domaingv *gv, BIO *bio, ddsrt_socket_t *sock); }; #if defined (__cplusplus) @@ -45,7 +45,7 @@ struct ddsi_ssl_plugins extern "C" { #endif -int ddsi_tcp_init (struct q_globals *gv); +int ddsi_tcp_init (struct ddsi_domaingv *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 18d5bc7..6014051 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_threadmon.h @@ -17,12 +17,12 @@ extern "C" { #endif struct ddsi_threadmon; -struct q_globals; +struct ddsi_domaingv; 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_register_domain (struct ddsi_threadmon *sl, const struct ddsi_domaingv *gv); +void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct ddsi_domaingv *gv); void ddsi_threadmon_stop (struct ddsi_threadmon *sl); void ddsi_threadmon_free (struct ddsi_threadmon *sl); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h index 3461d63..e29460b 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h @@ -22,7 +22,7 @@ extern "C" { struct ddsi_tkmap; struct ddsi_serdata; struct dds_topic; -struct q_globals; +struct ddsi_domaingv; struct ddsi_tkmap_instance { @@ -31,7 +31,7 @@ struct ddsi_tkmap_instance ddsrt_atomic_uint32_t m_refc; }; -DDS_EXPORT struct ddsi_tkmap *ddsi_tkmap_new (struct q_globals *gv); +DDS_EXPORT struct ddsi_tkmap *ddsi_tkmap_new (struct ddsi_domaingv *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); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h index 488b401..4d7d0e4 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h @@ -78,7 +78,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, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface *interf); +typedef enum ddsi_nearby_address_result (*ddsi_is_nearby_address_fn_t) (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,12 +89,12 @@ enum ddsi_locator_from_string_result { typedef enum ddsi_locator_from_string_result (*ddsi_locator_from_string_fn_t) (ddsi_tran_factory_t tran, nn_locator_t *loc, const char *str); -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 char * (*ddsi_locator_to_string_fn_t) (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, enum transport_selector transport_selector, ddsrt_ifaddrs_t **interfs); /* Data types */ -struct q_globals; +struct ddsi_domaingv; struct ddsi_tran_base { /* Data */ @@ -102,7 +102,7 @@ struct ddsi_tran_base uint32_t m_port; uint32_t m_trantype; bool m_multicast; - struct q_globals *gv; + struct ddsi_domaingv *gv; /* Functions */ @@ -182,7 +182,7 @@ struct ddsi_tran_factory const char *m_default_spdp_address; bool m_connless; bool m_stream; - struct q_globals *gv; + struct ddsi_domaingv *gv; /* Relationships */ @@ -197,11 +197,11 @@ struct ddsi_tran_qos int m_diffserv; }; -void ddsi_tran_factories_fini (struct q_globals *gv); -void ddsi_factory_add (struct q_globals *gv, ddsi_tran_factory_t factory); +void ddsi_tran_factories_fini (struct ddsi_domaingv *gv); +void ddsi_factory_add (struct ddsi_domaingv *gv, ddsi_tran_factory_t factory); void ddsi_factory_free (ddsi_tran_factory_t factory); -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); +ddsi_tran_factory_t ddsi_factory_find (const struct ddsi_domaingv *gv, const char * type); +ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct ddsi_domaingv *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 (const struct ddsi_tran_factory *factory, int32_t kind) { @@ -253,11 +253,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 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); +int ddsi_is_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc); +int ddsi_is_ssm_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc); +enum ddsi_nearby_address_result ddsi_is_nearby_address (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 (const struct q_globals *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory); +enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct ddsi_domaingv *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory); /* 8 for transport/ 1 for [ @@ -270,8 +270,8 @@ enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct q_gl */ #define DDSI_LOCSTRLEN 70 -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); +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); int ddsi_enumerate_interfaces (ddsi_tran_factory_t factory, enum transport_selector transport_selector, ddsrt_ifaddrs_t **interfs); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_udp.h b/src/core/ddsi/include/dds/ddsi/ddsi_udp.h index 888452c..4b58a19 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_udp.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_udp.h @@ -24,7 +24,7 @@ typedef struct nn_udpv4mcgen_address { uint8_t idx; /* must be last: then sorting will put them consecutively */ } nn_udpv4mcgen_address_t; -int ddsi_udp_init (struct q_globals *gv); +int ddsi_udp_init (struct ddsi_domaingv *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_xqos.h b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h similarity index 87% rename from src/core/ddsi/include/dds/ddsi/q_xqos.h rename to src/core/ddsi/include/dds/ddsi/ddsi_xqos.h index bb64519..5227ea4 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xqos.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h @@ -9,8 +9,8 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef NN_XQOS_H -#define NN_XQOS_H +#ifndef DDSI_XQOS_H +#define DDSI_XQOS_H #include "dds/ddsc/dds_public_qosdefs.h" /*XXX*/ @@ -304,35 +304,32 @@ struct dds_qos { struct nn_xmsg; -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); -DDS_EXPORT bool nn_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith, bool check_non_empty); - +DDS_EXPORT void ddsi_xqos_init_empty (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_reader (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_writer (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_writer_noautodispose (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_subscriber (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_publisher (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_init_default_topic (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_copy (dds_qos_t *dst, const dds_qos_t *src); +DDS_EXPORT void ddsi_xqos_unalias (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_fini (dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask); +DDS_EXPORT dds_return_t ddsi_xqos_valid (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); +DDS_EXPORT void ddsi_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask); +DDS_EXPORT uint64_t ddsi_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint64_t mask); +DDS_EXPORT void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted); +DDS_EXPORT void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); +DDS_EXPORT size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos); +DDS_EXPORT dds_qos_t *ddsi_xqos_dup (const dds_qos_t *src); +DDS_EXPORT bool ddsi_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith, bool check_non_empty); #ifdef DDSI_INCLUDE_SECURITY - - - struct omg_security_configuration_type; -DDS_EXPORT void nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg); +DDS_EXPORT void ddsi_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg); #endif #if defined (__cplusplus) } #endif -#endif /* NN_XQOS_H */ +#endif /* DDSI_XQOS_H */ diff --git a/src/core/ddsi/include/dds/ddsi/q_addrset.h b/src/core/ddsi/include/dds/ddsi/q_addrset.h index 669061f..2ded8b9 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 (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); +void add_to_addrset (const struct ddsi_domaingv *gv, struct addrset *as, const nn_locator_t *loc); +void remove_from_addrset (const struct ddsi_domaingv *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 (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); +void copy_addrset_into_addrset_uc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset_mc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset (const struct ddsi_domaingv *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 (struct q_globals *gv, uint32_t tf, const char *prefix, const struct addrset *as); +void nn_log_addrset (struct ddsi_domaingv *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); -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); +struct ddsi_domaingv; +int add_addresses_to_addrset (const struct ddsi_domaingv *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 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); +int addrset_contains_ssm (const struct ddsi_domaingv *gv, const struct addrset *as); +int addrset_any_ssm (const struct ddsi_domaingv *gv, const struct addrset *as, nn_locator_t *dst); +int addrset_any_non_ssm_mc (const struct ddsi_domaingv *gv, const struct addrset *as, nn_locator_t *dst); +void copy_addrset_into_addrset_no_ssm_mc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd); +void copy_addrset_into_addrset_no_ssm (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd); #endif #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 d2162b4..16c8149 100644 --- a/src/core/ddsi/include/dds/ddsi/q_config.h +++ b/src/core/ddsi/include/dds/ddsi/q_config.h @@ -14,7 +14,7 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_thread.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/ddsi_portmapping.h" @@ -253,7 +253,7 @@ struct config int64_t liveliness_monitoring_interval; int prioritize_retransmit; int xpack_send_async; - int multiple_recv_threads; + enum boolean_default multiple_recv_threads; unsigned recv_thread_stop_maxretries; unsigned primary_reorder_maxsamples; 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 9077d98..c5c801e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h +++ b/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h @@ -23,7 +23,7 @@ struct writer; struct reader; struct nn_rsample_info; struct nn_rdata; -struct nn_plist; +struct ddsi_plist; int spdp_write (struct participant *pp); int spdp_dispose_unregister (struct participant *pp); @@ -33,8 +33,7 @@ int sedp_write_reader (struct reader *rd); int sedp_dispose_unregister_writer (struct writer *wr); 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_topic (struct participant *pp, const struct ddsi_plist *datap); int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_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 5f5ac06..3596f77 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 (struct q_globals *gv, int32_t port); +struct debug_monitor *new_debug_monitor (struct ddsi_domaingv *gv, int32_t 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 d769c12..3623888 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -18,9 +18,8 @@ #include "dds/ddsrt/fibheap.h" #include "dds/ddsrt/sync.h" #include "dds/ddsi/q_rtps.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_protocol.h" -#include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_lat_estim.h" #include "dds/ddsi/q_hbcontrol.h" #include "dds/ddsi/q_feature_check.h" @@ -44,7 +43,7 @@ struct addrset; struct ddsi_sertopic; struct whc; struct dds_qos; -struct nn_plist; +struct ddsi_plist; struct lease; struct proxy_group; @@ -68,8 +67,7 @@ enum liveliness_changed_data_extra { LIVELINESS_CHANGED_REMOVE_NOT_ALIVE, LIVELINESS_CHANGED_REMOVE_ALIVE, LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE, - LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE, - LIVELINESS_CHANGED_TWITCH + LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE }; typedef struct status_cb_data @@ -106,6 +104,8 @@ struct wr_rd_match { struct rd_wr_match { ddsrt_avl_node_t avlnode; ddsi_guid_t wr_guid; + unsigned wr_alive: 1; /* tracks wr's alive state */ + uint32_t wr_alive_vclock; /* used to ensure progress */ }; struct wr_prd_match { @@ -171,7 +171,7 @@ struct entity_common { struct ddsi_tkmap_instance *tk; ddsrt_mutex_t lock; bool onlylocal; - struct q_globals *gv; + struct ddsi_domaingv *gv; ddsrt_avl_node_t all_entities_avlnode; /* QoS changes always lock the entity itself, and additionally @@ -191,7 +191,7 @@ struct local_reader_ary { 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") */ uint32_t n_readers; - struct reader **rdary; /* for efficient delivery, null-pointer terminated */ + struct reader **rdary; /* for efficient delivery, null-pointer terminated, grouped by topic */ }; struct avail_entityid_set { @@ -203,9 +203,8 @@ struct participant struct entity_common e; 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 ddsi_plist *plist; /* settings/QoS for this participant */ struct xevent *spdp_xevent; /* timed event for periodically publishing SPDP */ struct xevent *pmd_update_xevent; /* timed event for periodically publishing ParticipantMessageData */ nn_locator_t m_locator; @@ -216,6 +215,8 @@ struct participant int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */ int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */ ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */ + ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness writer's lease */ + ddsrt_fibheap_t leaseheap_man; /* keeps leases for this participant's writers (with liveliness manual-by-participant) */ #ifdef DDSI_INCLUDE_SECURITY int64_t local_identity_handle; /* OMG DDS Security related member */ int64_t permissions_handle; /* OMG DDS Security related member */ @@ -254,7 +255,7 @@ struct writer struct endpoint_common c; status_cb_t status_cb; void * status_cb_entity; - ddsrt_cond_t throttle_cond; /* used to trigger a transmit thread blocked in throttle_writer() */ + ddsrt_cond_t throttle_cond; /* used to trigger a transmit thread blocked in throttle_writer() or wait_for_acks() */ seqno_t seq; /* last sequence number (transmitted seqs are 1 ... seq) */ seqno_t cs_seq; /* 1st seq in coherent set (or 0) */ seq_xmit_t seq_xmit; /* last sequence number actually transmitted */ @@ -270,10 +271,12 @@ struct writer unsigned include_keyhash: 1; /* iff 1, this writer includes a keyhash; keyless topics => include_keyhash = 0 */ unsigned force_md5_keyhash: 1; /* iff 1, when keyhash has to be hashed, no matter the size */ unsigned retransmitting: 1; /* iff 1, this writer is currently retransmitting */ + unsigned alive: 1; /* iff 1, the writer is alive (lease for this writer is not expired); field may be modified only when holding both wr->e.lock and wr->c.pp->e.lock */ #ifdef DDSI_INCLUDE_SSM unsigned supports_ssm: 1; struct addrset *ssm_as; #endif + uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */ const struct ddsi_sertopic * topic; /* topic, but may be NULL for built-ins */ 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 */ @@ -297,6 +300,7 @@ struct writer uint32_t rexmit_lost_count; /* cum samples lost but retransmit requested (also counting events) */ struct xeventq *evq; /* timed event queue to be used by this writer */ struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */ + struct lease *lease; /* for liveliness administration (writer can only become inactive when using manual liveliness) */ }; inline seqno_t writer_read_seq_xmit (const struct writer *wr) { @@ -343,7 +347,7 @@ struct proxy_participant unsigned bes; /* built-in endpoint set */ unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */ ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */ - struct nn_plist *plist; /* settings/QoS for this participant */ + struct ddsi_plist *plist; /* settings/QoS for this participant */ ddsrt_atomic_voidp_t minl_auto; /* lease object for shortest automatic liveliness pwr's lease (includes this proxypp's lease) */ ddsrt_fibheap_t leaseheap_auto; /* keeps leases for this proxypp and leases for pwrs (with liveliness automatic) */ ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness pwr's lease */ @@ -361,7 +365,6 @@ struct proxy_participant unsigned lease_expired: 1; unsigned deleting: 1; unsigned proxypp_have_spdp: 1; - unsigned proxypp_have_cm: 1; unsigned owns_lease: 1; #ifdef DDSI_INCLUDE_SECURITY int64_t remote_identity_handle; /* OMG DDS Security related member */ @@ -450,12 +453,12 @@ struct proxy_reader { filter_fn_t filter; }; -extern const ddsrt_avl_treedef_t wr_readers_treedef; -extern const ddsrt_avl_treedef_t wr_local_readers_treedef; -extern const ddsrt_avl_treedef_t rd_writers_treedef; -extern const ddsrt_avl_treedef_t rd_local_writers_treedef; -extern const ddsrt_avl_treedef_t pwr_readers_treedef; -extern const ddsrt_avl_treedef_t prd_writers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t wr_readers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t wr_local_readers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t rd_writers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t rd_local_writers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t pwr_readers_treedef; +DDS_EXPORT extern const ddsrt_avl_treedef_t prd_writers_treedef; extern const ddsrt_avl_treedef_t deleted_participants_treedef; #define DPG_LOCAL 1 @@ -553,7 +556,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e); * @retval DDS_RETCODE_OUT_OF_RESOURCES * The configured maximum number of participants has been reached. */ -dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist); +dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); /** * @brief Create a new participant in the domain. See also new_participant_guid. @@ -577,7 +580,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * * @retval DDS_RETCODE_OUT_OF_RESOURCES * The configured maximum number of participants has been reached. */ -dds_return_t new_participant (struct ddsi_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist); +dds_return_t new_participant (struct ddsi_guid *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); /** * @brief Initiate the deletion of the participant: @@ -603,9 +606,9 @@ dds_return_t new_participant (struct ddsi_guid *ppguid, struct q_globals *gv, un * @retval DDS_RETCODE_BAD_PARAMETER * ppguid lookup failed. */ -dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_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 ddsi_guid *guid); +dds_return_t delete_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid); +void update_participant_plist (struct participant *pp, const struct ddsi_plist *plist); +uint64_t get_entity_instance_id (const struct ddsi_domaingv *gv, const struct ddsi_guid *guid); /* Gets the interval for PMD messages, which is the minimal lease duration for writers with auto liveliness in this participant, or the participants lease duration if shorter */ @@ -620,9 +623,9 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi GUID "ppguid". May return NULL if participant unknown or writer/reader already known. */ -dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_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_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_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_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_reader (struct reader **rd_out, struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_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); @@ -634,20 +637,24 @@ seqno_t writer_max_drop_seq (const struct writer *wr); int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_state *whcst); void writer_set_retransmitting (struct writer *wr); void writer_clear_retransmitting (struct writer *wr); +dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout); -dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid); -dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid); -dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid); +dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); +dds_return_t delete_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); +dds_return_t delete_writer_nolinger (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); dds_return_t delete_writer_nolinger_locked (struct writer *wr); -dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid); +dds_return_t delete_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); struct local_orphan_writer { struct writer wr; }; -struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc); +struct local_orphan_writer *new_local_orphan_writer (struct ddsi_domaingv *gv, ddsi_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); +void writer_set_alive_may_unlock (struct writer *wr, bool notify); +int writer_set_notalive (struct writer *wr, bool notify); + /* To create or delete a new proxy participant: "guid" MUST have the pre-defined participant entity id. Unlike delete_participant(), deleting a proxy participant will automatically delete all its @@ -672,25 +679,20 @@ 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 (struct q_globals *gv, const struct ddsi_guid *guid, unsigned bes, unsigned prismtech_bes, const struct ddsi_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 ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit); +void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct ddsi_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 ddsi_domaingv *gv, const struct ddsi_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, 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); +int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, nn_wctime_t timestamp); +int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, nn_wctime_t timestamp); void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease); -void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc); +void purge_proxy_participants (struct ddsi_domaingv *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 (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_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 ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq + int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct ddsi_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq); +int new_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct ddsi_plist *plist, nn_wctime_t timestamp, seqno_t seq #ifdef DDSI_INCLUDE_SSM , int favours_ssm #endif @@ -701,15 +703,14 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons 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 (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit); -int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit); +int delete_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit); +int delete_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit); 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); void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify); int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify); -void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify); int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp); @@ -718,7 +719,7 @@ void delete_proxy_group (struct entity_index *entidx, const struct ddsi_guid *gu /* 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(struct q_globals *gv, int rebuild); +void rebuild_or_clear_writer_addrsets(struct ddsi_domaingv *gv, int rebuild); void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok); diff --git a/src/core/ddsi/include/dds/ddsi/q_freelist.h b/src/core/ddsi/include/dds/ddsi/q_freelist.h index 75b4fc0..84cc3e5 100644 --- a/src/core/ddsi/include/dds/ddsi/q_freelist.h +++ b/src/core/ddsi/include/dds/ddsi/q_freelist.h @@ -25,11 +25,11 @@ extern "C" { #define FREELIST_TYPE FREELIST_DOUBLE -#if 0 -#if HAVE_ATOMIC_LIFO +#ifndef FREELIST_TYPE +#if DDSRT_HAVE_ATOMIC_LIFO #define FREELIST_TYPE FREELIST_ATOMIC_LIFO #else -#define FREELIST_TYPE FREELIST_SIMPLE +#define FREELIST_TYPE FREELIST_DOUBLE #endif #endif @@ -45,7 +45,7 @@ struct nn_freelist { ddsrt_atomic_lifo_t x; ddsrt_atomic_uint32_t count; uint32_t max; - off_t linkoff; + size_t linkoff; }; #elif FREELIST_TYPE == FREELIST_DOUBLE @@ -73,12 +73,12 @@ struct nn_freelist { struct nn_freelistM *emlist; uint32_t count; uint32_t max; - off_t linkoff; + size_t linkoff; }; #endif -void nn_freelist_init (struct nn_freelist *fl, uint32_t max, off_t linkoff); +void nn_freelist_init (struct nn_freelist *fl, uint32_t max, size_t linkoff); void nn_freelist_fini (struct nn_freelist *fl, void (*free) (void *elem)); bool nn_freelist_push (struct nn_freelist *fl, void *elem); void *nn_freelist_pushmany (struct nn_freelist *fl, void *first, void *last, uint32_t n); diff --git a/src/core/ddsi/include/dds/ddsi/q_gc.h b/src/core/ddsi/include/dds/ddsi/q_gc.h index 2b02bd3..ffb2e11 100644 --- a/src/core/ddsi/include/dds/ddsi/q_gc.h +++ b/src/core/ddsi/include/dds/ddsi/q_gc.h @@ -21,7 +21,7 @@ extern "C" { struct gcreq; struct gcreq_queue; -struct q_globals; +struct ddsi_domaingv; struct writer; struct reader; @@ -44,7 +44,7 @@ struct gcreq { struct idx_vtime vtimes[]; }; -DDS_EXPORT struct gcreq_queue *gcreq_queue_new (struct q_globals *gv); +DDS_EXPORT struct gcreq_queue *gcreq_queue_new (struct ddsi_domaingv *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_init.h b/src/core/ddsi/include/dds/ddsi/q_init.h index 73f3548..32010f9 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 (struct q_globals *gv); -int joinleave_spdp_defmcip (struct q_globals *gv, int dojoin); +int create_multicast_sockets (struct ddsi_domaingv *gv); +int joinleave_spdp_defmcip (struct ddsi_domaingv *gv, int dojoin); #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 51a00cb..b6c5f5c 100644 --- a/src/core/ddsi/include/dds/ddsi/q_lease.h +++ b/src/core/ddsi/include/dds/ddsi/q_lease.h @@ -24,7 +24,7 @@ extern "C" { struct receiver_state; struct participant; struct entity_common; -struct q_globals; /* FIXME: make a special for the lease admin */ +struct ddsi_domaingv; /* FIXME: make a special for the lease admin */ struct lease { ddsrt_fibheap_node_t heapnode; @@ -37,8 +37,8 @@ struct lease { int compare_lease_tsched (const void *va, const void *vb); int compare_lease_tdur (const void *va, const void *vb); -void lease_management_init (struct q_globals *gv); -void lease_management_term (struct q_globals *gv); +void lease_management_init (struct ddsi_domaingv *gv); +void lease_management_term (struct ddsi_domaingv *gv); struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e); struct lease *lease_clone (const struct lease *l); void lease_register (struct lease *l); @@ -46,7 +46,7 @@ void lease_unregister (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 (struct q_globals *gv, nn_etime_t tnow); +int64_t check_and_handle_lease_expiration (struct ddsi_domaingv *gv, nn_etime_t tnow); #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 e69a5a7..7e4688c 100644 --- a/src/core/ddsi/include/dds/ddsi/q_nwif.h +++ b/src/core/ddsi/include/dds/ddsi/q_nwif.h @@ -22,7 +22,7 @@ extern "C" { #endif -struct q_globals; +struct ddsi_domaingv; #define MAX_INTERFACES 128 struct nn_interface { @@ -35,8 +35,8 @@ struct nn_interface { char *name; }; -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); +int make_socket (ddsrt_socket_t *socket, uint16_t port, bool stream, bool reuse, const struct ddsi_domaingv *gv); +int find_own_ip (struct ddsi_domaingv *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 09836c8..94f7d22 100644 --- a/src/core/ddsi/include/dds/ddsi/q_pcap.h +++ b/src/core/ddsi/include/dds/ddsi/q_pcap.h @@ -23,8 +23,8 @@ struct msghdr; FILE * new_pcap_file (const struct ddsrt_log_cfg *logcfg, const char *name); -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, +void write_pcap_received (struct ddsi_domaingv *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 ddsi_domaingv *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_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h index c580729..1ffb559 100644 --- a/src/core/ddsi/include/dds/ddsi/q_protocol.h +++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h @@ -58,9 +58,9 @@ typedef struct nn_fragment_number_set_header { typedef int32_t nn_count_t; #define DDSI_COUNT_MIN (-2147483647 - 1) #define DDSI_COUNT_MAX (2147483647) -/* address field in locator maintained in network byte order, the rest - in host (yes: that's a FIXME) */ +/* address field in locator maintained in network byte order, the rest in host */ typedef struct { + const struct ddsi_tran_factory *tran; int32_t kind; uint32_t port; unsigned char address[16]; diff --git a/src/core/ddsi/include/dds/ddsi/q_radmin.h b/src/core/ddsi/include/dds/ddsi/q_radmin.h index 4cf7b9a..a7df7e4 100644 --- a/src/core/ddsi/include/dds/ddsi/q_radmin.h +++ b/src/core/ddsi/include/dds/ddsi/q_radmin.h @@ -112,7 +112,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 ddsi_domaingv *gv; }; struct nn_rsample_info { @@ -233,7 +233,7 @@ unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t m seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder); void nn_reorder_set_next_seq (struct nn_reorder *reorder, seqno_t seq); -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 *nn_dqueue_new (const char *name, const struct ddsi_domaingv *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 0c8650d..bc6942e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_receive.h +++ b/src/core/ddsi/include/dds/ddsi/q_receive.h @@ -32,10 +32,10 @@ struct nn_gap_info { }; void nn_gap_info_init(struct nn_gap_info *gi); -void nn_gap_info_update(struct q_globals *gv, struct nn_gap_info *gi, int64_t seqnr); +void nn_gap_info_update(struct ddsi_domaingv *gv, struct nn_gap_info *gi, int64_t seqnr); struct nn_xmsg * nn_gap_info_create_gap(struct writer *wr, struct proxy_reader *prd, struct nn_gap_info *gi); -void trigger_recv_threads (const struct q_globals *gv); +void trigger_recv_threads (const struct ddsi_domaingv *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 ddsi_guid_t *rdguid, void *qarg); diff --git a/src/core/ddsi/include/dds/ddsi/q_rtps.h b/src/core/ddsi/include/dds/ddsi/q_rtps.h index a980cb6..56b0083 100644 --- a/src/core/ddsi/include/dds/ddsi/q_rtps.h +++ b/src/core/ddsi/include/dds/ddsi/q_rtps.h @@ -58,12 +58,6 @@ typedef int64_t seqno_t; #define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER 0xff0101c2 #define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER 0xff0101c7 -#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER 0x142 -#define NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER 0x147 -#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER 0x242 -#define NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER 0x247 -#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER 0x342 -#define NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER 0x347 #define NN_ENTITYID_SOURCE_MASK 0xc0 #define NN_ENTITYID_SOURCE_USER 0x00 #define NN_ENTITYID_SOURCE_BUILTIN 0xc0 @@ -78,13 +72,13 @@ typedef int64_t seqno_t; #define NN_ENTITYID_ALLOCSTEP 0x100 struct cfgst; -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); +struct ddsi_domaingv; +int rtps_config_prep (struct ddsi_domaingv *config, struct cfgst *cfgst); +int rtps_config_open_trace (struct ddsi_domaingv *config); +int rtps_init (struct ddsi_domaingv *config); +int rtps_start (struct ddsi_domaingv *config); +void rtps_stop (struct ddsi_domaingv *config); +void rtps_fini (struct ddsi_domaingv *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 e1703f9..c899ee1 100644 --- a/src/core/ddsi/include/dds/ddsi/q_thread.h +++ b/src/core/ddsi/include/dds/ddsi/q_thread.h @@ -54,7 +54,7 @@ enum thread_state { THREAD_STATE_ALIVE /* known to be alive - for Cyclone internal threads */ }; -struct q_globals; +struct ddsi_domaingv; struct config; struct ddsrt_log_cfg; @@ -103,10 +103,10 @@ DDS_EXPORT bool thread_states_fini (void); 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 dds_return_t create_thread (struct thread_state1 **ts, const struct ddsi_domaingv *gv, const char *name, uint32_t (*f) (void *arg), void *arg); DDS_EXPORT struct thread_state1 *lookup_thread_state_real (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 log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct ddsi_domaingv *gv); DDS_EXPORT void reset_thread_state (struct thread_state1 *ts1); DDS_EXPORT int thread_exists (const char *name); @@ -161,13 +161,13 @@ DDS_EXPORT inline void thread_state_asleep (struct thread_state1 *ts1) ddsrt_atomic_st32 (&ts1->vtime, vt); } -DDS_EXPORT inline void thread_state_awake (struct thread_state1 *ts1, const struct q_globals *gv) +DDS_EXPORT inline void thread_state_awake (struct thread_state1 *ts1, const struct ddsi_domaingv *gv) { vtime_t vt = ddsrt_atomic_ld32 (&ts1->vtime); assert ((vt & VTIME_NEST_MASK) < VTIME_NEST_MASK); 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_stvoidp (&ts1->gv, (struct ddsi_domaingv *) gv); ddsrt_atomic_fence_stst (); ddsrt_atomic_st32 (&ts1->vtime, vt + 1u); /* nested calls a rare and an extra fence doesn't break things */ diff --git a/src/core/ddsi/include/dds/ddsi/q_transmit.h b/src/core/ddsi/include/dds/ddsi/q_transmit.h index f3df9f3..62feeda 100644 --- a/src/core/ddsi/include/dds/ddsi/q_transmit.h +++ b/src/core/ddsi/include/dds/ddsi/q_transmit.h @@ -40,11 +40,11 @@ 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 */ -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); +dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct ddsi_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 ddsi_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, int hbliveliness, ddsi_entityid_t dst, int issync); -dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp); -int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd); +dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp); +int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_whc.h b/src/core/ddsi/include/dds/ddsi/q_whc.h index b726f52..40622a8 100644 --- a/src/core/ddsi/include/dds/ddsi/q_whc.h +++ b/src/core/ddsi/include/dds/ddsi/q_whc.h @@ -20,7 +20,7 @@ extern "C" { #endif struct ddsi_serdata; -struct nn_plist; +struct ddsi_plist; struct ddsi_tkmap_instance; struct whc_node; /* opaque, but currently used for deferred free lists */ struct whc; @@ -28,7 +28,7 @@ struct whc; struct whc_borrowed_sample { seqno_t seq; struct ddsi_serdata *serdata; - struct nn_plist *plist; + struct ddsi_plist *plist; bool unacked; nn_mtime_t last_rexmit_ts; unsigned rexmit_count; @@ -73,7 +73,7 @@ typedef void (*whc_free_t)(struct whc *whc); reliable readers that have not acknowledged all data */ /* 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, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); +typedef int (*whc_insert_t)(struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); 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); @@ -121,7 +121,7 @@ inline bool whc_sample_iter_borrow_next (struct whc_sample_iter *it, struct whc_ inline void whc_free (struct whc *whc) { whc->ops->free (whc); } -inline int whc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { +inline int whc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { return whc->ops->insert (whc, max_drop_seq, seq, exp, plist, serdata, tk); } inline unsigned whc_downgrade_to_volatile (struct whc *whc, struct whc_state *st) { diff --git a/src/core/ddsi/include/dds/ddsi/q_xmsg.h b/src/core/ddsi/include/dds/ddsi/q_xmsg.h index eb99196..e82a81d 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xmsg.h +++ b/src/core/ddsi/include/dds/ddsi/q_xmsg.h @@ -15,7 +15,7 @@ #include #include "dds/ddsi/q_protocol.h" /* for, e.g., SubmessageKind_t */ -#include "dds/ddsi/q_xqos.h" /* for, e.g., octetseq, stringseq */ +#include "dds/ddsi/ddsi_xqos.h" /* for, e.g., octetseq, stringseq */ #include "dds/ddsi/ddsi_tran.h" #if defined (__cplusplus) @@ -59,7 +59,7 @@ void nn_xmsgpool_free (struct nn_xmsgpool *pool); struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_t *src_guid, struct participant *pp, size_t expected_size, enum nn_xmsg_kind kind); /* For sending to a particular destination (participant) */ -void nn_xmsg_setdst1 (struct q_globals *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr); +void nn_xmsg_setdst1 (struct ddsi_domaingv *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr); bool nn_xmsg_getdst1prefix (struct nn_xmsg *m, ddsi_guid_prefix_t *gp); /* For sending to a particular proxy reader; this is a convenience @@ -95,7 +95,7 @@ void nn_xmsg_set_data_readerId (struct nn_xmsg *m, ddsi_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 q_globals *gv, struct nn_xmsg *m, const struct nn_xmsg *madd); +int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct ddsi_domaingv *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 @@ -144,10 +144,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 (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); +void nn_xpack_sendq_init (struct ddsi_domaingv *gv); +void nn_xpack_sendq_start (struct ddsi_domaingv *gv); +void nn_xpack_sendq_stop (struct ddsi_domaingv *gv); +void nn_xpack_sendq_fini (struct ddsi_domaingv *gv); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds_stream.c b/src/core/ddsi/src/ddsi_cdrstream.c similarity index 85% rename from src/core/ddsc/src/dds_stream.c rename to src/core/ddsi/src/ddsi_cdrstream.c index 24e3866..3565d45 100644 --- a/src/core/ddsc/src/dds_stream.c +++ b/src/core/ddsi/src/ddsi_cdrstream.c @@ -18,7 +18,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds__alloc.h" #if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN @@ -210,7 +210,7 @@ static uint32_t get_type_size (enum dds_stream_typecode type) return (uint32_t)1 << ((uint32_t) type - 1); } -static size_t dds_stream_check_optimize1 (const dds_topic_descriptor_t * __restrict desc) +static size_t dds_stream_check_optimize1 (const struct ddsi_sertopic_default_desc * __restrict desc) { const uint32_t *ops = desc->m_ops; uint32_t insn; @@ -251,11 +251,141 @@ static size_t dds_stream_check_optimize1 (const dds_topic_descriptor_t * __restr return desc->m_size; } -size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc) +size_t dds_stream_check_optimize (const struct ddsi_sertopic_default_desc * __restrict desc) { return dds_stream_check_optimize1 (desc); } +static void dds_stream_countops1 (const uint32_t * __restrict ops, const uint32_t **ops_end); + +static const uint32_t *dds_stream_countops_seq (const uint32_t * __restrict ops, uint32_t insn, const uint32_t **ops_end) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + switch (subtype) + { + 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: + ops += 2; + break; + case DDS_OP_VAL_BST: + ops += 3; + break; + 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]); + if (ops + 4 > *ops_end) + *ops_end = ops + 4; + dds_stream_countops1 (jsr_ops, ops_end); + ops += (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */ + } + } + if (ops > *ops_end) + *ops_end = ops; + return ops; +} + +static const uint32_t *dds_stream_countops_arr (const uint32_t * __restrict ops, uint32_t insn, const uint32_t **ops_end) +{ + const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn); + switch (subtype) + { + 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: + ops += 3; + break; + case DDS_OP_VAL_BST: + 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 jmp = DDS_OP_ADR_JMP (ops[3]); + const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); + if (ops + 5 > *ops_end) + *ops_end = ops + 5; + dds_stream_countops1 (jsr_ops, ops_end); + ops += (jmp ? jmp : 5); + break; + } + } + if (ops > *ops_end) + *ops_end = ops; + return ops; +} + +static const uint32_t *dds_stream_countops_uni (const uint32_t * __restrict ops, const uint32_t **ops_end) +{ + const uint32_t numcases = ops[2]; + const uint32_t *jeq_op = ops + DDS_OP_ADR_JSR (ops[3]); + for (uint32_t i = 0; i < numcases; i++) + { + const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]); + switch (valtype) + { + 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: + 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_countops1 (jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), ops_end); + break; + } + jeq_op += 3; + } + if (jeq_op > *ops_end) + *ops_end = jeq_op; + ops += DDS_OP_ADR_JMP (ops[3]); + if (ops > *ops_end) + *ops_end = ops; + return ops; +} + +static void dds_stream_countops1 (const uint32_t * __restrict ops, const uint32_t **ops_end) +{ + 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: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: + ops += 2; + break; + case DDS_OP_VAL_BST: + ops += 3; + break; + case DDS_OP_VAL_SEQ: ops = dds_stream_countops_seq (ops, insn, ops_end); break; + case DDS_OP_VAL_ARR: ops = dds_stream_countops_arr (ops, insn, ops_end); break; + case DDS_OP_VAL_UNI: ops = dds_stream_countops_uni (ops, ops_end); break; + case DDS_OP_VAL_STU: abort (); break; + } + break; + } + case DDS_OP_JSR: { + dds_stream_countops1 (ops + DDS_OP_JUMP (insn), ops_end); + ops++; + break; + } + case DDS_OP_RTS: case DDS_OP_JEQ: { + abort (); + break; + } + } + } + ++ops; /* skip RTS op */ + if (ops > *ops_end) + *ops_end = ops; +} + +uint32_t dds_stream_countops (const uint32_t * __restrict ops) +{ + const uint32_t *ops_end = ops; + dds_stream_countops1 (ops, &ops_end); + return (uint32_t) (ops_end - ops); +} + static void dds_stream_reuse_string_bound (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound) { const uint32_t length = dds_is_get4 (is); @@ -1039,12 +1169,12 @@ static bool stream_normalize (char * __restrict data, uint32_t * __restrict off, return true; } -static bool stream_normalize_key (void * __restrict data, uint32_t size, bool bswap, const struct dds_topic_descriptor * __restrict desc) +static bool stream_normalize_key (void * __restrict data, uint32_t size, bool bswap, const struct ddsi_sertopic_default_desc * __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; + const uint32_t *op = desc->m_ops + desc->m_keys[i]; assert (insn_key_ok_p (*op)); switch (DDS_OP_TYPE (*op)) { @@ -1068,14 +1198,211 @@ bool dds_stream_normalize (void * __restrict data, uint32_t size, bool bswap, co if (size > CDR_SIZE_MAX) return false; if (just_key) - return stream_normalize_key (data, size, bswap, topic->type); + 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); + return stream_normalize (data, &off, size, bswap, topic->type.m_ops); } } +/******************************************************************************************* + ** + ** Freeing samples + ** + *******************************************************************************************/ + +//#define OP_DEBUG_FREE 1 +void dds_stream_free_sample (void *vdata, const uint32_t * ops) +{ +#if defined OP_DEBUG_FREE + static const char *stream_op_type[11] = { + NULL, "1Byte", "2Byte", "4Byte", "8Byte", "String", "BString", "Sequence", "Array", "Union", "Struct" + }; +#endif + char *data = vdata; + uint32_t op; + uint32_t type; + uint32_t num; + uint32_t subtype; + char *addr; + while ((op = *ops) != DDS_OP_RTS) + { + switch (DDS_OP_MASK & op) + { + case DDS_OP_ADR: + { + type = DDS_OP_TYPE (op); +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-ADR: %s offset %d\n", stream_op_type[type], ops[1]); +#endif + addr = data + ops[1]; + switch (type) + { + case DDS_OP_VAL_1BY: + case DDS_OP_VAL_2BY: + case DDS_OP_VAL_4BY: + case DDS_OP_VAL_8BY: + ops += 2; + break; + case DDS_OP_VAL_STR: +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-STR: @ %p %s\n", addr, *((char **) addr)); +#endif + ops += 2; + dds_free (*((char **) addr)); + *((char **) addr) = NULL; + break; + case DDS_OP_VAL_SEQ: { + dds_sequence_t * seq = (dds_sequence_t *) addr; + ops += 2; + subtype = DDS_OP_SUBTYPE (op); + num = (seq->_maximum > seq->_length) ? seq->_maximum : seq->_length; +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-SEQ: of %s\n", stream_op_type[subtype]); +#endif + if ((seq->_release && 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: + break; + case DDS_OP_VAL_BST: + ops++; + break; + case DDS_OP_VAL_STR: { + char **ptr = (char **) seq->_buffer; + while (num--) + dds_free (*ptr++); + 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_free_sample (ptr, jsr_ops); + ptr += elem_size; + } + ops += jmp ? (jmp - 3) : 1; + break; + } + } + } + if (seq->_release) + { + dds_free (seq->_buffer); + seq->_maximum = 0; + seq->_length = 0; + seq->_buffer = NULL; + } + break; + } + case DDS_OP_VAL_ARR: { + ops += 2; + subtype = DDS_OP_SUBTYPE (op); + num = *ops++; +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-ARR: of %s size %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: + break; + case DDS_OP_VAL_STR: { + char **ptr = (char **) addr; + while (num--) + dds_free (*ptr++); + break; + } + case DDS_OP_VAL_BST: + 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_free_sample (addr, jsr_ops); + addr += elem_size; + } + ops += jmp ? (jmp - 3) : 2; + break; + } + } + break; + } + case DDS_OP_VAL_UNI: { +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-UNI: switch %s\n", stream_op_type[subtype]); +#endif + /* Get discriminant */ + uint32_t disc = 0; + switch (DDS_OP_SUBTYPE (op)) + { + case DDS_OP_VAL_1BY: disc = *((uint8_t *) addr); break; + case DDS_OP_VAL_2BY: disc = *((uint16_t *) addr); break; + case DDS_OP_VAL_4BY: disc = *((uint32_t *) addr); break; + default: assert (0); + } + uint32_t const * const jeq_op = find_union_case (ops, disc); + ops += DDS_OP_ADR_JMP (ops[3]); + if (jeq_op) + { + subtype = DDS_JEQ_TYPE (jeq_op[0]); + addr = data + jeq_op[2]; + switch (subtype) + { + case DDS_OP_VAL_1BY: + case DDS_OP_VAL_2BY: + case DDS_OP_VAL_4BY: + case DDS_OP_VAL_8BY: + case DDS_OP_VAL_BST: + break; + case DDS_OP_VAL_STR: + dds_free (*((char **) addr)); + *((char **) addr) = NULL; + break; + default: + dds_stream_free_sample (addr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0])); + break; + } + } + break; + } + case DDS_OP_VAL_BST: + ops += 3; + break; + default: + assert (0); + } + break; + } + case DDS_OP_JSR: /* Implies nested type */ +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-JSR: %d\n", DDS_OP_JUMP (op)); +#endif + dds_stream_free_sample (data, ops + DDS_OP_JUMP (op)); + ops++; + break; + default: + assert (0); + } + } +#ifdef OP_DEBUG_FREE + DDS_TRACE("F-RTS:\n"); +#endif +} + /******************************************************************************************* ** ** Read/write of samples and keys -- i.e., DDSI payloads. @@ -1084,7 +1411,7 @@ bool dds_stream_normalize (void * __restrict data, uint32_t size, bool bswap, co 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; + const struct ddsi_sertopic_default_desc *desc = &topic->type; if (topic->opt_size) dds_is_get_bytes (is, data, desc->m_size, 1); else @@ -1097,7 +1424,7 @@ void dds_stream_read_sample (dds_istream_t * __restrict is, void * __restrict da 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); + dds_stream_free_sample (data, desc->m_ops); memset (data, 0, desc->m_size); } dds_stream_read (is, data, desc->m_ops); @@ -1106,7 +1433,7 @@ void dds_stream_read_sample (dds_istream_t * __restrict is, void * __restrict da 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; + const struct ddsi_sertopic_default_desc *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 @@ -1115,10 +1442,10 @@ void dds_stream_write_sample (dds_ostream_t * __restrict os, const void * __rest 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; + const struct ddsi_sertopic_default_desc *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; + const uint32_t *op = desc->m_ops + desc->m_keys[i]; char *dst = sample + op[1]; assert (insn_key_ok_p (*op)); switch (DDS_OP_TYPE (*op)) @@ -1141,10 +1468,10 @@ void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sampl 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; + const struct ddsi_sertopic_default_desc *desc = &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 uint32_t *insnp = desc->m_ops + desc->m_keys[i]; const void *src = sample + insnp[1]; assert (insn_key_ok_p (*insnp)); switch (DDS_OP_TYPE (*insnp)) @@ -1201,10 +1528,10 @@ static void dds_stream_swap_insitu (void * __restrict vbuf, uint32_t size, uint3 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; + const struct ddsi_sertopic_default_desc *desc = &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 uint32_t *insnp = desc->m_ops + desc->m_keys[i]; const void *src = sample + insnp[1]; assert (insn_key_ok_p (*insnp)); switch (DDS_OP_TYPE (*insnp)) @@ -1362,10 +1689,10 @@ static void dds_stream_extract_keyBE_from_key_prim_op (dds_istream_t * __restric 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; + const struct ddsi_sertopic_default_desc *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; + uint32_t const * const op = desc->m_ops + desc->m_keys[i]; dds_stream_extract_keyBE_from_key_prim_op (is, os, op); } } @@ -1565,21 +1892,21 @@ static void dds_stream_extract_keyBE_from_data1 (dds_istream_t * __restrict is, 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; + const struct ddsi_sertopic_default_desc *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; + const struct ddsi_sertopic_default_desc *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; + const struct ddsi_sertopic_default_desc *desc = &topic->type; kh->m_set = 1; if (desc->m_nkeys == 0) { @@ -1874,17 +2201,17 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize) { - (void) dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true); + (void) dds_stream_print_sample1 (&buf, &bufsize, is, topic->type.m_ops, true); return bufsize; } size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize) { - const dds_topic_descriptor_t *desc = topic->type; + const struct ddsi_sertopic_default_desc *desc = &topic->type; bool cont = prtf (&buf, &bufsize, ":k:{"); for (uint32_t i = 0; cont && i < desc->m_nkeys; i++) { - const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index; + const uint32_t *op = desc->m_ops + desc->m_keys[i]; assert (insn_key_ok_p (*op)); switch (DDS_OP_TYPE (*op)) { diff --git a/src/core/ddsi/src/ddsi_deadline.c b/src/core/ddsi/src/ddsi_deadline.c new file mode 100644 index 0000000..56ab8e4 --- /dev/null +++ b/src/core/ddsi/src/ddsi_deadline.c @@ -0,0 +1,112 @@ +/* + * 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 + */ +#include +#include +#include "dds/ddsrt/circlist.h" +#include "dds/ddsi/ddsi_deadline.h" +#include "dds/ddsi/q_time.h" +#include "dds/ddsi/q_xevent.h" + +static void instance_deadline_missed_cb (struct xevent *xev, void *varg, nn_mtime_t tnow) +{ + struct deadline_adm * const deadline_adm = varg; + nn_mtime_t next_valid = deadline_adm->deadline_missed_cb((char *)deadline_adm - deadline_adm->list_offset, tnow); + resched_xevent_if_earlier (xev, next_valid); +} + +/* Gets the instance from the list in deadline admin that has the earliest missed deadline and + * removes the instance element from the list. If no more instances with missed deadline exist + * in the list, the deadline (nn_mtime_t) for the first instance to 'expire' is returned. If the + * list is empty, NN_MTIME_NEVER is returned */ +nn_mtime_t deadline_next_missed_locked (struct deadline_adm *deadline_adm, nn_mtime_t tnow, void **instance) +{ + struct deadline_elem *elem = NULL; + if (!ddsrt_circlist_isempty (&deadline_adm->list)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (&deadline_adm->list); + elem = DDSRT_FROM_CIRCLIST (struct deadline_elem, e, list_elem); + if (elem->t_deadline.v <= tnow.v) + { + ddsrt_circlist_remove (&deadline_adm->list, &elem->e); + if (instance != NULL) + *instance = (char *)elem - deadline_adm->elem_offset; + return (nn_mtime_t) { 0 }; + } + } + if (instance != NULL) + *instance = NULL; + return (elem != NULL) ? elem->t_deadline : NN_MTIME_NEVER; +} + +void deadline_init (const struct ddsi_domaingv *gv, struct deadline_adm *deadline_adm, size_t list_offset, size_t elem_offset, deadline_missed_cb_t deadline_missed_cb) +{ + ddsrt_circlist_init (&deadline_adm->list); + deadline_adm->evt = qxev_callback (gv->xevents, NN_MTIME_NEVER, instance_deadline_missed_cb, deadline_adm); + deadline_adm->deadline_missed_cb = deadline_missed_cb; + deadline_adm->list_offset = list_offset; + deadline_adm->elem_offset = elem_offset; +} + +void deadline_stop (const struct deadline_adm *deadline_adm) +{ + delete_xevent_callback (deadline_adm->evt); +} + +void deadline_clear (struct deadline_adm *deadline_adm) +{ + while ((deadline_next_missed_locked (deadline_adm, NN_MTIME_NEVER, NULL)).v == 0); +} + +void deadline_fini (const struct deadline_adm *deadline_adm) +{ + assert (ddsrt_circlist_isempty (&deadline_adm->list)); + (void) deadline_adm; +} + +extern inline void deadline_register_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tnow); +extern inline void deadline_reregister_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tnow); + +void deadline_register_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem, nn_mtime_t tprev, nn_mtime_t tnow) +{ + ddsrt_circlist_append(&deadline_adm->list, &elem->e); + elem->t_deadline = (tprev.v + deadline_adm->dur >= tnow.v) ? tprev : tnow; + elem->t_deadline.v += deadline_adm->dur; + resched_xevent_if_earlier (deadline_adm->evt, elem->t_deadline); +} + +extern inline void deadline_unregister_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem); + +void deadline_unregister_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem) +{ + /* Updating the scheduled event with the new shortest expiry + * is not required, because the event will be rescheduled when + * this removed element expires. Only remove the element from the + * deadline list */ + + elem->t_deadline = NN_MTIME_NEVER; + ddsrt_circlist_remove(&deadline_adm->list, &elem->e); +} + +extern inline void deadline_renew_instance_locked (struct deadline_adm *deadline_adm, struct deadline_elem *elem); + +void deadline_renew_instance_real (struct deadline_adm *deadline_adm, struct deadline_elem *elem) +{ + /* move element to end of the list (list->latest) and update deadline + according to current deadline duration in rhc (event with old deadline + will still be triggered, but has no effect on this instance because in + the callback the deadline (which will be the updated value) will be + checked for expiry */ + ddsrt_circlist_remove(&deadline_adm->list, &elem->e); + elem->t_deadline = now_mt(); + elem->t_deadline.v += deadline_adm->dur; + ddsrt_circlist_append(&deadline_adm->list, &elem->e); +} diff --git a/src/core/ddsi/src/ddsi_deliver_locally.c b/src/core/ddsi/src/ddsi_deliver_locally.c new file mode 100644 index 0000000..b04d2fe --- /dev/null +++ b/src/core/ddsi/src/ddsi_deliver_locally.c @@ -0,0 +1,269 @@ +/* + * 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/log.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/avl.h" + +#include "dds/ddsi/ddsi_deliver_locally.h" +#include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/ddsi_rhc.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_entity.h" + +#define TOPIC_SAMPLE_CACHE_SIZE 4 + +struct ddsi_sertopic; +struct ddsi_serdata; +struct ddsi_tkmap_instance; + +struct topic_sample_cache_entry { + struct ddsi_serdata *sample; + struct ddsi_tkmap_instance *tk; +}; + +struct topic_sample_cache_large_entry { + ddsrt_avl_node_t avlnode; + const struct ddsi_sertopic *topic; + struct ddsi_serdata *sample; + struct ddsi_tkmap_instance *tk; +}; + +struct topic_sample_cache { + uint32_t n; + const struct ddsi_sertopic *topics[TOPIC_SAMPLE_CACHE_SIZE]; + struct topic_sample_cache_entry samples[TOPIC_SAMPLE_CACHE_SIZE]; + ddsrt_avl_tree_t overflow; +}; + +static int cmp_topic_ptrs (const void *va, const void *vb) +{ + uintptr_t a = (uintptr_t) va; + uintptr_t b = (uintptr_t) vb; + return (a == b) ? 0 : (a < b) ? -1 : 1; +} + +static const ddsrt_avl_treedef_t tsc_large_td = DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY (offsetof (struct topic_sample_cache_large_entry, avlnode), offsetof (struct topic_sample_cache_large_entry, topic), cmp_topic_ptrs, 0); + +static void free_sample_after_store (struct ddsi_domaingv *gv, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk) +{ + if (sample) + { + ddsi_tkmap_instance_unref (gv->m_tkmap, tk); + ddsi_serdata_unref (sample); + } +} + +static void topic_sample_cache_init (struct topic_sample_cache * __restrict tsc) +{ + tsc->n = 0; + ddsrt_avl_init (&tsc_large_td, &tsc->overflow); +} + +static void free_large_entry (void *vnode, void *varg) +{ + struct topic_sample_cache_large_entry *e = vnode; + struct ddsi_domaingv *gv = varg; + free_sample_after_store (gv, e->sample, e->tk); + ddsrt_free (e); +} + +static void topic_sample_cache_fini (struct topic_sample_cache * __restrict tsc, struct ddsi_domaingv *gv) +{ + for (uint32_t i = 0; i < tsc->n && i < TOPIC_SAMPLE_CACHE_SIZE; i++) + if (tsc->topics[i] && tsc->samples[i].tk) + free_sample_after_store (gv, tsc->samples[i].sample, tsc->samples[i].tk); + + ddsrt_avl_free_arg (&tsc_large_td, &tsc->overflow, free_large_entry, gv); +} + +static bool topic_sample_cache_lookup (struct ddsi_serdata ** __restrict sample, struct ddsi_tkmap_instance ** __restrict tk, struct topic_sample_cache * __restrict tsc, const struct ddsi_sertopic *topic) +{ + /* linear scan of an array of pointers should be pretty fast */ + for (uint32_t i = 0; i < tsc->n && i < TOPIC_SAMPLE_CACHE_SIZE; i++) + { + if (tsc->topics[i] == topic) + { + *tk = tsc->samples[i].tk; + *sample = tsc->samples[i].sample; + return true; + } + } + + struct topic_sample_cache_large_entry *e; + if ((e = ddsrt_avl_lookup (&tsc_large_td, &tsc->overflow, topic)) != NULL) + { + *tk = e->tk; + *sample = e->sample; + return true; + } + return false; +} + +static void topic_sample_cache_store (struct topic_sample_cache * __restrict tsc, const struct ddsi_sertopic *topic, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk) +{ + if (tsc->n < TOPIC_SAMPLE_CACHE_SIZE) + { + tsc->topics[tsc->n] = topic; + tsc->samples[tsc->n].tk = tk; + tsc->samples[tsc->n].sample = sample; + } + else + { + struct topic_sample_cache_large_entry *e = ddsrt_malloc (sizeof (*e)); + e->topic = topic; + e->tk = tk; + e->sample = sample; + ddsrt_avl_insert (&tsc_large_td, &tsc->overflow, e); + } + tsc->n++; +} + +dds_return_t deliver_locally_one (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, const ddsi_guid_t *rdguid, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo) +{ + struct reader *rd = entidx_lookup_reader_guid (gv->entity_index, rdguid); + if (rd == NULL) + return DDS_RETCODE_OK; + + struct ddsi_serdata *payload; + struct ddsi_tkmap_instance *tk; + if ((payload = ops->makesample (&tk, gv, rd->topic, vsourceinfo)) != NULL) + { + EETRACE (source_entity, " =>"PGUIDFMT"\n", PGUID (*rdguid)); + /* FIXME: why look up rd,pwr again? Their states remains valid while the thread stays + "awake" (although a delete can be initiated), and blocking like this is a stopgap + anyway -- quite possibly to abort once either is deleted */ + while (!ddsi_rhc_store (rd->rhc, wrinfo, payload, tk)) + { + if (source_entity_locked) + ddsrt_mutex_unlock (&source_entity->lock); + dds_sleepfor (DDS_MSECS (1)); + if (source_entity_locked) + ddsrt_mutex_lock (&source_entity->lock); + if (entidx_lookup_reader_guid (gv->entity_index, rdguid) == NULL || + entidx_lookup_guid_untyped (gv->entity_index, &source_entity->guid) == NULL) + { + /* give up when reader or proxy writer no longer accessible */ + break; + } + } + free_sample_after_store (gv, payload, tk); + } + return DDS_RETCODE_OK; +} + +static dds_return_t deliver_locally_slowpath (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo) +{ + /* 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. */ + struct topic_sample_cache tsc; + ddsrt_avl_iter_t it; + struct reader *rd; + topic_sample_cache_init (&tsc); + if (!source_entity_locked) + ddsrt_mutex_lock (&source_entity->lock); + rd = ops->first_reader (gv->entity_index, source_entity, &it); + if (rd != NULL) + EETRACE (source_entity, " =>"); + while (rd != NULL) + { + struct ddsi_serdata *payload; + struct ddsi_tkmap_instance *tk; + if (!topic_sample_cache_lookup (&payload, &tk, &tsc, rd->topic)) + { + payload = ops->makesample (&tk, gv, rd->topic, vsourceinfo); + topic_sample_cache_store (&tsc, rd->topic, payload, tk); + } + /* check payload to allow for deserialisation failures */ + if (payload) + { + EETRACE (source_entity, " "PGUIDFMT, PGUID (rd->e.guid)); + (void) ddsi_rhc_store (rd->rhc, wrinfo, payload, tk); + } + rd = ops->next_reader (gv->entity_index, &it); + } + EETRACE (source_entity, "\n"); + if (!source_entity_locked) + ddsrt_mutex_unlock (&source_entity->lock); + topic_sample_cache_fini (&tsc, gv); + return DDS_RETCODE_OK; +} + +static dds_return_t deliver_locally_fastpath (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo) +{ + struct reader ** const rdary = fastpath_rdary->rdary; + uint32_t i = 0; + while (rdary[i]) + { + struct ddsi_sertopic const * const topic = rdary[i]->topic; + struct ddsi_serdata *payload; + struct ddsi_tkmap_instance *tk; + if ((payload = ops->makesample (&tk, gv, topic, vsourceinfo)) == NULL) + { + /* malformed payload: skip all readers with the same topic */ + while (rdary[++i] && rdary[i]->topic == topic) + ; /* do nothing */ + } + else + { + do { + dds_return_t rc; + while (!ddsi_rhc_store (rdary[i]->rhc, wrinfo, payload, tk)) + { + if ((rc = ops->on_failure_fastpath (source_entity, source_entity_locked, fastpath_rdary, vsourceinfo)) != DDS_RETCODE_OK) + { + free_sample_after_store (gv, payload, tk); + return rc; + } + } + } while (rdary[++i] && rdary[i]->topic == topic); + free_sample_after_store (gv, payload, tk); + } + } + return DDS_RETCODE_OK; +} + +dds_return_t deliver_locally_allinsync (struct ddsi_domaingv *gv, struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, const struct ddsi_writer_info *wrinfo, const struct deliver_locally_ops * __restrict ops, void *vsourceinfo) +{ + dds_return_t rc; + /* FIXME: Retry loop for re-delivery of rejected reliable samples is a bad hack + should instead throttle back the writer by skipping acknowledgement and retry */ + do { + ddsrt_mutex_lock (&fastpath_rdary->rdary_lock); + if (fastpath_rdary->fastpath_ok) + { + EETRACE (source_entity, " => EVERYONE\n"); + if (fastpath_rdary->rdary[0]) + rc = deliver_locally_fastpath (gv, source_entity, source_entity_locked, fastpath_rdary, wrinfo, ops, vsourceinfo); + else + rc = DDS_RETCODE_OK; + ddsrt_mutex_unlock (&fastpath_rdary->rdary_lock); + } + else + { + ddsrt_mutex_unlock (&fastpath_rdary->rdary_lock); + rc = deliver_locally_slowpath (gv, source_entity, source_entity_locked, wrinfo, ops, vsourceinfo); + } + } while (rc == DDS_RETCODE_TRY_AGAIN); + return rc; +} diff --git a/src/core/ddsi/src/ddsi_entity_index.c b/src/core/ddsi/src/ddsi_entity_index.c index b22488b..e23c922 100644 --- a/src/core/ddsi/src/ddsi_entity_index.c +++ b/src/core/ddsi/src/ddsi_entity_index.c @@ -20,7 +20,7 @@ #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_gc.h" #include "dds/ddsi/q_rtps.h" /* guid_t */ @@ -220,13 +220,13 @@ static void gc_buckets_cb (struct gcreq *gcreq) static void gc_buckets (void *bs, void *varg) { - struct q_globals *gv = varg; + struct ddsi_domaingv *gv = varg; struct gcreq *gcreq = gcreq_new (gv->gcreq_queue, gc_buckets_cb); gcreq->arg = bs; gcreq_enqueue (gcreq); } -struct entity_index *entity_index_new (struct q_globals *gv) +struct entity_index *entity_index_new (struct ddsi_domaingv *gv) { struct entity_index *entidx; entidx = ddsrt_malloc (sizeof (*entidx)); diff --git a/src/core/ddsi/src/ddsi_handshake.c b/src/core/ddsi/src/ddsi_handshake.c index 13d8390..63de1a0 100644 --- a/src/core/ddsi/src/ddsi_handshake.c +++ b/src/core/ddsi/src/ddsi_handshake.c @@ -24,7 +24,7 @@ struct ddsi_handshake ddsi_guid_t local_pguid; /* the guid of the local participant */ ddsi_guid_t remote_pguid; /* the guid of the remote participant */ ddsi_handshake_end_cb_t end_cb; - struct q_globals *gv; + struct ddsi_domaingv *gv; ddsrt_mutex_t lock; ddsrt_cond_t cv; diff --git a/src/core/ddsi/src/ddsi_ipaddr.c b/src/core/ddsi/src/ddsi_ipaddr.c index f939816..d9f89ae 100644 --- a/src/core/ddsi/src/ddsi_ipaddr.c +++ b/src/core/ddsi/src/ddsi_ipaddr.c @@ -18,7 +18,7 @@ #include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/q_nwif.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" int ddsi_ipaddr_compare (const struct sockaddr *const sa1, const struct sockaddr *const sa2) { @@ -54,11 +54,10 @@ 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, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) +enum ddsi_nearby_address_result ddsi_ipaddr_is_nearby_address (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; - (void)tran; ddsi_ipaddr_from_loc(&tmp, loc); for (i = 0; i < ninterf; i++) { @@ -111,16 +110,15 @@ enum ddsi_locator_from_string_result ddsi_ipaddr_from_string (ddsi_tran_factory_ if (tmpaddr.ss_family != af) { return AFSR_MISMATCH; } - ddsi_ipaddr_to_loc (loc, (struct sockaddr *)&tmpaddr, kind); + ddsi_ipaddr_to_loc (tran, loc, (struct sockaddr *)&tmpaddr, kind); /* This is just an address, so there is no valid value for port, other than INVALID. Without a guarantee that tmpaddr has port 0, best is to set it explicitly here */ loc->port = NN_LOCATOR_PORT_INVALID; return AFSR_OK; } -char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) +char *ddsi_ipaddr_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) { - (void)tran; assert (sizeof_dst > 1); if (loc->kind == NN_LOCATOR_KIND_INVALID) (void) snprintf (dst, sizeof_dst, "(invalid)"); @@ -161,8 +159,9 @@ char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_ return dst; } -void ddsi_ipaddr_to_loc (nn_locator_t *dst, const struct sockaddr *src, int32_t kind) +void ddsi_ipaddr_to_loc (const struct ddsi_tran_factory *tran, nn_locator_t *dst, const struct sockaddr *src, int32_t kind) { + dst->tran = (struct ddsi_tran_factory *) tran; dst->kind = kind; switch (src->sa_family) { @@ -172,6 +171,7 @@ void ddsi_ipaddr_to_loc (nn_locator_t *dst, const struct sockaddr *src, int32_t assert (kind == NN_LOCATOR_KIND_UDPv4 || kind == NN_LOCATOR_KIND_TCPv4); if (x->sin_addr.s_addr == htonl (INADDR_ANY)) { + dst->tran = NULL; dst->kind = NN_LOCATOR_KIND_INVALID; dst->port = NN_LOCATOR_PORT_INVALID; memset (dst->address, 0, sizeof (dst->address)); @@ -191,6 +191,7 @@ void ddsi_ipaddr_to_loc (nn_locator_t *dst, const struct sockaddr *src, int32_t assert (kind == NN_LOCATOR_KIND_UDPv6 || kind == NN_LOCATOR_KIND_TCPv6); if (IN6_IS_ADDR_UNSPECIFIED (&x->sin6_addr)) { + dst->tran = NULL; dst->kind = NN_LOCATOR_KIND_INVALID; dst->port = NN_LOCATOR_PORT_INVALID; memset (dst->address, 0, sizeof (dst->address)); diff --git a/src/core/ddsi/src/ddsi_lifespan.c b/src/core/ddsi/src/ddsi_lifespan.c index 1ed3a3c..3ad8737 100644 --- a/src/core/ddsi/src/ddsi_lifespan.c +++ b/src/core/ddsi/src/ddsi_lifespan.c @@ -49,7 +49,7 @@ nn_mtime_t lifespan_next_expired_locked (const struct lifespan_adm *lifespan_adm return (node != NULL) ? node->t_expire : NN_MTIME_NEVER; } -void lifespan_init (const struct q_globals *gv, struct lifespan_adm *lifespan_adm, size_t fh_offset, size_t fh_node_offset, sample_expired_cb_t sample_expired_cb) +void lifespan_init (const struct ddsi_domaingv *gv, struct lifespan_adm *lifespan_adm, size_t fh_offset, size_t fh_node_offset, sample_expired_cb_t sample_expired_cb) { ddsrt_fibheap_init (&lifespan_fhdef, &lifespan_adm->ls_exp_heap); lifespan_adm->evt = qxev_callback (gv->xevents, NN_MTIME_NEVER, lifespan_rhc_node_exp, lifespan_adm); diff --git a/src/core/ddsi/src/ddsi_mcgroup.c b/src/core/ddsi/src/ddsi_mcgroup.c index a956ce1..cd49444 100644 --- a/src/core/ddsi/src/ddsi_mcgroup.c +++ b/src/core/ddsi/src/ddsi_mcgroup.c @@ -20,7 +20,7 @@ #include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsrt/avl.h" struct nn_group_membership_node { @@ -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(conn->m_base.gv, srcstr, sizeof(srcstr), srcloc); + ddsi_locator_to_string_no_port(srcstr, sizeof(srcstr), srcloc); } #else DDSRT_UNUSED_ARG (srcloc); #endif - ddsi_locator_to_string_no_port (conn->m_base.gv, mcstr, sizeof(mcstr), mcloc); + ddsi_locator_to_string_no_port (mcstr, sizeof(mcstr), mcloc); if (interf) - ddsi_locator_to_string_no_port(conn->m_base.gv, interfstr, sizeof(interfstr), &interf->loc); + ddsi_locator_to_string_no_port(interfstr, sizeof(interfstr), &interf->loc); else (void) snprintf (interfstr, sizeof (interfstr), "(default)"); n = err ? snprintf (buf, bufsz, "error %d in ", err) : 0; @@ -177,7 +177,7 @@ static int interface_in_recvips_p (const struct config_in_addr_node *recvips, co return 0; } -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) +static int joinleave_mcgroups (const struct ddsi_domaingv *gv, ddsi_tran_conn_t conn, int join, const nn_locator_t *srcloc, const nn_locator_t *mcloc) { int rc; switch (gv->recvips_mode) @@ -223,7 +223,7 @@ static int joinleave_mcgroups (const struct q_globals *gv, ddsi_tran_conn_t conn return 0; } -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) +int ddsi_join_mc (const struct ddsi_domaingv *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; @@ -242,7 +242,7 @@ int ddsi_join_mc (const struct q_globals *gv, struct nn_group_membership *mship, return ret; } -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 ddsi_leave_mc (const struct ddsi_domaingv *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 (&mship->lock); @@ -282,7 +282,7 @@ void ddsi_transfer_group_membership (struct nn_group_membership *mship, ddsi_tra ddsrt_mutex_unlock (&mship->lock); } -int ddsi_rejoin_transferred_mcgroups (const struct q_globals *gv, struct nn_group_membership *mship, ddsi_tran_conn_t conn) +int ddsi_rejoin_transferred_mcgroups (const struct ddsi_domaingv *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; diff --git a/src/core/ddsi/src/q_plist.c b/src/core/ddsi/src/ddsi_plist.c similarity index 83% rename from src/core/ddsi/src/q_plist.c rename to src/core/ddsi/src/ddsi_plist.c index 2e38033..d2243f6 100644 --- a/src/core/ddsi/src/q_plist.c +++ b/src/core/ddsi/src/ddsi_plist.c @@ -24,17 +24,17 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_xmsg.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.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/ddsi_domaingv.h" #include "dds/ddsi/q_protocol.h" /* for NN_STATUSINFO_... */ -#include "dds/ddsi/q_radmin.h" /* for nn_plist_quickscan */ +#include "dds/ddsi/q_radmin.h" /* for ddsi_plist_quickscan */ #include "dds/ddsrt/avl.h" #include "dds/ddsi/q_misc.h" /* for vendor_is_... */ @@ -50,7 +50,7 @@ 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 - entries in nn_plist, but they are never to be inspected and + entries in ddsi_plist, but they are never to be inspected and the bits corresponding to them must be 0 except while processing an incoming parameter list.) */ #define PPTMP_MULTICAST_IPADDRESS (1 << 0) @@ -97,7 +97,7 @@ struct piddesc { 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 plist_offset; /* offset from start of ddsi_plist_t */ size_t size; /* in-memory size for copying */ union { /* descriptor for generic code: 12 is enough for the current set of @@ -111,12 +111,12 @@ struct piddesc { 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); + bool (*print) (char * __restrict *buf, size_t * __restrict bufsize, const void *src, 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); @@ -124,8 +124,8 @@ 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 int partitions_equal (const void *srca, const void *srcb, size_t off); +static dds_return_t ddsi_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos, bool strict); static size_t pserop_seralign(enum pserop op) { @@ -237,6 +237,34 @@ static dds_return_t deser_int64 (int64_t *dst, const struct dd * __restrict dd, return 0; } +/* Returns true if buffer not yet exhausted, false otherwise */ +static bool prtf (char * __restrict *buf, size_t * __restrict bufsize, const char *fmt, ...) +{ + va_list ap; + if (*bufsize == 0) + return false; + va_start (ap, fmt); + int n = vsnprintf (*buf, *bufsize, fmt, ap); + va_end (ap); + if (n < 0) + { + **buf = 0; + return false; + } + else if ((size_t) n <= *bufsize) + { + *buf += (size_t) n; + *bufsize -= (size_t) n; + return (*bufsize > 0); + } + else + { + *buf += *bufsize; + *bufsize = 0; + return false; + } +} + #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) @@ -290,6 +318,12 @@ static bool equal_reliability (const void *srcx, const void *srcy, size_t srcoff return x->kind == y->kind && x->max_blocking_time == y->max_blocking_time; } +static bool print_reliability (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff) +{ + dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); + return prtf (buf, bufsize, "%d:%"PRId64, (int) x->kind, x->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)); @@ -314,6 +348,12 @@ static dds_return_t ser_statusinfo (struct nn_xmsg *xmsg, nn_parameterid_t pid, return 0; } +static bool print_statusinfo (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff) +{ + uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + return prtf (buf, bufsize, "%"PRIx32, *x); +} + 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)); @@ -339,8 +379,10 @@ static dds_return_t ser_locator (struct nn_xmsg *xmsg, nn_parameterid_t pid, con 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)); + char * const p = nn_xmsg_addpar (xmsg, pid, 24); + memcpy (p, &l->loc.kind, 4); + memcpy (p + 4, &l->loc.port, 4); + memcpy (p + 8, l->loc.address, 16); } return 0; } @@ -400,6 +442,21 @@ static const enum pserop* pserop_advance (const enum pserop * __restrict desc) return (desc + 1); } +static bool print_locator (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff) +{ + nn_locators_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_locators_t)); + const char *sep = ""; + prtf (buf, bufsize, "{"); + for (const struct nn_locators_one *l = x->first; l != NULL; l = l->next) + { + char tmp[DDSI_LOCATORSTRLEN]; + ddsi_locator_to_string (tmp, sizeof (tmp), &l->loc); + prtf (buf, bufsize, "%s%s", sep, tmp); + sep = ","; + } + return prtf (buf, bufsize, "}"); +} + static size_t ser_generic_srcsize (const enum pserop * __restrict desc) { size_t srcoff = 0, srcalign = 0; @@ -1169,10 +1226,202 @@ bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop return equal_generic (srcx, srcy, 0, desc); } +static uint32_t isprint_runlen (uint32_t n, const unsigned char *xs) +{ + uint32_t m; + for (m = 0; m < n && xs[m] != '"' && isprint (xs[m]) && xs[m] < 127; m++) + ; + return m; +} + +static bool prtf_octetseq (char * __restrict *buf, size_t * __restrict bufsize, uint32_t n, const unsigned char *xs) +{ + uint32_t i = 0; + while (i < n) + { + uint32_t m = isprint_runlen (n - i, xs); + if (m >= 4 || (i == 0 && m == n)) + { + if (!prtf (buf, bufsize, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs)) + return false; + xs += m; + i += m; + } + else + { + if (m == 0) + m = 1; + while (m--) + { + if (!prtf (buf, bufsize, "%s%u", i == 0 ? "" : ",", *xs++)) + return false; + i++; + } + } + } + return true; +} + +static bool print_generic1 (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff, const enum pserop * __restrict desc, const char *sep) +{ + while (true) + { + switch (*desc) + { + case XSTOP: + return true; + case XO: { /* octet sequence */ + ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); + prtf (buf, bufsize, "%s%"PRIu32"<", sep, x->length); + (void) prtf_octetseq (buf, bufsize, x->length, x->value); + if (!prtf (buf, bufsize, ">")) + return false; + srcoff += sizeof (*x); + break; + } + case XS: { /* string */ + char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *)); + if (!prtf (buf, bufsize, "%s\"%s\"", sep, *x)) + return false; + srcoff += sizeof (*x); + break; + } + case XE1: case XE2: case XE3: { /* enum */ + unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned)); + if (!prtf (buf, bufsize, "%s%u", sep, *x)) + return false; + 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); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%"PRId32, sep, x[i])) + return false; + sep = ":"; + } + 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); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%"PRIu32, sep, x[i])) + return false; + sep = ":"; + } + srcoff += cnt * sizeof (*x); + break; + } + case Xl: { + int64_t const * const x = deser_generic_src (src, &srcoff, alignof (int64_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xl); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%"PRId64, sep, x[i])) + return false; + sep = ":"; + } + 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); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%"PRId64, sep, x[i])) + return false; + sep = ":"; + } + 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); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%d", sep, x[i])) + return false; + sep = ":"; + } + 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! */ + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%d", sep, x[i])) + return false; + sep = ":"; + } + srcoff += cnt * sizeof (*x); + break; + } + case XbPROP: { /* "propagate" boolean: don't serialize, skip it and everything that follows if false */ + unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char)); + if (!prtf (buf, bufsize, "%s%d", sep, *x)) + return false; + srcoff++; + break; + } + case XG: { /* GUID */ + ddsi_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_guid_t)); + if (!prtf (buf, bufsize, "%s"PGUIDFMT, sep, PGUID (*x))) + return false; + srcoff += sizeof (*x); + break; + } + case XK: { /* keyhash */ + nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t)); + if (!prtf (buf, bufsize, "%s{%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x}", sep, + x->value[0], x->value[1], x->value[2], x->value[3], x->value[4], x->value[5], x->value[6], x->value[7], + x->value[8], x->value[9], x->value[10], x->value[11], x->value[12], x->value[13], x->value[14], x->value[15])) + return false; + srcoff += sizeof (*x); + break; + } + case XQ: { + ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); + if (!prtf (buf, bufsize, "%s{", sep)) + return false; + if (x->length > 0) + { + const size_t elem_size = ser_generic_srcsize (desc + 1); + for (uint32_t i = 0; i < x->length; i++) + if (!print_generic1 (buf, bufsize, x->value, i * elem_size, desc + 1, (i == 0) ? "" : ",")) + return false; + } + if (!prtf (buf, bufsize, "}")) + return false; + srcoff += sizeof (*x); + while (*++desc != XSTOP) { } + break; + } + case Xopt: + break; + } + sep = ":"; + desc++; + } +} + +static bool print_generic (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ + return print_generic1 (buf, bufsize, src, srcoff, desc, ""); +} + #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 ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \ + { PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct ddsi_plist, member_), \ + membersize (struct ddsi_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__) @@ -1253,9 +1502,8 @@ static dds_return_t dvx_reader_favours_ssm (void * __restrict dst, const struct } #endif - -/* 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 */ +/* Standardized parameters -- QoS _MUST_ come first (ddsi_plist_init_tables verifies this) because + it allows early-out when processing a dds_qos_t instead of an ddsi_plist_t */ static const struct piddesc piddesc_omg[] = { QP (USER_DATA, user_data, XO), QP (TOPIC_NAME, topic_name, XS), @@ -1274,8 +1522,8 @@ static const struct piddesc piddesc_omg[] = { QP (PROPERTY_LIST, property, XQ, XbPROP, XS, XS, XSTOP, Xopt, XQ, XbPROP, XS, XO, XSTOP), /* 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 }, + offsetof (struct ddsi_plist, qos.reliability), membersize (struct ddsi_plist, qos.reliability), + { .f = { .deser = deser_reliability, .ser = ser_reliability, .valid = valid_reliability, .equal = equal_reliability, .print = print_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" */ @@ -1313,35 +1561,35 @@ static const struct piddesc piddesc_omg[] = { PP (DOMAIN_ID, domain_id, Xu), PP (DOMAIN_TAG, domain_tag, XS), { 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 }, + offsetof (struct ddsi_plist, statusinfo), membersize (struct ddsi_plist, statusinfo), + { .f = { .deser = deser_statusinfo, .ser = ser_statusinfo, .print = print_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 }, + offsetof (struct ddsi_plist, unicast_locators), membersize (struct ddsi_plist, unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 }, + offsetof (struct ddsi_plist, multicast_locators), membersize (struct ddsi_plist, multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 }, + offsetof (struct ddsi_plist, default_unicast_locators), membersize (struct ddsi_plist, default_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 }, + offsetof (struct ddsi_plist, default_multicast_locators), membersize (struct ddsi_plist, default_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 }, + offsetof (struct ddsi_plist, metatraffic_unicast_locators), membersize (struct ddsi_plist, metatraffic_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 }, + offsetof (struct ddsi_plist, metatraffic_multicast_locators), membersize (struct ddsi_plist, metatraffic_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator, .print = print_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 */ @@ -1356,13 +1604,9 @@ static const struct piddesc piddesc_eclipse[] = { QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2), QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XQ, XS, XSTOP), { PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL", - offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal), + offsetof (struct ddsi_plist, qos.ignorelocal), membersize (struct ddsi_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 } }; @@ -1374,11 +1618,7 @@ static const struct piddesc piddesc_prismtech[] = { 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, XQ, XS, XSTOP), - 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 } }; @@ -1424,7 +1664,7 @@ struct piddesc_index { Sizes are such that the highest PID (without flags) in table are the last entry in the array. Checked by - nn_plist_init_tables. + ddsi_plist_init_tables. FIXME: should compute them at build-time */ #define DEFAULT_PROC_ARRAY_SIZE 20 @@ -1465,10 +1705,10 @@ static const struct piddesc_index piddesc_vendor_index[] = { #undef INDEX_ANY /* List of entries that require unalias, fini processing; - initialized by nn_plist_init_tables; will assert when + initialized by ddsi_plist_init_tables; will assert when table too small or too large */ -static const struct piddesc *piddesc_unalias[DEFAULT_PROC_ARRAY_SIZE + SECURITY_PROC_ARRAY_SIZE]; -static const struct piddesc *piddesc_fini[DEFAULT_PROC_ARRAY_SIZE + SECURITY_PROC_ARRAY_SIZE]; +static const struct piddesc *piddesc_unalias[18 + SECURITY_PROC_ARRAY_SIZE]; +static const struct piddesc *piddesc_fini[18 + SECURITY_PROC_ARRAY_SIZE]; static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT; static size_t pid_to_index (nn_parameterid_t pid) @@ -1496,7 +1736,7 @@ static int piddesc_cmp_qos_addr (const void *va, const void *vb) return ((uintptr_t) *a == (uintptr_t) *b) ? 0 : ((uintptr_t) *a < (uintptr_t) *b) ? -1 : 1; } -static void nn_plist_init_tables_real (void) +static void ddsi_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++) @@ -1588,9 +1828,9 @@ static void nn_plist_init_tables_real (void) #endif } -void nn_plist_init_tables (void) +void ddsi_plist_init_tables (void) { - ddsrt_once (&table_init_control, nn_plist_init_tables_real); + ddsrt_once (&table_init_control, ddsi_plist_init_tables_real); } static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pmask, uint64_t qmask) @@ -1600,7 +1840,7 @@ static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pm /* 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 (); + ddsi_plist_init_tables (); if (shift > 0) { dds_qos_t *qos = dst; @@ -1609,7 +1849,7 @@ static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pm } else { - nn_plist_t *plist = dst; + ddsi_plist_t *plist = dst; pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; } @@ -1642,7 +1882,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift) /* 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 (); + ddsi_plist_init_tables (); if (shift > 0) { dds_qos_t *qos = dst; @@ -1651,7 +1891,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift) } else { - nn_plist_t *plist = dst; + ddsi_plist_t *plist = dst; pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; } @@ -1683,8 +1923,8 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _ 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; + const uint64_t aliased_dst_inp = (shift == 0) ? ((ddsi_plist_t *) dst)->aliased : 0; + const uint64_t aliased_dst_inq = (shift == 0) ? ((ddsi_plist_t *) dst)->qos.aliased : ((dds_qos_t *) dst)->aliased; #endif if (shift > 0) { @@ -1697,8 +1937,8 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _ } else { - nn_plist_t *plist_dst = dst; - const nn_plist_t *plist_src = src; + ddsi_plist_t *plist_dst = dst; + const ddsi_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 }; @@ -1759,7 +1999,7 @@ static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restric } else { - const nn_plist_t *plist = src; + const ddsi_plist_t *plist = src; pw = plist->present & pwanted; qw = plist->qos.present & qwanted; } @@ -1785,21 +2025,26 @@ static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restric } } -void nn_plist_fini (nn_plist_t *plist) +void ddsi_plist_fini (ddsi_plist_t *plist) { plist_or_xqos_fini (plist, 0, ~(uint64_t)0, ~(uint64_t)0); } -void nn_plist_unalias (nn_plist_t *plist) +void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask) +{ + plist_or_xqos_fini (plist, 0, pmask, qmask); +} + +void ddsi_plist_unalias (ddsi_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) +static dds_return_t ddsi_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 (); + ddsi_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]; @@ -1810,14 +2055,14 @@ static dds_return_t nn_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg break; if (xqos->present & entry->present_flag) { - const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + const size_t srcoff = entry->plist_offset - offsetof (ddsi_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); + DDS_CLOG (DDS_LC_PLIST, logcfg, "ddsi_xqos_valid: %s invalid\n", entry->name); return ret; } } @@ -1825,52 +2070,82 @@ static dds_return_t nn_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg } 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"); + DDS_CLOG (DDS_LC_PLIST, logcfg, "ddsi_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) +dds_return_t ddsi_xqos_valid (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos) { - return nn_xqos_valid_strictness (logcfg, xqos, true); + return ddsi_xqos_valid_strictness (logcfg, xqos, true); } -uint64_t nn_xqos_delta (const dds_qos_t *x, const dds_qos_t *y, uint64_t mask) +static void plist_or_xqos_delta (uint64_t *pdelta, uint64_t *qdelta, const void *srcx, const void *srcy, size_t shift, uint64_t pmask, uint64_t qmask) { + uint64_t pcheck, qcheck; + 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; + ddsi_plist_init_tables (); + if (shift > 0) + { + const dds_qos_t *x = srcx; + const dds_qos_t *y = srcy; + *pdelta = 0; + pcheck = 0; + *qdelta = (x->present ^ y->present) & qmask; + qcheck = (x->present & y->present) & qmask; + } + else + { + const ddsi_plist_t *x = srcx; + const ddsi_plist_t *y = srcy; + *pdelta = (x->present ^ y->present) & pmask; + pcheck = (x->present & y->present) & pmask; + *qdelta = (x->qos.present ^ y->qos.present) & qmask; + qcheck = (x->qos.present & y->qos.present) & qmask; + } 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)) + if (shift > 0 && !(entry->flags & PDF_QOS)) break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + const uint64_t check = (entry->flags & PDF_QOS) ? qcheck : pcheck; + uint64_t * const delta = (entry->flags & PDF_QOS) ? qdelta : pdelta; if (check & entry->present_flag) { - const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + const size_t off = entry->plist_offset - shift; 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); + equal = partitions_equal (srcx, srcy, off); else if (!(entry->flags & PDF_FUNCTION)) - equal = equal_generic (x, y, srcoff, entry->op.desc); + equal = equal_generic (srcx, srcy, off, entry->op.desc); else - equal = entry->op.f.equal (x, y, srcoff); + equal = entry->op.f.equal (srcx, srcy, off); if (!equal) - delta |= entry->present_flag; + *delta |= entry->present_flag; } } } - return delta; +} + +uint64_t ddsi_xqos_delta (const dds_qos_t *x, const dds_qos_t *y, uint64_t mask) +{ + uint64_t pdelta, qdelta; + plist_or_xqos_delta (&pdelta, &qdelta, x, y, offsetof (ddsi_plist_t, qos), 0, mask); + return qdelta; +} + +void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask) +{ + plist_or_xqos_delta (pdelta, qdelta, x, y, 0, pmask, qmask); } static dds_return_t validate_external_duration (const ddsi_duration_t *d) @@ -2029,10 +2304,12 @@ static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t w { nn_locator_t loc; - if (dd->bufsz < sizeof (loc)) + if (dd->bufsz < 24) return DDS_RETCODE_BAD_PARAMETER; - memcpy (&loc, dd->buf, sizeof (loc)); + memcpy (&loc.kind, dd->buf, 4); + memcpy (&loc.port, dd->buf + 4, 4); + memcpy (loc.address, dd->buf + 8, 16); if (dd->bswap) { loc.kind = ddsrt_bswap4 (loc.kind); @@ -2067,26 +2344,29 @@ static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t w return DDS_RETCODE_BAD_PARAMETER; if (loc.port != 0) return DDS_RETCODE_BAD_PARAMETER; - /* silently dropped correctly formatted "invalid" locators. */ + /* silently drop correctly formatted "invalid" locators. */ return 0; case NN_LOCATOR_KIND_RESERVED: - /* silently dropped "reserved" locators. */ + /* silently drop "reserved" locators. */ return 0; default: return 0; } + + loc.tran = ddsi_factory_supports (factory, loc.kind) ? factory : NULL; 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, ddsi_tran_factory_t factory) { + loc->tran = factory; 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 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) +static dds_return_t do_ipv4address (ddsi_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; @@ -2153,7 +2433,7 @@ static dds_return_t do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t } } -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) +static dds_return_t do_port (ddsi_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; @@ -2210,7 +2490,7 @@ static dds_return_t do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_t } } -static dds_return_t return_unrecognized_pid (nn_plist_t *plist, nn_parameterid_t pid) +static dds_return_t return_unrecognized_pid (ddsi_plist_t *plist, nn_parameterid_t pid) { if (!(pid & PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)) return 0; @@ -2221,7 +2501,7 @@ static dds_return_t return_unrecognized_pid (nn_plist_t *plist, nn_parameterid_t } } -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) +static dds_return_t init_one_parameter (ddsi_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) { /* special-cased ipv4address and port, because they have state beyond that what gets passed into the generic code */ @@ -2308,48 +2588,49 @@ static dds_return_t init_one_parameter (nn_plist_t *plist, nn_ipaddress_params_t 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 = ", + char tmp[256], *ptmp = tmp; + size_t tmpsize = sizeof (tmp); + (void) prtf_octetseq (&ptmp, &tmpsize, (uint32_t) dd->bufsz, dd->buf); + DDS_CWARNING (logcfg, "invalid parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" (%s) invalid, input = %s\n", 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"); + pid, entry->name, tmp); } return ret; } -void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b, uint64_t pmask, uint64_t qmask) +void ddsi_plist_mergein_missing (ddsi_plist_t *a, const ddsi_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) +void ddsi_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); + plist_or_xqos_mergein_missing (a, b, offsetof (ddsi_plist_t, qos), 0, mask); } -void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src) +void ddsi_plist_copy (ddsi_plist_t *dst, const ddsi_plist_t *src) { - nn_plist_init_empty (dst); - nn_plist_mergein_missing (dst, src, ~(uint64_t)0, ~(uint64_t)0); + ddsi_plist_init_empty (dst); + ddsi_plist_mergein_missing (dst, src, ~(uint64_t)0, ~(uint64_t)0); } -nn_plist_t *nn_plist_dup (const nn_plist_t *src) +ddsi_plist_t *ddsi_plist_dup (const ddsi_plist_t *src) { - nn_plist_t *dst; + ddsi_plist_t *dst; dst = ddsrt_malloc (sizeof (*dst)); - nn_plist_copy (dst, src); + ddsi_plist_copy (dst, src); assert (dst->aliased == 0); return dst; } -void nn_plist_init_empty (nn_plist_t *dest) +void ddsi_plist_init_empty (ddsi_plist_t *dest) { #ifndef NDEBUG memset (dest, 0, sizeof (*dest)); #endif dest->present = dest->aliased = 0; - nn_xqos_init_empty (&dest->qos); + ddsi_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) @@ -2429,12 +2710,12 @@ static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_ver return 0; } -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) +static dds_return_t final_validation (ddsi_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) +dds_return_t ddsi_plist_init_frommsg (ddsi_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const ddsi_plist_src_t *src) { const unsigned char *pl; struct dd dd; @@ -2470,10 +2751,10 @@ dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uin src->vendorid.id[0], src->vendorid.id[1], src->encoding); return DDS_RETCODE_BAD_PARAMETER; } - nn_plist_init_empty (dest); + ddsi_plist_init_empty (dest); dest_tmp.present = 0; - DDS_CLOG (DDS_LC_PLIST, src->logconfig, "NN_PLIST_INIT (bswap %d)\n", dd.bswap); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "DDSI_PLIST_INIT (bswap %d)\n", dd.bswap); pl = src->buf; while (pl + sizeof (nn_parameter_t) <= src->buf + src->bufsz) @@ -2494,7 +2775,7 @@ dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uin 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); + ddsi_plist_fini (dest); return res; } else @@ -2513,22 +2794,23 @@ dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uin { 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); + ddsi_plist_fini (dest); return DDS_RETCODE_BAD_PARAMETER; } if ((length % 4) != 0) /* DDSI 9.4.2.11 */ { 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); + ddsi_plist_fini (dest); return DDS_RETCODE_BAD_PARAMETER; } if (src->logconfig->c.mask & DDS_LC_PLIST) { - 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"); + char tmp[256], *ptmp = tmp; + size_t tmpsize = sizeof (tmp); + (void) prtf_octetseq (&ptmp, &tmpsize, length, (const unsigned char *) (par + 1)); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "%4"PRIx32" PID %"PRIx16" len %"PRIu16" %s\n", (uint32_t) (pl - src->buf), pid, length, tmp); } dd.buf = (const unsigned char *) (par + 1); @@ -2537,7 +2819,7 @@ dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uin { /* make sure we print a trace message on error */ 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); + ddsi_plist_fini (dest); return res; } pl += sizeof (*par) + length; @@ -2546,11 +2828,11 @@ dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uin without encountering a sentinel. That is an error */ 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); + ddsi_plist_fini (dest); return DDS_RETCODE_BAD_PARAMETER; } -const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid) +const unsigned char *ddsi_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid) { /* Scans the parameter list starting at src looking just for pid, returning NULL if not found; no further checking is done and the input is assumed to valid and in native format. Clearly @@ -2566,11 +2848,11 @@ const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_pa return (unsigned char *) (par + 1); } -unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const nn_plist_src_t *src) +unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src) { /* Sets a few fields in dest, returns address of first byte following parameter list, or NULL on error. Most errors will go - undetected, unlike nn_plist_init_frommsg(). */ + undetected, unlike ddsi_plist_init_frommsg(). */ const unsigned char *pl; (void)rmsg; dest->statusinfo = 0; @@ -2597,7 +2879,7 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn src->vendorid.id[0], src->vendorid.id[1], src->encoding); return NULL; } - DDS_CLOG (DDS_LC_PLIST, src->logconfig, "NN_PLIST_QUICKSCAN (bswap %d)\n", dest->bswap); + DDS_CLOG (DDS_LC_PLIST, src->logconfig, "DDSI_PLIST_QUICKSCAN (bswap %d)\n", dest->bswap); pl = src->buf; while (pl + sizeof (nn_parameter_t) <= src->buf + src->bufsz) { @@ -2658,7 +2940,7 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn return NULL; } -void nn_xqos_init_empty (dds_qos_t *dest) +void ddsi_xqos_init_empty (dds_qos_t *dest) { #ifndef NDEBUG memset (dest, 0, sizeof (*dest)); @@ -2666,9 +2948,9 @@ void nn_xqos_init_empty (dds_qos_t *dest) dest->present = dest->aliased = 0; } -void nn_plist_init_default_participant (nn_plist_t *plist) +void ddsi_plist_init_default_participant (ddsi_plist_t *plist) { - nn_plist_init_empty (plist); + ddsi_plist_init_empty (plist); plist->qos.present |= QP_PRISMTECH_ENTITY_FACTORY; plist->qos.entity_factory.autoenable_created_entities = 0; @@ -2680,7 +2962,7 @@ void nn_plist_init_default_participant (nn_plist_t *plist) static void xqos_init_default_common (dds_qos_t *xqos) { - nn_xqos_init_empty (xqos); + ddsi_xqos_init_empty (xqos); xqos->present |= QP_PRESENTATION; xqos->presentation.access_scope = DDS_PRESENTATION_INSTANCE; @@ -2722,7 +3004,7 @@ static void xqos_init_default_common (dds_qos_t *xqos) xqos->ignorelocal.value = DDS_IGNORELOCAL_NONE; } -static void nn_xqos_init_default_endpoint (dds_qos_t *xqos) +static void ddsi_xqos_init_default_endpoint (dds_qos_t *xqos) { xqos_init_default_common (xqos); @@ -2743,9 +3025,9 @@ static void nn_xqos_init_default_endpoint (dds_qos_t *xqos) xqos->partition.strs = NULL; } -void nn_xqos_init_default_reader (dds_qos_t *xqos) +void ddsi_xqos_init_default_reader (dds_qos_t *xqos) { - nn_xqos_init_default_endpoint (xqos); + ddsi_xqos_init_default_endpoint (xqos); xqos->present |= QP_RELIABILITY; xqos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT; @@ -2767,9 +3049,9 @@ void nn_xqos_init_default_reader (dds_qos_t *xqos) xqos->subscription_keys.key_list.strs = NULL; } -void nn_xqos_init_default_writer (dds_qos_t *xqos) +void ddsi_xqos_init_default_writer (dds_qos_t *xqos) { - nn_xqos_init_default_endpoint (xqos); + ddsi_xqos_init_default_endpoint (xqos); xqos->present |= QP_DURABILITY_SERVICE; xqos->durability_service.service_cleanup_delay = 0; @@ -2796,13 +3078,13 @@ void nn_xqos_init_default_writer (dds_qos_t *xqos) xqos->writer_data_lifecycle.autodispose_unregistered_instances = 1; } -void nn_xqos_init_default_writer_noautodispose (dds_qos_t *xqos) +void ddsi_xqos_init_default_writer_noautodispose (dds_qos_t *xqos) { - nn_xqos_init_default_writer (xqos); + ddsi_xqos_init_default_writer (xqos); xqos->writer_data_lifecycle.autodispose_unregistered_instances = 0; } -void nn_xqos_init_default_topic (dds_qos_t *xqos) +void ddsi_xqos_init_default_topic (dds_qos_t *xqos) { xqos_init_default_common (xqos); @@ -2830,9 +3112,9 @@ void nn_xqos_init_default_topic (dds_qos_t *xqos) xqos->subscription_keys.key_list.strs = NULL; } -static void nn_xqos_init_default_publisher_subscriber (dds_qos_t *xqos) +static void ddsi_xqos_init_default_publisher_subscriber (dds_qos_t *xqos) { - nn_xqos_init_empty (xqos); + ddsi_xqos_init_empty (xqos); xqos->present |= QP_GROUP_DATA; xqos->group_data.length = 0; @@ -2846,46 +3128,46 @@ static void nn_xqos_init_default_publisher_subscriber (dds_qos_t *xqos) xqos->partition.strs = NULL; } -void nn_xqos_init_default_subscriber (dds_qos_t *xqos) +void ddsi_xqos_init_default_subscriber (dds_qos_t *xqos) { - nn_xqos_init_default_publisher_subscriber (xqos); + ddsi_xqos_init_default_publisher_subscriber (xqos); } -void nn_xqos_init_default_publisher (dds_qos_t *xqos) +void ddsi_xqos_init_default_publisher (dds_qos_t *xqos) { - nn_xqos_init_default_publisher_subscriber (xqos); + ddsi_xqos_init_default_publisher_subscriber (xqos); } -void nn_xqos_copy (dds_qos_t *dst, const dds_qos_t *src) +void ddsi_xqos_copy (dds_qos_t *dst, const dds_qos_t *src) { - nn_xqos_init_empty (dst); - nn_xqos_mergein_missing (dst, src, ~(uint64_t)0); + ddsi_xqos_init_empty (dst); + ddsi_xqos_mergein_missing (dst, src, ~(uint64_t)0); } -void nn_xqos_fini (dds_qos_t *xqos) +void ddsi_xqos_fini (dds_qos_t *xqos) { - plist_or_xqos_fini (xqos, offsetof (nn_plist_t, qos), ~(uint64_t)0, ~(uint64_t)0); + plist_or_xqos_fini (xqos, offsetof (ddsi_plist_t, qos), ~(uint64_t)0, ~(uint64_t)0); } -void nn_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask) +void ddsi_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask) { - plist_or_xqos_fini (xqos, offsetof (nn_plist_t, qos), ~(uint64_t)0, mask); + plist_or_xqos_fini (xqos, offsetof (ddsi_plist_t, qos), ~(uint64_t)0, mask); } -void nn_xqos_unalias (dds_qos_t *xqos) +void ddsi_xqos_unalias (dds_qos_t *xqos) { - plist_or_xqos_unalias (xqos, offsetof (nn_plist_t, qos)); + plist_or_xqos_unalias (xqos, offsetof (ddsi_plist_t, qos)); } -dds_qos_t * nn_xqos_dup (const dds_qos_t *src) +dds_qos_t * ddsi_xqos_dup (const dds_qos_t *src) { dds_qos_t *dst = ddsrt_malloc (sizeof (*dst)); - nn_xqos_copy (dst, src); + ddsi_xqos_copy (dst, src); assert (dst->aliased == 0); return dst; } -bool nn_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith, bool check_non_empty) +bool ddsi_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith, bool check_non_empty) { if (!(xqos->present & QP_PROPERTY_LIST)) return false; @@ -2913,7 +3195,7 @@ static void fill_property(dds_property_t *prop, const char *name, const char *va * plugins to get their proper settings. If security properties are already present in * the QoS, the settings from configuration are ignored. */ -void nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg) +void ddsi_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg) { assert(cfg != NULL); @@ -3007,8 +3289,10 @@ static int partitions_equal_nlogn (const dds_partition_qospolicy_t *a, const dds return equal; } -static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b) +static int partitions_equal (const void *srca, const void *srcb, size_t off) { + const dds_partition_qospolicy_t *a = (const dds_partition_qospolicy_t *) ((const char *) srca + off); + const dds_partition_qospolicy_t *b = (const dds_partition_qospolicy_t *) ((const char *) srcb + off); /* Return true iff (the set a->strs) equals (the set b->strs); that is, order doesn't matter. One could argue that "**" and "*" are equal, but we're not that precise here. */ @@ -3047,151 +3331,105 @@ static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_parti /*************************/ -void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted) +void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted) { - plist_or_xqos_addtomsg (m, xqos, offsetof (struct nn_plist, qos), 0, wanted); + plist_or_xqos_addtomsg (m, xqos, offsetof (struct ddsi_plist, qos), 0, wanted); } -void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted) +void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted) { plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted); } /*************************/ -static uint32_t isprint_runlen (uint32_t n, const unsigned char *xs) +static void plist_or_xqos_print (char * __restrict *buf, size_t * __restrict bufsize, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted) { - 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, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs) -{ - uint32_t i = 0; - while (i < n) + /* shift == 0: plist, shift > 0: just qos */ + const char *sep = ""; + uint64_t pw, qw; + if (shift > 0) { - uint32_t m = isprint_runlen (n - i, xs); - if (m >= 4 || (i == 0 && m == n)) + const dds_qos_t *qos = src; + pw = 0; + qw = qos->present & qwanted; + } + else + { + const ddsi_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++) { - DDS_CLOG (cat, logcfg, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs); - xs += m; - i += m; - } - else - { - if (m == 0) - m = 1; - while (m--) + struct piddesc const * const entry = &table[i]; + if (entry->pid == PID_PAD) + continue; + if (((entry->flags & PDF_QOS) ? qw : pw) & entry->present_flag) { - DDS_CLOG (cat, logcfg, "%s%u", i == 0 ? "" : ",", *xs++); - i++; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t srcoff = entry->plist_offset - shift; + /* convert name to lower case for making the trace easier on the eyes */ + char lcname[64]; + const size_t namelen = strlen (entry->name); + assert (namelen < sizeof (lcname)); + for (size_t p = 0; p < namelen; p++) + lcname[p] = (char) tolower (entry->name[p]); + lcname[namelen] = 0; + if (!prtf (buf, bufsize, "%s%s=", sep, lcname)) + return; + sep = ","; + bool cont; + if (!(entry->flags & PDF_FUNCTION)) + cont = print_generic (buf, bufsize, src, srcoff, entry->op.desc); + else + cont = entry->op.f.print (buf, bufsize, src, srcoff); + if (!cont) + return; } } } } -void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos) +static void plist_or_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted) { - uint64_t p = xqos->present; - const char *prefix = ""; -#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 "%"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, { LOGB1 ("presentation=%d:%u:%u", xqos->presentation.access_scope, xqos->presentation.coherent_access, xqos->presentation.ordered_access); }); - DO (PARTITION, { - LOGB0 ("partition={"); - for (uint32_t i = 0; i < xqos->partition.n; i++) { - DDS_CLOG (cat, logcfg, "%s%s", (i == 0) ? "" : ",", xqos->partition.strs[i]); - } - DDS_CLOG (cat, logcfg, "}"); - }); - DO (GROUP_DATA, { - LOGB1 ("group_data=%"PRIu32"<", xqos->group_data.length); - 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, 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_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, { 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, { 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, 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, { 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, { - 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, { - LOGB1 ("subscription_keys={%u,{", xqos->subscription_keys.use_key_list); - 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_CLOG (cat, logcfg, "}}"); - }); - DO (PRISMTECH_ENTITY_FACTORY, { LOGB1 ("entity_factory=%u", xqos->entity_factory.autoenable_created_entities); }); - DO (CYCLONE_IGNORELOCAL, { LOGB1 ("ignorelocal=%u", xqos->ignorelocal.value); }); - DO (PROPERTY_LIST, { - LOGB0 ("property_list={"); - DDS_CLOG (cat, logcfg, "value={"); - for (uint32_t i = 0; i < xqos->property.value.n; i++) { - DDS_CLOG (cat, logcfg, "%s{%s,%s,%u}", - (i == 0) ? "" : ",", - xqos->property.value.props[i].name, - xqos->property.value.props[i].value, - xqos->property.value.props[i].propagate); - } - DDS_CLOG (cat, logcfg, "}"); - DDS_CLOG (cat, logcfg, "binary_value={"); - for (uint32_t i = 0; i < xqos->property.binary_value.n; i++) { - DDS_CLOG (cat, logcfg, "%s{%s,(%u,%p),%u}", - (i == 0) ? "" : ",", - xqos->property.binary_value.props[i].name, - xqos->property.binary_value.props[i].value.length, - xqos->property.binary_value.props[i].value.value, - xqos->property.binary_value.props[i].propagate); - } - DDS_CLOG (cat, logcfg, "}"); - DDS_CLOG (cat, logcfg, "}"); - }); - -#undef PRINTARG_DUR -#undef FMT_DUR -#undef DO -#undef LOGB5 -#undef LOGB4 -#undef LOGB3 -#undef LOGB2 -#undef LOGB1 -#undef LOGB0 + if (logcfg->c.mask & cat) + { + char tmp[2048], *ptmp = tmp; + size_t tmpsize = sizeof (tmp); + plist_or_xqos_print (&ptmp, &tmpsize, src, shift, pwanted, qwanted); + DDS_CLOG (cat, logcfg, "%s", tmp); + } +} + +size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos) +{ + const size_t bufsize_in = bufsize; + (void) prtf (&buf, &bufsize, "{"); + plist_or_xqos_print (&buf, &bufsize, xqos, offsetof (ddsi_plist_t, qos), 0, ~(uint64_t)0); + (void) prtf (&buf, &bufsize, "}"); + return bufsize_in - bufsize; +} + +size_t ddsi_plist_print (char * __restrict buf, size_t bufsize, const ddsi_plist_t *plist) +{ + const size_t bufsize_in = bufsize; + (void) prtf (&buf, &bufsize, "{"); + plist_or_xqos_print (&buf, &bufsize, plist, 0, ~(uint64_t)0, ~(uint64_t)0); + (void) prtf (&buf, &bufsize, "}"); + return bufsize_in - bufsize; +} + +void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos) +{ + plist_or_xqos_log (cat, logcfg, xqos, offsetof (ddsi_plist_t, qos), 0, ~(uint64_t)0); +} + +void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist) +{ + plist_or_xqos_log (cat, logcfg, plist, 0, ~(uint64_t)0, ~(uint64_t)0); } diff --git a/src/core/ddsi/src/ddsi_pmd.c b/src/core/ddsi/src/ddsi_pmd.c index 198bc27..9a6df62 100644 --- a/src/core/ddsi/src/ddsi_pmd.c +++ b/src/core/ddsi/src/ddsi_pmd.c @@ -18,7 +18,7 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/ddsi_entity_index.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_lease.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_misc.h" @@ -31,7 +31,7 @@ #include "dds/ddsi/sysdeps.h" -static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len) +static void debug_print_rawdata (const struct ddsi_domaingv *gv, const char *msg, const void *data, size_t len) { const unsigned char *c = data; size_t i; @@ -46,22 +46,27 @@ static void debug_print_rawdata (const struct q_globals *gv, const char *msg, co GVTRACE (">"); } -void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind) +void write_pmd_message_guid (struct ddsi_domaingv * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind) { struct thread_state1 * const ts1 = lookup_thread_state (); + struct lease *lease; thread_state_awake (ts1, gv); struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, pp_guid); if (pp == NULL) GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (*pp_guid)); else + { + if ((lease = ddsrt_atomic_ldvoidp (&pp->minl_man)) != NULL) + lease_renew (lease, now_et()); write_pmd_message (ts1, NULL, pp, pmd_kind); + } thread_state_asleep (ts1); } 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 ddsi_domaingv * const gv = pp->e.gv; struct writer *wr; union { ParticipantMessageData_t pmd; diff --git a/src/core/ddsi/src/ddsi_raweth.c b/src/core/ddsi/src/ddsi_raweth.c index e3454f9..1f7ed6a 100644 --- a/src/core/ddsi/src/ddsi_raweth.c +++ b/src/core/ddsi/src/ddsi_raweth.c @@ -17,7 +17,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_pcap.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" @@ -38,9 +38,8 @@ typedef struct ddsi_raweth_conn { int m_ifindex; } *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) +static char *ddsi_raweth_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) { - (void)tran; if (with_port) (void) snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]:%u", loc->address[10], loc->address[11], loc->address[12], @@ -80,6 +79,7 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf { if (srcloc) { + srcloc->tran = conn->m_factory; srcloc->kind = NN_LOCATOR_KIND_RAWETH; srcloc->port = ntohs (src.sll_protocol); memset(srcloc->address, 0, 10); @@ -305,9 +305,8 @@ 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, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) +static enum ddsi_nearby_address_result ddsi_raweth_is_nearby_address (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; @@ -319,6 +318,7 @@ static enum ddsi_locator_from_string_result ddsi_raweth_address_from_string (dds { int i = 0; (void)tran; + loc->tran = tran; loc->kind = NN_LOCATOR_KIND_RAWETH; loc->port = NN_LOCATOR_PORT_INVALID; memset (loc->address, 0, sizeof (loc->address)); @@ -362,7 +362,7 @@ static int ddsi_raweth_is_valid_port (ddsi_tran_factory_t fact, uint32_t port) return (port >= 1 && port <= 65535); } -int ddsi_raweth_init (struct q_globals *gv) +int ddsi_raweth_init (struct ddsi_domaingv *gv) { struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact)); memset (fact, 0, sizeof (*fact)); @@ -391,6 +391,6 @@ int ddsi_raweth_init (struct q_globals *gv) #else -int ddsi_raweth_init (struct q_globals *gv) { (void) gv; return 0; } +int ddsi_raweth_init (struct ddsi_domaingv *gv) { (void) gv; return 0; } #endif /* defined __linux */ diff --git a/src/core/ddsi/src/ddsi_security_msg.c b/src/core/ddsi/src/ddsi_security_msg.c index d67aa65..a0bbe77 100644 --- a/src/core/ddsi/src/ddsi_security_msg.c +++ b/src/core/ddsi/src/ddsi_security_msg.c @@ -14,7 +14,7 @@ #include "dds/ddsrt/md5.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_transmit.h" @@ -164,7 +164,7 @@ write_crypto_exchange_message( const char *classid, const nn_dataholderseq_t *tokens) { - struct q_globals * const gv = pp->e.gv; + struct ddsi_domaingv * const gv = pp->e.gv; struct nn_participant_generic_message pmg; struct ddsi_tkmap_instance *tk; struct ddsi_serdata *serdata; diff --git a/src/core/ddsi/src/ddsi_security_omg.c b/src/core/ddsi/src/ddsi_security_omg.c index c08b649..f118f41 100644 --- a/src/core/ddsi/src/ddsi_security_omg.c +++ b/src/core/ddsi/src/ddsi_security_omg.c @@ -34,7 +34,7 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_xevent.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #define AUTH_NAME "Authentication" #define AC_NAME "Access Control" @@ -399,7 +399,7 @@ void q_omg_security_deregister_remote_participant (struct proxy_participant *pro DDSRT_UNUSED_ARG (proxypp); } -bool is_proxy_participant_deletion_allowed (struct q_globals * const gv, const struct ddsi_guid *guid, const ddsi_entityid_t pwr_entityid) +bool is_proxy_participant_deletion_allowed (struct ddsi_domaingv * const gv, const struct ddsi_guid *guid, const ddsi_entityid_t pwr_entityid) { struct proxy_participant *proxypp; @@ -509,7 +509,7 @@ bool q_omg_security_is_local_rtps_protected (const struct participant *pp, ddsi_ return false; } -void set_proxy_participant_security_info (struct proxy_participant *proxypp, const nn_plist_t *plist) +void set_proxy_participant_security_info (struct proxy_participant *proxypp, const ddsi_plist_t *plist) { assert (proxypp); assert (plist); @@ -522,7 +522,7 @@ void set_proxy_participant_security_info (struct proxy_participant *proxypp, con } } -static void q_omg_get_proxy_endpoint_security_info (const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const nn_plist_t *plist, nn_security_info_t *info) +static void q_omg_get_proxy_endpoint_security_info (const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const ddsi_plist_t *plist, nn_security_info_t *info) { const bool proxypp_info_available = (proxypp_sec_info->security_attributes != 0 || proxypp_sec_info->plugin_security_attributes != 0); @@ -600,13 +600,13 @@ static void q_omg_get_proxy_endpoint_security_info (const struct entity_common * } } -void set_proxy_reader_security_info (struct proxy_reader *prd, const nn_plist_t *plist) +void set_proxy_reader_security_info (struct proxy_reader *prd, const ddsi_plist_t *plist) { assert (prd); q_omg_get_proxy_endpoint_security_info (&prd->e, &prd->c.proxypp->security_info, plist, &prd->c.security_info); } -void set_proxy_writer_security_info (struct proxy_writer *pwr, const nn_plist_t *plist) +void set_proxy_writer_security_info (struct proxy_writer *pwr, const ddsi_plist_t *plist) { assert (pwr); q_omg_get_proxy_endpoint_security_info (&pwr->e, &pwr->c.proxypp->security_info, plist, &pwr->c.security_info); @@ -736,7 +736,7 @@ bool encode_payload (struct writer *wr, ddsrt_iovec_t *vec, unsigned char **buf) } -static bool decode_payload (const struct q_globals *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t *payloadsz, size_t *submsg_len) +static bool decode_payload (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t *payloadsz, size_t *submsg_len) { assert (payloadp); assert (payloadsz); @@ -772,7 +772,7 @@ static bool decode_payload (const struct q_globals *gv, struct nn_rsample_info * return true; } -bool decode_Data (const struct q_globals *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) +bool decode_Data (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) { /* Only decode when there's actual data. */ if (payloadp == NULL || payloadsz == 0) @@ -787,7 +787,7 @@ bool decode_Data (const struct q_globals *gv, struct nn_rsample_info *sampleinfo } } -bool decode_DataFrag (const struct q_globals *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) +bool decode_DataFrag (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) { /* Only decode when there's actual data; do not touch the sampleinfo->size in contradiction to decode_Data() (it has been calculated differently). */ @@ -899,7 +899,7 @@ bool validate_msg_decoding (const struct entity_common *e, const struct proxy_en return true; } -static int32_t validate_submsg (struct q_globals *gv, SubmessageKind_t smid, const unsigned char *submsg, unsigned char const * const end, int byteswap) +static int32_t validate_submsg (struct ddsi_domaingv *gv, SubmessageKind_t smid, const unsigned char *submsg, unsigned char const * const end, int byteswap) { assert (end >= submsg); if ((size_t) (end - submsg) < RTPS_SUBMESSAGE_HEADER_SIZE) @@ -927,7 +927,7 @@ static int32_t validate_submsg (struct q_globals *gv, SubmessageKind_t smid, con return result; } -static int32_t padding_submsg (struct q_globals *gv, unsigned char *start, unsigned char *end, int byteswap) +static int32_t padding_submsg (struct ddsi_domaingv *gv, unsigned char *start, unsigned char *end, int byteswap) { assert (end >= start); const size_t size = (size_t) (end - start); @@ -1039,7 +1039,7 @@ bool decode_SecPrefix (const struct receiver_state *rst, unsigned char *submsg, return result; } -static nn_rtps_msg_state_t check_rtps_message_is_secure (struct q_globals *gv, Header_t *hdr, const unsigned char *buff, bool isstream, struct proxy_participant **proxypp) +static nn_rtps_msg_state_t check_rtps_message_is_secure (struct ddsi_domaingv *gv, Header_t *hdr, const unsigned char *buff, bool isstream, struct proxy_participant **proxypp) { const uint32_t offset = RTPS_MESSAGE_HEADER_SIZE + (isstream ? sizeof (MsgLen_t) : 0); const SubmessageHeader_t *submsg = (const SubmessageHeader_t *) (buff + offset); @@ -1127,7 +1127,7 @@ decode_rtps_message_awake ( nn_rtps_msg_state_t decode_rtps_message ( struct thread_state1 * const ts1, - struct q_globals *gv, + struct ddsi_domaingv *gv, struct nn_rmsg **rmsg, Header_t **hdr, unsigned char **buff, @@ -1274,7 +1274,7 @@ extern inline unsigned determine_publication_writer( UNUSED_ARG(const struct writer *wr)); extern inline bool is_proxy_participant_deletion_allowed( - UNUSED_ARG(struct q_globals * const gv), + UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const struct ddsi_guid *guid), UNUSED_ARG(const ddsi_entityid_t pwr_entityid)); @@ -1298,25 +1298,25 @@ extern inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct part extern inline void set_proxy_participant_security_info( UNUSED_ARG(struct proxy_participant *prd), - UNUSED_ARG(const nn_plist_t *plist)); + UNUSED_ARG(const ddsi_plist_t *plist)); extern inline void set_proxy_reader_security_info( UNUSED_ARG(struct proxy_reader *prd), - UNUSED_ARG(const nn_plist_t *plist)); + UNUSED_ARG(const ddsi_plist_t *plist)); extern inline void set_proxy_writer_security_info( UNUSED_ARG(struct proxy_writer *pwr), - UNUSED_ARG(const nn_plist_t *plist)); + UNUSED_ARG(const ddsi_plist_t *plist)); extern inline bool decode_Data( - UNUSED_ARG(const struct q_globals *gv), + UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rsample_info *sampleinfo), UNUSED_ARG(unsigned char *payloadp), UNUSED_ARG(uint32_t payloadsz), UNUSED_ARG(size_t *submsg_len)); extern inline bool decode_DataFrag( - UNUSED_ARG(const struct q_globals *gv), + UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rsample_info *sampleinfo), UNUSED_ARG(unsigned char *payloadp), UNUSED_ARG(uint32_t payloadsz), @@ -1351,7 +1351,7 @@ extern inline int decode_SecPrefix( extern inline nn_rtps_msg_state_t decode_rtps_message( UNUSED_ARG(struct thread_state1 * const ts1), - UNUSED_ARG(struct q_globals *gv), + UNUSED_ARG(struct ddsi_domaingv *gv), UNUSED_ARG(struct nn_rmsg **rmsg), UNUSED_ARG(Header_t **hdr), UNUSED_ARG(unsigned char **buff), diff --git a/src/core/ddsi/src/ddsi_serdata.c b/src/core/ddsi/src/ddsi_serdata.c index 33d9584..97e43c2 100644 --- a/src/core/ddsi/src/ddsi_serdata.c +++ b/src/core/ddsi/src/ddsi_serdata.c @@ -36,6 +36,7 @@ extern inline struct ddsi_serdata *ddsi_serdata_ref (const struct ddsi_serdata * extern inline void ddsi_serdata_unref (struct ddsi_serdata *serdata); extern inline uint32_t ddsi_serdata_size (const struct ddsi_serdata *d); extern inline struct ddsi_serdata *ddsi_serdata_from_ser (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size); +extern inline struct ddsi_serdata *ddsi_serdata_from_ser_iov (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size); extern inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash); extern inline struct ddsi_serdata *ddsi_serdata_from_sample (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, const void *sample); extern inline struct ddsi_serdata *ddsi_serdata_to_topicless (const struct ddsi_serdata *d); diff --git a/src/core/ddsi/src/ddsi_serdata_default.c b/src/core/ddsi/src/ddsi_serdata_default.c index 34f88e9..f89e30c 100644 --- a/src/core/ddsi/src/ddsi_serdata_default.c +++ b/src/core/ddsi/src/ddsi_serdata_default.c @@ -17,13 +17,14 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" #include "dds/ddsi/ddsi_tkmap.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/q_radmin.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_serdata_default.h" #if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN @@ -117,59 +118,10 @@ static void serdata_default_append_blob (struct ddsi_serdata_default **d, size_t memcpy (p, data, sz); } -/* Fixed seed and length */ - -#define DDS_MH3_LEN 16 -#define DDS_MH3_SEED 0 - -#define DDS_MH3_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) - -/* Really - http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, - MurmurHash3_x86_32 - */ - -static uint32_t dds_mh3 (const void * key) -{ - const uint8_t *data = (const uint8_t *) key; - const intptr_t nblocks = (intptr_t) (DDS_MH3_LEN / 4); - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - uint32_t h1 = DDS_MH3_SEED; - - const uint32_t *blocks = (const uint32_t *) (data + nblocks * 4); - register intptr_t i; - - for (i = -nblocks; i; i++) - { - uint32_t k1 = blocks[i]; - - k1 *= c1; - k1 = DDS_MH3_ROTL32 (k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = DDS_MH3_ROTL32 (h1, 13); - h1 = h1 * 5+0xe6546b64; - } - - /* finalization */ - - h1 ^= DDS_MH3_LEN; - h1 ^= h1 >> 16; - h1 *= 0x85ebca6b; - h1 ^= h1 >> 13; - h1 *= 0xc2b2ae35; - h1 ^= h1 >> 16; - - return h1; -} - static struct ddsi_serdata *fix_serdata_default(struct ddsi_serdata_default *d, uint32_t basehash) { if (d->keyhash.m_iskey) - d->c.hash = dds_mh3 (d->keyhash.m_hash) ^ basehash; + d->c.hash = ddsrt_mh3 (d->keyhash.m_hash, 16, 0) ^ basehash; else d->c.hash = *((uint32_t *)d->keyhash.m_hash) ^ basehash; return &d->c; @@ -317,6 +269,51 @@ static struct ddsi_serdata_default *serdata_default_from_ser_common (const struc } } +static struct ddsi_serdata_default *serdata_default_from_ser_iov_common (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) +{ + const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; + + /* 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; + assert (niov >= 1); + if (iov[0].iov_len < 4) /* CDR header */ + return NULL; + struct ddsi_serdata_default *d = serdata_default_new_size (tp, kind, (uint32_t) size); + if (d == NULL) + return NULL; + + memcpy (&d->hdr, iov[0].iov_base, sizeof (d->hdr)); + assert (d->hdr.identifier == CDR_LE || d->hdr.identifier == CDR_BE); + serdata_default_append_blob (&d, 1, iov[0].iov_len - 4, (const char *) iov[0].iov_base + 4); + for (ddsrt_msg_iovlen_t i = 1; i < niov; i++) + serdata_default_append_blob (&d, 1, iov[i].iov_len, iov[i].iov_base); + + const bool needs_bswap = (d->hdr.identifier != NATIVE_ENCODING); + d->hdr.identifier = NATIVE_ENCODING; + const uint32_t pad = ddsrt_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) { struct ddsi_serdata_default *d; @@ -325,6 +322,14 @@ static struct ddsi_serdata *serdata_default_from_ser (const struct ddsi_sertopic return fix_serdata_default (d, tpcmn->serdata_basehash); } +static struct ddsi_serdata *serdata_default_from_ser_iov (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) +{ + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_ser_iov_common (tpcmn, kind, niov, iov, 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) { struct ddsi_serdata_default *d; @@ -333,11 +338,19 @@ static struct ddsi_serdata *serdata_default_from_ser_nokey (const struct ddsi_se return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); } +static struct ddsi_serdata *serdata_default_from_ser_iov_nokey (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) +{ + struct ddsi_serdata_default *d; + if ((d = serdata_default_from_ser_iov_common (tpcmn, kind, niov, iov, size)) == NULL) + return NULL; + return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); +} + 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; - if (!(tp->type->m_flagset & DDS_TOPIC_FIXED_KEY)) + if (!(tp->type.m_flagset & DDS_TOPIC_FIXED_KEY)) { /* keyhash is MD5 of a key value, so impossible to turn into a key value */ return NULL; @@ -376,7 +389,7 @@ static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct dd 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; + const struct ddsi_sertopic_default_desc *desc = &topic->type; kh->m_set = 1; if (desc->m_nkeys == 0) { @@ -457,7 +470,7 @@ static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi 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); + const unsigned char *rawkey = ddsi_plist_findparam_native_unchecked (sample->blob, sample->keyparam); #ifndef NDEBUG size_t keysize; #endif @@ -658,10 +671,27 @@ static size_t serdata_default_print_cdr (const struct ddsi_sertopic *sertopic_co static size_t serdata_default_print_plist (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) { - /* FIXME: should change q_plist.c to print to a string instead of a log, and then drop the - logging of QoS in the rest of code, instead relying on this */ - (void)sertopic_common; (void)serdata_common; - return (size_t) snprintf (buf, size, "(plist)"); + const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; + const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; + ddsi_plist_src_t src; + ddsi_plist_t tmp; + src.buf = (const unsigned char *) d->data; + src.bufsz = d->pos; + src.encoding = d->hdr.identifier; + src.factory = tp->c.gv->m_factory; + src.logconfig = &tp->c.gv->logconfig; + src.protocol_version.major = RTPS_MAJOR; + src.protocol_version.minor = RTPS_MINOR; + src.strict = false; + src.vendorid = NN_VENDORID_ECLIPSE; + if (ddsi_plist_init_frommsg (&tmp, NULL, ~(uint64_t)0, ~(uint64_t)0, &src) < 0) + return (size_t) snprintf (buf, size, "(unparseable-plist)"); + else + { + size_t ret = ddsi_plist_print (buf, size, &tmp); + ddsi_plist_fini (&tmp); + return ret; + } } static size_t serdata_default_print_raw (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) @@ -693,6 +723,7 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = { .eqkey = serdata_default_eqkey, .free = serdata_default_free, .from_ser = serdata_default_from_ser, + .from_ser_iov = serdata_default_from_ser_iov, .from_keyhash = ddsi_serdata_from_keyhash_cdr, .from_sample = serdata_default_from_sample_cdr, .to_ser = serdata_default_to_ser, @@ -710,6 +741,7 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = { .eqkey = serdata_default_eqkey_nokey, .free = serdata_default_free, .from_ser = serdata_default_from_ser_nokey, + .from_ser_iov = serdata_default_from_ser_iov_nokey, .from_keyhash = ddsi_serdata_from_keyhash_cdr_nokey, .from_sample = serdata_default_from_sample_cdr_nokey, .to_ser = serdata_default_to_ser, @@ -727,6 +759,7 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_plist = { .eqkey = serdata_default_eqkey, .free = serdata_default_free, .from_ser = serdata_default_from_ser, + .from_ser_iov = serdata_default_from_ser_iov, .from_keyhash = 0, .from_sample = serdata_default_from_sample_plist, .to_ser = serdata_default_to_ser, @@ -744,6 +777,7 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = { .eqkey = serdata_default_eqkey, .free = serdata_default_free, .from_ser = serdata_default_from_ser, + .from_ser_iov = serdata_default_from_ser_iov, .from_keyhash = 0, .from_sample = serdata_default_from_sample_rawcdr, .to_ser = serdata_default_to_ser, diff --git a/src/core/ddsi/src/ddsi_sertopic.c b/src/core/ddsi/src/ddsi_sertopic.c index 968a1de..8776ede 100644 --- a/src/core/ddsi/src/ddsi_sertopic.c +++ b/src/core/ddsi/src/ddsi_sertopic.c @@ -16,6 +16,8 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" +#include "dds/ddsrt/hopscotch.h" #include "dds/ddsrt/string.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" @@ -23,21 +25,79 @@ #include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_domaingv.h" + +bool ddsi_sertopic_equal (const struct ddsi_sertopic *a, const struct ddsi_sertopic *b) +{ + if (strcmp (a->name, b->name) != 0) + return false; + if (strcmp (a->type_name, b->type_name) != 0) + return false; + if (a->serdata_basehash != b->serdata_basehash) + return false; + if (a->ops != b->ops) + return false; + if (a->serdata_ops != b->serdata_ops) + return false; + if (a->topickind_no_key != b->topickind_no_key) + return false; + return a->ops->equal (a, b); +} + +uint32_t ddsi_sertopic_hash (const struct ddsi_sertopic *a) +{ + uint32_t h; + h = ddsrt_mh3 (a->name, strlen (a->name), a->serdata_basehash); + h = ddsrt_mh3 (a->type_name, strlen (a->type_name), h); + h ^= a->serdata_basehash ^ (uint32_t) a->topickind_no_key; + return h ^ a->ops->hash (a); +} struct ddsi_sertopic *ddsi_sertopic_ref (const struct ddsi_sertopic *sertopic_const) { - struct ddsi_sertopic *sertopic = (struct ddsi_sertopic *)sertopic_const; + struct ddsi_sertopic *sertopic = (struct ddsi_sertopic *) sertopic_const; if (sertopic) ddsrt_atomic_inc32 (&sertopic->refc); return sertopic; } +struct ddsi_sertopic *ddsi_sertopic_lookup_locked (struct ddsi_domaingv *gv, const struct ddsi_sertopic *sertopic_template) +{ + struct ddsi_sertopic *sertopic = ddsrt_hh_lookup (gv->sertopics, sertopic_template); +#ifndef NDEBUG + if (sertopic != NULL) + assert (sertopic->gv != NULL); +#endif + return ddsi_sertopic_ref (sertopic); +} + +void ddsi_sertopic_register_locked (struct ddsi_domaingv *gv, struct ddsi_sertopic *sertopic) +{ + assert (sertopic->gv == NULL); + assert (ddsrt_atomic_ld32 (&sertopic->refc) == 1); + + (void) ddsi_sertopic_ref (sertopic); + sertopic->gv = gv; + int x = ddsrt_hh_add (gv->sertopics, sertopic); + assert (x); + (void) x; +} + void ddsi_sertopic_unref (struct ddsi_sertopic *sertopic) { if (sertopic) { if (ddsrt_atomic_dec32_ov (&sertopic->refc) == 1) { + /* if registered, drop from set of registered sertopics */ + if (sertopic->gv) + { + ddsrt_mutex_lock (&sertopic->gv->sertopics_lock); + (void) ddsrt_hh_remove (sertopic->gv->sertopics, sertopic); + ddsrt_mutex_unlock (&sertopic->gv->sertopics_lock); + sertopic->gv = NULL; + } + ddsi_sertopic_free (sertopic); } } @@ -46,36 +106,20 @@ 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; + /* set later, on registration */ + tp->gv = NULL; } 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) diff --git a/src/core/ddsi/src/ddsi_sertopic_default.c b/src/core/ddsi/src/ddsi_sertopic_default.c index 0fbfec6..a10cb96 100644 --- a/src/core/ddsi/src/ddsi_sertopic_default.c +++ b/src/core/ddsi/src/ddsi_sertopic_default.c @@ -15,29 +15,71 @@ #include #include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_serdata_default.h" -static void sertopic_default_free (struct ddsi_sertopic *tp) +static bool sertopic_default_equal (const struct ddsi_sertopic *acmn, const struct ddsi_sertopic *bcmn) { - ddsi_sertopic_fini (tp); + const struct ddsi_sertopic_default *a = (struct ddsi_sertopic_default *) acmn; + const struct ddsi_sertopic_default *b = (struct ddsi_sertopic_default *) bcmn; + if (a->native_encoding_identifier != b->native_encoding_identifier) + return false; + if (a->type.m_size != b->type.m_size) + return false; + if (a->type.m_align != b->type.m_align) + return false; + if (a->type.m_flagset != b->type.m_flagset) + return false; + if (a->type.m_nkeys != b->type.m_nkeys) + return false; + if (memcmp (a->type.m_keys, b->type.m_keys, a->type.m_nkeys * sizeof (*a->type.m_keys)) != 0) + return false; + if (a->type.m_nops != b->type.m_nops) + return false; + if (memcmp (a->type.m_ops, b->type.m_ops, a->type.m_nops * sizeof (*a->type.m_ops)) != 0) + return false; + assert (a->opt_size == b->opt_size); + return true; +} + +static uint32_t sertopic_default_hash (const struct ddsi_sertopic *tpcmn) +{ + const struct ddsi_sertopic_default *tp = (struct ddsi_sertopic_default *) tpcmn; + uint32_t h = 0; + h = ddsrt_mh3 (&tp->native_encoding_identifier, sizeof (tp->native_encoding_identifier), 0); + h = ddsrt_mh3 (&tp->type.m_size, sizeof (tp->type.m_size), h); + h = ddsrt_mh3 (&tp->type.m_align, sizeof (tp->type.m_align), h); + h = ddsrt_mh3 (&tp->type.m_flagset, sizeof (tp->type.m_flagset), h); + h = ddsrt_mh3 (tp->type.m_keys, tp->type.m_nkeys * sizeof (*tp->type.m_keys), h); + h = ddsrt_mh3 (tp->type.m_ops, tp->type.m_nops * sizeof (*tp->type.m_ops), h); + return h; +} + +static void sertopic_default_free (struct ddsi_sertopic *tpcmn) +{ + struct ddsi_sertopic_default *tp = (struct ddsi_sertopic_default *) tpcmn; + ddsrt_free (tp->type.m_keys); + ddsrt_free (tp->type.m_ops); + ddsi_sertopic_fini (&tp->c); ddsrt_free (tp); } static void sertopic_default_zero_samples (const struct ddsi_sertopic *sertopic_common, void *sample, size_t count) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; - memset (sample, 0, tp->type->m_size * count); + memset (sample, 0, tp->type.m_size * count); } static void sertopic_default_realloc_samples (void **ptrs, const struct ddsi_sertopic *sertopic_common, void *old, size_t oldcount, size_t count) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; - const size_t size = tp->type->m_size; + const size_t size = tp->type.m_size; char *new = (oldcount == count) ? old : dds_realloc (old, size * count); if (new && count > oldcount) memset (new + size * oldcount, 0, size * (count - oldcount)); @@ -53,7 +95,7 @@ static void sertopic_default_free_samples (const struct ddsi_sertopic *sertopic_ if (count > 0) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; - const struct dds_topic_descriptor *type = tp->type; + const struct ddsi_sertopic_default_desc *type = &tp->type; const size_t size = type->m_size; #ifndef NDEBUG for (size_t i = 0, off = 0; i < count; i++, off += size) @@ -64,7 +106,7 @@ static void sertopic_default_free_samples (const struct ddsi_sertopic *sertopic_ char *ptr = ptrs[0]; for (size_t i = 0; i < count; i++) { - dds_sample_free (ptr, type, DDS_FREE_CONTENTS); + dds_stream_free_sample (ptr, type->m_ops); ptr += size; } } @@ -76,6 +118,8 @@ static void sertopic_default_free_samples (const struct ddsi_sertopic *sertopic_ } const struct ddsi_sertopic_ops ddsi_sertopic_ops_default = { + .equal = sertopic_default_equal, + .hash = sertopic_default_hash, .free = sertopic_default_free, .zero_samples = sertopic_default_zero_samples, .realloc_samples = sertopic_default_realloc_samples, diff --git a/src/core/ddsi/src/ddsi_ssl.c b/src/core/ddsi/src/ddsi_ssl.c index e8abd98..bbbf19b 100644 --- a/src/core/ddsi/src/ddsi_ssl.c +++ b/src/core/ddsi/src/ddsi_ssl.c @@ -28,7 +28,7 @@ #include "dds/ddsrt/sockets.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" static SSL_CTX *ddsi_ssl_ctx = NULL; static bool ddsi_ssl_allow_self_signed_hack = false; @@ -38,7 +38,7 @@ static SSL *ddsi_ssl_new (void) return SSL_new (ddsi_ssl_ctx); } -static void ddsi_ssl_error (const struct q_globals *gv, SSL *ssl, const char *str, int err) +static void ddsi_ssl_error (const struct ddsi_domaingv *gv, SSL *ssl, const char *str, int err) { char buff[128]; ERR_error_string ((unsigned) SSL_get_error (ssl, err), buff); @@ -178,7 +178,7 @@ 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; + struct ddsi_domaingv *gv = udata; (void) rwflag; if (num < 0 || (size_t) num < strlen (gv->config.ssl_key_pass) + 1) return 0; @@ -188,7 +188,7 @@ static int ddsi_ssl_password (char *buf, int num, int rwflag, void *udata) return (int) strlen (gv->config.ssl_key_pass); } -static SSL_CTX *ddsi_ssl_ctx_init (struct q_globals *gv) +static SSL_CTX *ddsi_ssl_ctx_init (struct ddsi_domaingv *gv) { SSL_CTX *ctx = SSL_CTX_new (SSLv23_method ()); unsigned disallow_TLSv1_2; @@ -281,7 +281,7 @@ fail: return NULL; } -static void dds_report_tls_version (const struct q_globals *gv, const SSL *ssl, const char *oper) +static void dds_report_tls_version (const struct ddsi_domaingv *gv, const SSL *ssl, const char *oper) { if (ssl) { @@ -292,7 +292,7 @@ static void dds_report_tls_version (const struct q_globals *gv, const SSL *ssl, } } -static SSL *ddsi_ssl_connect (const struct q_globals *gv, ddsrt_socket_t sock) +static SSL *ddsi_ssl_connect (const struct ddsi_domaingv *gv, ddsrt_socket_t sock) { SSL *ssl; int err; @@ -326,7 +326,7 @@ static BIO *ddsi_ssl_listen (ddsrt_socket_t sock) return bio; } -static SSL *ddsi_ssl_accept (const struct q_globals *gv, BIO *bio, ddsrt_socket_t *sock) +static SSL *ddsi_ssl_accept (const struct ddsi_domaingv *gv, BIO *bio, ddsrt_socket_t *sock) { SSL *ssl = NULL; BIO *nbio; @@ -350,7 +350,7 @@ static SSL *ddsi_ssl_accept (const struct q_globals *gv, BIO *bio, ddsrt_socket_ return ssl; } -static bool ddsi_ssl_init (struct q_globals *gv) +static bool ddsi_ssl_init (struct ddsi_domaingv *gv) { /* FIXME: allocate this stuff ... don't copy gv into a global variable ... */ ERR_load_BIO_strings (); diff --git a/src/core/ddsi/src/ddsi_tcp.c b/src/core/ddsi/src/ddsi_tcp.c index 47ff028..e46bfc9 100644 --- a/src/core/ddsi/src/ddsi_tcp.c +++ b/src/core/ddsi/src/ddsi_tcp.c @@ -25,7 +25,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #define INVALID_PORT (~0u) @@ -100,11 +100,11 @@ static const ddsrt_avl_treedef_t ddsi_tcp_treedef = DDSRT_AVL_TREEDEF_INITIALIZE static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, ddsrt_socket_t, bool, struct sockaddr *); -static char *sockaddr_to_string_with_port (const struct q_globals *gv, char *dst, size_t sizeof_dst, const struct sockaddr *src) +static char *sockaddr_to_string_with_port (struct ddsi_tran_factory_tcp *fact, 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(gv, dst, sizeof_dst, &loc); + ddsi_ipaddr_to_loc(&fact->fact, &loc, src, src->sa_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); + ddsi_locator_to_string(dst, sizeof_dst, &loc); return dst; } @@ -165,7 +165,7 @@ static void ddsi_tcp_sock_free (const struct ddsrt_log_cfg *logcfg, ddsrt_socket } } -static void ddsi_tcp_sock_new (ddsrt_socket_t *sock, unsigned short port, const struct q_globals *gv) +static void ddsi_tcp_sock_new (ddsrt_socket_t *sock, unsigned short port, const struct ddsi_domaingv *gv) { if (make_socket (sock, port, true, true, gv) != 0) { @@ -182,9 +182,7 @@ 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_return_t ret; @@ -219,7 +217,7 @@ static void ddsi_tcp_conn_connect (ddsi_tcp_conn_t conn, const ddsrt_msghdr_t * } #endif - sockaddr_to_string_with_port(conn->m_base.m_base.gv, buff, sizeof(buff), (struct sockaddr *) msg->msg_name); + sockaddr_to_string_with_port(fact, 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 */ @@ -267,7 +265,7 @@ static void ddsi_tcp_cache_add (struct ddsi_tran_factory_tcp *fact, ddsi_tcp_con } } - sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + sockaddr_to_string_with_port(fact, 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); } @@ -282,7 +280,7 @@ static void ddsi_tcp_cache_remove (ddsi_tcp_conn_t conn) node = ddsrt_avl_lookup_dpath (&ddsi_tcp_treedef, &fact->ddsi_tcp_cache_g, conn, &path); if (node) { - sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + sockaddr_to_string_with_port(fact, 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); @@ -383,9 +381,7 @@ static bool ddsi_tcp_select (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t 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) { -#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_return_t * err) = ddsi_tcp_conn_read_plain; @@ -409,7 +405,7 @@ static ssize_t ddsi_tcp_conn_read (ddsi_tran_conn_t conn, unsigned char *buf, si { if (srcloc) { - ddsi_ipaddr_to_loc(srcloc, (struct sockaddr *)&tcp->m_peer_addr, tcp->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); + ddsi_ipaddr_to_loc(&fact->fact, srcloc, (struct sockaddr *)&tcp->m_peer_addr, tcp->m_peer_addr.ss_family == AF_INET ? NN_LOCATOR_KIND_TCPv4 : NN_LOCATOR_KIND_TCPv6); } return (ssize_t) pos; } @@ -775,7 +771,7 @@ 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(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + sockaddr_to_string_with_port(fact, 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) @@ -785,7 +781,7 @@ static ddsi_tran_conn_t ddsi_tcp_accept (ddsi_tran_listener_t listener) } else { - sockaddr_to_string_with_port(fact->fact.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + sockaddr_to_string_with_port(fact, 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); @@ -822,8 +818,8 @@ static void ddsi_tcp_conn_peer_locator (ddsi_tran_conn_t conn, nn_locator_t * lo char buff[DDSI_LOCSTRLEN]; 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(conn->m_base.gv, buff, sizeof(buff), loc); + ddsi_ipaddr_to_loc (conn->m_factory, 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_CLOG (DDS_LC_TCP, &conn->m_base.gv->logconfig, "(tcp EP:%s)", buff); } @@ -863,6 +859,7 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, struct sockaddr_storage addr; socklen_t addrlen = sizeof (addr); ddsi_tcp_listener_t tl = NULL; + struct ddsi_tran_factory_tcp * const fact_tcp = (struct ddsi_tran_factory_tcp *) fact; (void) qos; @@ -894,7 +891,7 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, return NULL; } - sockaddr_to_string_with_port(fact->gv, buff, sizeof(buff), (struct sockaddr *)&addr); + sockaddr_to_string_with_port(fact_tcp, buff, sizeof(buff), (struct sockaddr *)&addr); DDS_CLOG (DDS_LC_TCP, &fact->gv->logconfig, "tcp create listener socket %"PRIdSOCK" on %s\n", sock, buff); } @@ -903,11 +900,9 @@ static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, 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(conn->m_base.m_base.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + sockaddr_to_string_with_port(fact, 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 @@ -932,10 +927,10 @@ static void ddsi_tcp_close_conn (ddsi_tran_conn_t tc) char buff[DDSI_LOCSTRLEN]; nn_locator_t loc; ddsi_tcp_conn_t conn = (ddsi_tcp_conn_t) tc; - sockaddr_to_string_with_port(tc->m_base.gv, buff, sizeof(buff), (struct sockaddr *)&conn->m_peer_addr); + sockaddr_to_string_with_port(fact_tcp, 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); + ddsi_ipaddr_to_loc(&fact_tcp->fact, &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 (conn->m_base.m_base.gv, &loc, conn->m_base.m_server); } @@ -993,8 +988,9 @@ static void ddsi_tcp_unblock_listener (ddsi_tran_listener_t listener) } while (ret == DDS_RETCODE_INTERRUPTED); if (ret != DDS_RETCODE_OK) { + struct ddsi_tran_factory_tcp * const fact = (struct ddsi_tran_factory_tcp *) listener->m_factory; char buff[DDSI_LOCSTRLEN]; - sockaddr_to_string_with_port(listener->m_base.gv, buff, sizeof(buff), (struct sockaddr *)&addr); + sockaddr_to_string_with_port(fact, 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); } } @@ -1050,9 +1046,9 @@ 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, const nn_locator_t *ownloc, size_t ninterf, const struct nn_interface interf[]) +static enum ddsi_nearby_address_result ddsi_tcp_is_nearby_address (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, ownloc, ninterf, interf); + return ddsi_ipaddr_is_nearby_address(loc, ownloc, ninterf, interf); } static int ddsi_tcp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port) @@ -1061,7 +1057,7 @@ static int ddsi_tcp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port) return (port <= 65535); } -int ddsi_tcp_init (struct q_globals *gv) +int ddsi_tcp_init (struct ddsi_domaingv *gv) { struct ddsi_tran_factory_tcp *fact = ddsrt_malloc (sizeof (*fact)); diff --git a/src/core/ddsi/src/ddsi_threadmon.c b/src/core/ddsi/src/ddsi_threadmon.c index 53139e9..2d1a453 100644 --- a/src/core/ddsi/src/ddsi_threadmon.c +++ b/src/core/ddsi/src/ddsi_threadmon.c @@ -22,7 +22,7 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_globals.h" /* for mattr, cattr */ +#include "dds/ddsi/ddsi_domaingv.h" /* for mattr, cattr */ #include "dds/ddsi/q_receive.h" struct alive_vt { @@ -31,7 +31,7 @@ struct alive_vt { }; struct threadmon_domain { - const struct q_globals *gv; + const struct ddsi_domaingv *gv; unsigned n_not_alive; size_t msgpos; char msg[2048]; @@ -51,7 +51,7 @@ struct ddsi_threadmon { struct ddsrt_hh *domains; }; -static struct threadmon_domain *find_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) +static struct threadmon_domain *find_domain (struct ddsi_threadmon *sl, const struct ddsi_domaingv *gv) { struct threadmon_domain dummy; dummy.gv = gv; @@ -101,7 +101,7 @@ static uint32_t threadmon_thread (struct ddsi_threadmon *sl) 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 ddsi_domaingv const * const gv = ddsrt_atomic_ldvoidp (&thread_states.ts[i].gv); struct threadmon_domain *tmdom = find_domain (sl, gv); if (tmdom == NULL) continue; @@ -238,7 +238,7 @@ dds_return_t ddsi_threadmon_start (struct ddsi_threadmon *sl, const char *name) return DDS_RETCODE_ERROR; } -void ddsi_threadmon_register_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) +void ddsi_threadmon_register_domain (struct ddsi_threadmon *sl, const struct ddsi_domaingv *gv) { if (gv->config.liveliness_monitoring) { @@ -256,7 +256,7 @@ void ddsi_threadmon_register_domain (struct ddsi_threadmon *sl, const struct q_g } } -void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct q_globals *gv) +void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct ddsi_domaingv *gv) { if (gv->config.liveliness_monitoring) { diff --git a/src/core/ddsi/src/ddsi_tkmap.c b/src/core/ddsi/src/ddsi_tkmap.c index c00d4aa..9b6324b 100644 --- a/src/core/ddsi/src/ddsi_tkmap.c +++ b/src/core/ddsi/src/ddsi_tkmap.c @@ -18,13 +18,13 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_gc.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/ddsi_tkmap.h" -#include "dds/ddsrt/hopscotch.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsrt/hopscotch.h" #define REFC_DELETE 0x80000000 #define REFC_MASK 0x0fffffff @@ -32,7 +32,7 @@ struct ddsi_tkmap { struct ddsrt_chh *m_hh; - struct q_globals *gv; + struct ddsi_domaingv *gv; ddsrt_mutex_t m_lock; ddsrt_cond_t m_cond; }; @@ -86,7 +86,7 @@ static int dds_tk_equals_void (const void *a, const void *b) return dds_tk_equals (a, b); } -struct ddsi_tkmap *ddsi_tkmap_new (struct q_globals *gv) +struct ddsi_tkmap *ddsi_tkmap_new (struct ddsi_domaingv *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); diff --git a/src/core/ddsi/src/ddsi_tran.c b/src/core/ddsi/src/ddsi_tran.c index 5350d58..2bdda5d 100644 --- a/src/core/ddsi/src/ddsi_tran.c +++ b/src/core/ddsi/src/ddsi_tran.c @@ -17,9 +17,10 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/ifaddrs.h" #include "dds/ddsi/ddsi_tran.h" +#include "dds/ddsi/ddsi_ipaddr.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" extern inline uint32_t ddsi_conn_type (ddsi_tran_conn_t conn); extern inline uint32_t ddsi_conn_port (ddsi_tran_conn_t conn); @@ -36,13 +37,13 @@ extern inline ddsi_tran_conn_t ddsi_listener_accept (ddsi_tran_listener_t listen 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 (struct q_globals *gv, ddsi_tran_factory_t factory) +void ddsi_factory_add (struct ddsi_domaingv *gv, ddsi_tran_factory_t factory) { factory->m_factory = gv->ddsi_tran_factories; gv->ddsi_tran_factories = factory; } -ddsi_tran_factory_t ddsi_factory_find (const struct q_globals *gv, const char *type) +ddsi_tran_factory_t ddsi_factory_find (const struct ddsi_domaingv *gv, const char *type) { /* FIXME: should speed up */ ddsi_tran_factory_t factory = gv->ddsi_tran_factories; @@ -59,7 +60,7 @@ ddsi_tran_factory_t ddsi_factory_find (const struct q_globals *gv, const char *t return factory; } -void ddsi_tran_factories_fini (struct q_globals *gv) +void ddsi_tran_factories_fini (struct ddsi_domaingv *gv) { ddsi_tran_factory_t factory; while ((factory = gv->ddsi_tran_factories) != NULL) @@ -72,7 +73,7 @@ void ddsi_tran_factories_fini (struct q_globals *gv) } } -static ddsi_tran_factory_t ddsi_factory_find_with_len (const struct q_globals *gv, const char *type, size_t len) +static ddsi_tran_factory_t ddsi_factory_find_with_len (const struct ddsi_domaingv *gv, const char *type, size_t len) { /* FIXME: should speed up */ ddsi_tran_factory_t factory = gv->ddsi_tran_factories; @@ -90,7 +91,7 @@ static ddsi_tran_factory_t ddsi_factory_find_with_len (const struct q_globals *g } ddsrt_attribute_no_sanitize (("thread")) -ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct q_globals *gv, int32_t kind) +ddsi_tran_factory_t ddsi_factory_find_supported_kind (const struct ddsi_domaingv *gv, int32_t kind) { /* FIXME: MUST speed up */ ddsi_tran_factory_t factory; @@ -236,13 +237,13 @@ void ddsi_listener_free (ddsi_tran_listener_t listener) } } -int ddsi_is_mcaddr (const struct q_globals *gv, const nn_locator_t *loc) +int ddsi_is_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc) { 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 struct q_globals *gv, const nn_locator_t *loc) +int ddsi_is_ssm_mcaddr (const struct ddsi_domaingv *gv, const nn_locator_t *loc) { ddsi_tran_factory_t tran = ddsi_factory_find_supported_kind(gv, loc->kind); if (tran && tran->m_is_ssm_mcaddr_fn != 0) @@ -250,13 +251,15 @@ int ddsi_is_ssm_mcaddr (const struct q_globals *gv, const nn_locator_t *loc) return 0; } -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_nearby_address_result ddsi_is_nearby_address (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(gv, loc->kind); - return tran ? tran->m_is_nearby_address_fn (tran, loc, ownloc, ninterf, interf) : DNAR_DISTANT; + if (loc->tran != ownloc->tran || loc->kind != ownloc->kind) + return DNAR_DISTANT; + else + return ownloc->tran->m_is_nearby_address_fn (loc, ownloc, ninterf, interf); } -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) +enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct ddsi_domaingv *gv, nn_locator_t *loc, const char *str, ddsi_tran_factory_t default_factory) { const char *sep = strchr(str, '/'); ddsi_tran_factory_t tran; @@ -277,29 +280,67 @@ enum ddsi_locator_from_string_result ddsi_locator_from_string (const struct q_gl return tran->m_locator_from_string_fn (tran, loc, sep ? sep + 1 : str); } -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 (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(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); - } else { + if (loc->kind == NN_LOCATOR_KIND_INVALID) { (void) snprintf (dst, sizeof_dst, "invalid/0:0"); + } else if (loc->tran != NULL) { + int pos = snprintf (dst, sizeof_dst, "%s/", loc->tran->m_typename); + if (0 < pos && (size_t)pos < sizeof_dst) + (void) loc->tran->m_locator_to_string_fn (dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 1); + } else { + /* Because IPv4 and IPv6 addresses are so common we special-case and print them in the usual form + even if they didn't get mapped to a transport. To indicate that this mapping never took place + the kind is still printed as a number, not as (udp|tcp)6? */ + switch (loc->kind) + { + case NN_LOCATOR_KIND_TCPv4: + case NN_LOCATOR_KIND_TCPv6: + case NN_LOCATOR_KIND_UDPv4: + case NN_LOCATOR_KIND_UDPv6: { + int pos = snprintf (dst, sizeof_dst, "%"PRId32"/", loc->kind); + if (0 < pos && (size_t)pos < sizeof_dst) + (void) ddsi_ipaddr_to_string (dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 1); + break; + } + default: { + const unsigned char * const x = loc->address; + (void) snprintf (dst, sizeof_dst, "%"PRId32"/[%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]:%"PRIu32, + loc->kind, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], loc->port); + break; + } + } } return dst; } -char *ddsi_locator_to_string_no_port (const struct q_globals *gv, 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) { - if (loc->kind != NN_LOCATOR_KIND_INVALID) { - 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); - } else { + if (loc->kind == NN_LOCATOR_KIND_INVALID) { (void) snprintf (dst, sizeof_dst, "invalid/0"); + } else if (loc->tran != NULL) { + int pos = snprintf (dst, sizeof_dst, "%s/", loc->tran->m_typename); + if (0 < pos && (size_t)pos < sizeof_dst) + (void) loc->tran->m_locator_to_string_fn (dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 0); + } else { + switch (loc->kind) + { + case NN_LOCATOR_KIND_TCPv4: + case NN_LOCATOR_KIND_TCPv6: + case NN_LOCATOR_KIND_UDPv4: + case NN_LOCATOR_KIND_UDPv6: { + int pos = snprintf (dst, sizeof_dst, "%"PRId32"/", loc->kind); + if (0 < pos && (size_t)pos < sizeof_dst) + (void) ddsi_ipaddr_to_string (dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 0); + break; + } + default: { + const unsigned char * const x = loc->address; + (void) snprintf (dst, sizeof_dst, "%"PRId32"/[%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", + loc->kind, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]); + } + } } return dst; } diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 5addd41..8720468 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -25,7 +25,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_pcap.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" typedef struct ddsi_udp_conn { struct ddsi_tran_conn m_base; @@ -68,7 +68,7 @@ static ssize_t ddsi_udp_conn_read (ddsi_tran_conn_t conn, unsigned char * buf, s if (ret > 0) { if (srcloc) - ddsi_ipaddr_to_loc(srcloc, (struct sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6); + ddsi_ipaddr_to_loc(conn->m_factory, srcloc, (struct sockaddr *)&src, src.ss_family == AF_INET ? NN_LOCATOR_KIND_UDPv4 : NN_LOCATOR_KIND_UDPv6); if(conn->m_base.gv->pcap_fp) { @@ -88,8 +88,8 @@ 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(conn->m_base.gv, addrbuf, sizeof(addrbuf), &tmp); + ddsi_ipaddr_to_loc(conn->m_factory, &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_CWARNING(&conn->m_base.gv->logconfig, "%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len); } } @@ -432,10 +432,10 @@ static enum ddsi_locator_from_string_result ddsi_udp_address_from_string (ddsi_t 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) +static char *ddsi_udp_locator_to_string (char *dst, size_t sizeof_dst, const nn_locator_t *loc, int with_port) { if (loc->kind != NN_LOCATOR_KIND_UDPv4MCGEN) { - return ddsi_ipaddr_to_string(tran, dst, sizeof_dst, loc, with_port); + return ddsi_ipaddr_to_string(dst, sizeof_dst, loc, with_port); } else { struct sockaddr_in src; nn_udpv4mcgen_address_t mcgen; @@ -472,7 +472,7 @@ static int ddsi_udp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port) return (port <= 65535); } -int ddsi_udp_init (struct q_globals *gv) +int ddsi_udp_init (struct ddsi_domaingv *gv) { struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact)); memset (fact, 0, sizeof (*fact)); diff --git a/src/core/ddsi/src/q_addrset.c b/src/core/ddsi/src/q_addrset.c index 0d557e7..98e5406 100644 --- a/src/core/ddsi/src/q_addrset.c +++ b/src/core/ddsi/src/q_addrset.c @@ -23,7 +23,7 @@ #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_domaingv.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 @@ -44,7 +44,7 @@ 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 (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) +static int add_addresses_to_addrset_1 (const struct ddsi_domaingv *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; @@ -94,7 +94,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse if (port_mode >= 0) { loc.port = (unsigned) port_mode; - GVLOG (DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "%s: add %s", msgtag, ddsi_locator_to_string(buf, sizeof(buf), &loc)); add_to_addrset (gv, as, &loc); } else @@ -107,7 +107,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse { loc.port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, i); if (i == 0) - GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc)); else GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, loc.port); add_to_addrset (gv, as, &loc); @@ -119,7 +119,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse loc.port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0); else loc.port = (uint32_t) port_mode; - GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(buf, sizeof(buf), &loc)); add_to_addrset (gv, as, &loc); } } @@ -128,7 +128,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse return 0; } -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) +int add_addresses_to_addrset (const struct ddsi_domaingv *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 @@ -231,6 +231,7 @@ void unref_addrset (struct addrset *as) void set_unspec_locator (nn_locator_t *loc) { + loc->tran = NULL; loc->kind = NN_LOCATOR_KIND_INVALID; loc->port = NN_LOCATOR_PORT_INVALID; memset (loc->address, 0, sizeof (loc->address)); @@ -245,7 +246,7 @@ int is_unspec_locator (const nn_locator_t *loc) } #ifdef DDSI_INCLUDE_SSM -int addrset_contains_ssm (const struct q_globals *gv, const struct addrset *as) +int addrset_contains_ssm (const struct ddsi_domaingv *gv, const struct addrset *as) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -262,7 +263,7 @@ int addrset_contains_ssm (const struct q_globals *gv, const struct addrset *as) return 0; } -int addrset_any_ssm (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst) +int addrset_any_ssm (const struct ddsi_domaingv *gv, const struct addrset *as, nn_locator_t *dst) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -280,7 +281,7 @@ int addrset_any_ssm (const struct q_globals *gv, const struct addrset *as, nn_lo return 0; } -int addrset_any_non_ssm_mc (const struct q_globals *gv, const struct addrset *as, nn_locator_t *dst) +int addrset_any_non_ssm_mc (const struct ddsi_domaingv *gv, const struct addrset *as, nn_locator_t *dst) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -308,7 +309,7 @@ int addrset_purge (struct addrset *as) return 0; } -void add_to_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc) +void add_to_addrset (const struct ddsi_domaingv *gv, struct addrset *as, const nn_locator_t *loc) { if (!is_unspec_locator (loc)) { @@ -325,7 +326,7 @@ void add_to_addrset (const struct q_globals *gv, struct addrset *as, const nn_lo } } -void remove_from_addrset (const struct q_globals *gv, struct addrset *as, const nn_locator_t *loc) +void remove_from_addrset (const struct ddsi_domaingv *gv, struct addrset *as, const nn_locator_t *loc) { ddsrt_avl_dpath_t path; ddsrt_avl_ctree_t *tree = ddsi_is_mcaddr (gv, loc) ? &as->mcaddrs : &as->ucaddrs; @@ -339,7 +340,7 @@ void remove_from_addrset (const struct q_globals *gv, struct addrset *as, const UNLOCK (as); } -void copy_addrset_into_addrset_uc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_uc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -349,7 +350,7 @@ void copy_addrset_into_addrset_uc (const struct q_globals *gv, struct addrset *a UNLOCK (asadd); } -void copy_addrset_into_addrset_mc (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_mc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -359,14 +360,14 @@ void copy_addrset_into_addrset_mc (const struct q_globals *gv, struct addrset *a UNLOCK (asadd); } -void copy_addrset_into_addrset (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *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 (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_no_ssm_mc (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd) { struct addrset_node *n; ddsrt_avl_citer_t it; @@ -380,7 +381,7 @@ void copy_addrset_into_addrset_no_ssm_mc (const struct q_globals *gv, struct add } -void copy_addrset_into_addrset_no_ssm (const struct q_globals *gv, struct addrset *as, const struct addrset *asadd) +void copy_addrset_into_addrset_no_ssm (const struct ddsi_domaingv *gv, struct addrset *as, const struct addrset *asadd) { copy_addrset_into_addrset_uc (gv, as, asadd); copy_addrset_into_addrset_no_ssm_mc (gv, as, asadd); @@ -548,19 +549,19 @@ 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; + struct ddsi_domaingv *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; + const struct ddsi_domaingv *gv = arg->gv; char buf[DDSI_LOCSTRLEN]; if (gv->logconfig.c.mask & arg->tf) - GVLOG (arg->tf, " %s", ddsi_locator_to_string (gv, buf, sizeof(buf), n)); + GVLOG (arg->tf, " %s", ddsi_locator_to_string (buf, sizeof(buf), n)); } -void nn_log_addrset (struct q_globals *gv, uint32_t tf, const char *prefix, const struct addrset *as) +void nn_log_addrset (struct ddsi_domaingv *gv, uint32_t tf, const char *prefix, const struct addrset *as) { if (gv->logconfig.c.mask & tf) { diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index 53533b0..8203275 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -149,9 +149,7 @@ DU(ipv4); DUPF(allow_multicast); DUPF(boolean); DU(boolean_default); -#if 0 PF(boolean_default); -#endif DUPF(string); DU(tracingOutputFileName); DU(verbosity); @@ -731,8 +729,8 @@ static const struct cfgelem unsupp_cfgelems[] = { BLURB("

This element controls whether the actual sending of packets occurs on the same thread that prepares them, or is done asynchronously by another thread.

") }, { LEAF_W_ATTRS("RediscoveryBlacklistDuration", rediscovery_blacklist_duration_attrs), 1, "10s", ABSOFF(prune_deleted_ppant.delay), 0, uf_duration_inf, 0, pf_duration, BLURB("

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.

") }, - { LEAF_W_ATTRS("MultipleReceiveThreads", multiple_recv_threads_attrs), 1, "true", ABSOFF(multiple_recv_threads), 0, uf_boolean, 0, pf_boolean, - BLURB("

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).

") }, + { LEAF_W_ATTRS("MultipleReceiveThreads", multiple_recv_threads_attrs), 1, "default", ABSOFF(multiple_recv_threads), 0, uf_boolean_default, 0, pf_boolean_default, + BLURB("

This element controls whether all traffic is handled by a single receive thread (false) or whether multiple receive threads may be used to improve latency (true). By default it is disabled on Windows because it appears that one cannot count on being able to send packets to oneself, which is necessary to stop the thread during shutdown. Currently multiple receive threads are only used for connectionless transport (e.g., UDP) and ManySocketsMode not set to single (the default).

") }, { MGROUP("ControlTopic", control_topic_cfgelems, control_topic_cfgattrs), 1, 0, 0, 0, 0, 0, 0, 0, BLURB("

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

") }, { GROUP("Test", unsupp_test_cfgelems), @@ -1621,7 +1619,7 @@ 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) +GENERIC_ENUM (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 }; diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c index 43b086f..8877242 100644 --- a/src/core/ddsi/src/q_ddsi_discovery.c +++ b/src/core/ddsi/src/q_ddsi_discovery.c @@ -27,7 +27,7 @@ #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_xevent.h" #include "dds/ddsi/q_addrset.h" @@ -36,7 +36,7 @@ #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_transmit.h" @@ -46,7 +46,7 @@ #include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_pmd.h" -static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet) +static int get_locator (const struct ddsi_domaingv *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet) { struct nn_locators_one *l; nn_locator_t first, samenet; @@ -118,7 +118,7 @@ static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_ first_set = 1; } - switch (ddsi_is_nearby_address(gv, &l->loc, &gv->ownloc, (size_t) gv->n_interfaces, gv->interfaces)) + switch (ddsi_is_nearby_address(&l->loc, &gv->ownloc, (size_t) gv->n_interfaces, gv->interfaces)) { case DNAR_DISTANT: break; @@ -160,7 +160,7 @@ static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_ *** *****************************************************************************/ -static void maybe_add_pp_as_meta_to_as_disc (struct q_globals *gv, const struct addrset *as_meta) +static void maybe_add_pp_as_meta_to_as_disc (struct ddsi_domaingv *gv, const struct addrset *as_meta) { if (addrset_empty_mc (as_meta) || !(gv->config.allowMulticast & AMC_SPDP)) { @@ -188,7 +188,7 @@ int spdp_write (struct participant *pp) { struct nn_xmsg *mpayload; struct nn_locators_one def_uni_loc_one, def_multi_loc_one, meta_uni_loc_one, meta_multi_loc_one; - nn_plist_t ps; + ddsi_plist_t ps; struct writer *wr; size_t size; char node[64]; @@ -216,7 +216,7 @@ int spdp_write (struct participant *pp) construct the payload. */ mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, NULL, 0, NN_XMSG_KIND_DATA); - nn_plist_init_empty (&ps); + ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET | PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION | PP_DOMAIN_ID; @@ -237,11 +237,6 @@ int spdp_write (struct participant *pp) ps.aliased |= PP_DOMAIN_TAG; ps.domain_tag = pp->e.gv->config.domainTag; } - if (pp->prismtech_bes) - { - ps.present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET; - ps.prismtech_builtin_endpoint_set = pp->prismtech_bes; - } ps.default_unicast_locators.n = 1; ps.default_unicast_locators.first = ps.default_unicast_locators.last = &def_uni_loc_one; @@ -327,15 +322,15 @@ int spdp_write (struct participant *pp) } /* 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, &pp->e.gv->default_plist_pp.qos, QP_USER_DATA); + qosdiff = ddsi_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); - nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, 0); - nn_plist_addtomsg (mpayload, pp->plist, 0, qosdiff); + ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, 0); + ddsi_plist_addtomsg (mpayload, pp->plist, 0, qosdiff); nn_xmsg_addpar_sentinel (mpayload); - nn_plist_fini (&ps); + ddsi_plist_fini (&ps); ret = write_mpayload (wr, 1, PID_PARTICIPANT_GUID, mpayload); nn_xmsg_free (mpayload); @@ -345,7 +340,7 @@ int spdp_write (struct participant *pp) static int spdp_dispose_unregister_with_wr (struct participant *pp, unsigned entityid) { struct nn_xmsg *mpayload; - nn_plist_t ps; + ddsi_plist_t ps; struct writer *wr; int ret; @@ -358,12 +353,12 @@ static int spdp_dispose_unregister_with_wr (struct participant *pp, unsigned ent } mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, NULL, 0, NN_XMSG_KIND_DATA); - nn_plist_init_empty (&ps); + ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = pp->e.guid; - nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); + ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); nn_xmsg_addpar_sentinel (mpayload); - nn_plist_fini (&ps); + ddsi_plist_fini (&ps); ret = write_mpayload (wr, 0, PID_PARTICIPANT_GUID, mpayload); nn_xmsg_free (mpayload); @@ -414,7 +409,7 @@ static unsigned pseudo_random_delay (const ddsi_guid_t *x, const ddsi_guid_t *y, return (unsigned) (m >> 32); } -static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest_proxypp_guid) +static void respond_to_spdp (const struct ddsi_domaingv *gv, const ddsi_guid_t *dest_proxypp_guid) { struct entidx_enum_participant est; struct participant *pp; @@ -439,9 +434,9 @@ static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest entidx_enum_participant_fini (&est); } -static int handle_SPDP_dead (const struct receiver_state *rst, ddsi_entityid_t pwr_entityid, nn_wctime_t timestamp, const nn_plist_t *datap, unsigned statusinfo) +static int handle_SPDP_dead (const struct receiver_state *rst, ddsi_entityid_t pwr_entityid, nn_wctime_t timestamp, const ddsi_plist_t *datap, unsigned statusinfo) { - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; ddsi_guid_t guid; GVLOGDISC ("SPDP ST%x", statusinfo); @@ -474,7 +469,7 @@ static int handle_SPDP_dead (const struct receiver_state *rst, ddsi_entityid_t p return 1; } -static void allowmulticast_aware_add_to_addrset (const struct q_globals *gv, uint32_t allow_multicast, struct addrset *as, const nn_locator_t *loc) +static void allowmulticast_aware_add_to_addrset (const struct ddsi_domaingv *gv, uint32_t allow_multicast, struct addrset *as, const nn_locator_t *loc) { #if DDSI_INCLUDE_SSM if (ddsi_is_ssm_mcaddr (gv, loc)) @@ -508,7 +503,7 @@ static struct proxy_participant *find_ddsi2_proxy_participant (const struct enti return pp; } -static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const ddsi_guid_t *ddsi2guid, nn_wctime_t timestamp) +static void make_participants_dependent_on_ddsi2 (struct ddsi_domaingv *gv, const ddsi_guid_t *ddsi2guid, nn_wctime_t timestamp) { struct entidx_enum_proxy_participant it; struct proxy_participant *pp, *d2pp; @@ -544,15 +539,14 @@ static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const dd } } -static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, 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 ddsi_plist_t *datap) { - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; const unsigned bes_sedp_announcer_mask = NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER | NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; struct addrset *as_meta, *as_default; - unsigned builtin_endpoint_set; - unsigned prismtech_builtin_endpoint_set; + uint32_t builtin_endpoint_set; ddsi_guid_t privileged_pp_guid; dds_duration_t lease_duration; unsigned custom_flags = 0; @@ -580,7 +574,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ so it seemed; and yet they are necessary for correct operation, so add them. */ builtin_endpoint_set = datap->builtin_endpoint_set; - prismtech_builtin_endpoint_set = (datap->present & PP_PRISMTECH_BUILTIN_ENDPOINT_SET) ? datap->prismtech_builtin_endpoint_set : 0; if (vendor_is_rti (rst->vendor) && ((builtin_endpoint_set & (NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER | @@ -595,21 +588,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER | NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; } - if ((datap->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) && - (datap->present & PP_PRISMTECH_BUILTIN_ENDPOINT_SET) && - !(datap->prismtech_participant_version_info.flags & NN_PRISMTECH_FL_PTBES_FIXED_0)) - { - /* FIXED_0 (bug 0) indicates that this is an updated version that advertises - CM readers/writers correctly (without it, we could make a reasonable guess, - 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 ... */ - 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) - prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; - } /* Do we know this GUID already? */ { @@ -652,7 +630,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ GVLOGDISC ("SPDP ST0 "PGUIDFMT, PGUID (datap->participant_guid)); GVLOGDISC (proxypp->implicitly_created ? " (NEW was-implicitly-created)" : " (update)"); proxypp->implicitly_created = 0; - update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp); + update_proxy_participant_plist_locked (proxypp, seq, datap, timestamp); } ddsrt_mutex_unlock (&proxypp->e.lock); return interesting; @@ -666,7 +644,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ } } - GVLOGDISC ("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 NEW", PGUID (datap->participant_guid), builtin_endpoint_set); if (datap->present & PP_PARTICIPANT_LEASE_DURATION) { @@ -785,7 +763,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ } GVLOGDISC (" QOS={"); - nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, &datap->qos); + ddsi_xqos_log (DDS_LC_DISCOVERY, &gv->logconfig, &datap->qos); GVLOGDISC ("}\n"); maybe_add_pp_as_meta_to_as_disc (gv, as_meta); @@ -795,7 +773,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ gv, &datap->participant_guid, builtin_endpoint_set, - prismtech_builtin_endpoint_set, &privileged_pp_guid, as_default, as_meta, @@ -847,7 +824,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_ static void handle_SPDP (const struct receiver_state *rst, ddsi_entityid_t pwr_entityid, seqno_t seq, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, uint32_t len) { - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ if (data == NULL) { @@ -856,8 +833,8 @@ static void handle_SPDP (const struct receiver_state *rst, ddsi_entityid_t pwr_e } else { - nn_plist_t decoded_data; - nn_plist_src_t src; + ddsi_plist_t decoded_data; + ddsi_plist_src_t src; int interesting = 0; dds_return_t plist_ret; src.protocol_version = rst->protocol_version; @@ -868,7 +845,7 @@ static void handle_SPDP (const struct receiver_state *rst, ddsi_entityid_t pwr_e 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 = ddsi_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) { if (plist_ret != DDS_RETCODE_UNSUPPORTED) GVWARNING ("SPDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); @@ -888,14 +865,14 @@ static void handle_SPDP (const struct receiver_state *rst, ddsi_entityid_t pwr_e break; } - nn_plist_fini (&decoded_data); + ddsi_plist_fini (&decoded_data); GVLOG (interesting ? DDS_LC_DISCOVERY : DDS_LC_TRACE, "\n"); } } struct add_locator_to_ps_arg { - struct q_globals *gv; - nn_plist_t *ps; + struct ddsi_domaingv *gv; + ddsi_plist_t *ps; }; static void add_locator_to_ps (const nn_locator_t *loc, void *varg) @@ -942,14 +919,14 @@ static int sedp_write_endpoint const struct entity_common *common, const struct endpoint_common *epcommon, const dds_qos_t *xqos, struct addrset *as, nn_security_info_t *security) { - struct q_globals * const gv = wr->e.gv; + struct ddsi_domaingv * 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; + ddsi_plist_t ps; int ret; - nn_plist_init_empty (&ps); + ddsi_plist_init_empty (&ps); ps.present |= PP_ENDPOINT_GUID; ps.endpoint_guid = *epguid; @@ -1009,7 +986,7 @@ static int sedp_write_endpoint } #endif - qosdiff = nn_xqos_delta (xqos, defqos, ~(uint64_t)0); + qosdiff = ddsi_xqos_delta (xqos, defqos, ~(uint64_t)0); if (gv->config.explicitly_publish_qos_set_to_default) qosdiff |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; @@ -1027,10 +1004,10 @@ static int sedp_write_endpoint important, except that they need to be set to reasonable things or it'll crash */ mpayload = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, NULL, 0, NN_XMSG_KIND_DATA); - nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); - if (xqos) nn_xqos_addtomsg (mpayload, xqos, qosdiff); + ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); + if (xqos) ddsi_xqos_addtomsg (mpayload, xqos, qosdiff); nn_xmsg_addpar_sentinel (mpayload); - nn_plist_fini (&ps); + ddsi_plist_fini (&ps); GVLOGDISC ("sedp: write for "PGUIDFMT" via "PGUIDFMT"\n", PGUID (*epguid), PGUID (wr->e.guid)); ret = write_mpayload (wr, alive, PID_ENDPOINT_GUID, mpayload); @@ -1128,10 +1105,10 @@ static const char *durability_to_string (dds_durability_kind_t k) return "undefined-durability"; } -static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const ddsi_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq) +static struct proxy_participant *implicitly_create_proxypp (struct ddsi_domaingv *gv, const ddsi_guid_t *ppguid, ddsi_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq) { ddsi_guid_t privguid; - nn_plist_t pp_plist; + ddsi_plist_t pp_plist; if (memcmp (&ppguid->prefix, src_guid_prefix, sizeof (ppguid->prefix)) == 0) /* if the writer is owned by the participant itself, we're not interested */ @@ -1139,7 +1116,7 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv privguid.prefix = *src_guid_prefix; privguid.entityid = to_entityid (NN_ENTITYID_PARTICIPANT); - nn_plist_init_empty(&pp_plist); + ddsi_plist_init_empty(&pp_plist); if (vendor_is_cloud (vendorid)) { @@ -1165,7 +1142,7 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv 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(gv, ppguid, 0, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, T_NEVER, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq); + new_proxy_participant(gv, ppguid, 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)) { @@ -1184,9 +1161,9 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv goto err; } else { struct addrset *as_default, *as_meta; - nn_plist_t tmp_plist; + ddsi_plist_t tmp_plist; GVTRACE (" from-ddsi2 "PGUIDFMT, PGUID (privguid)); - nn_plist_init_empty (&pp_plist); + ddsi_plist_init_empty (&pp_plist); ddsrt_mutex_lock (&privpp->e.lock); as_default = ref_addrset(privpp->as_default); @@ -1195,23 +1172,23 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv 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, ~(uint64_t)0, ~(uint64_t)0); + ddsi_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 (gv, ppguid, 0, 0, &privguid, as_default, as_meta, &pp_plist, T_NEVER, vendorid, CF_IMPLICITLY_CREATED_PROXYPP | CF_PROXYPP_NO_SPDP, timestamp, seq); + new_proxy_participant (gv, ppguid, 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); + ddsi_plist_fini (&pp_plist); return entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid); } -static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_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, ddsi_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp) { #define E(msg, lbl) do { GVLOGDISC (msg); goto lbl; } while (0) - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; struct proxy_participant *pp; struct proxy_writer * pwr = NULL; struct proxy_reader * prd = NULL; @@ -1257,11 +1234,11 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn xqos = &datap->qos; is_writer = is_writer_entityid (datap->endpoint_guid.entityid); if (!is_writer) - nn_xqos_mergein_missing (xqos, &gv->default_xqos_rd, ~(uint64_t)0); + ddsi_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, ~(uint64_t)0); + ddsi_xqos_mergein_missing (xqos, &gv->default_xqos_wr, ~(uint64_t)0); else - nn_xqos_mergein_missing (xqos, &gv->default_xqos_wr_nad, ~(uint64_t)0); + ddsi_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, @@ -1349,7 +1326,7 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn GVLOGDISC (" ssm=%u", ssm); #endif GVLOGDISC (") QOS={"); - nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, xqos); + ddsi_xqos_log (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)) @@ -1403,9 +1380,9 @@ err: #undef E } -static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *datap, nn_wctime_t timestamp) +static void handle_SEDP_dead (const struct receiver_state *rst, ddsi_plist_t *datap, nn_wctime_t timestamp) { - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; int res; if (!(datap->present & PP_ENDPOINT_GUID)) { @@ -1422,7 +1399,7 @@ static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *data 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; + struct ddsi_domaingv * const gv = rst->gv; const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ GVLOGDISC ("SEDP ST%x", statusinfo); if (data == NULL) @@ -1432,8 +1409,8 @@ static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, nn_wctim } else { - nn_plist_t decoded_data; - nn_plist_src_t src; + ddsi_plist_t decoded_data; + ddsi_plist_src_t src; dds_return_t plist_ret; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; @@ -1443,7 +1420,7 @@ static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, nn_wctim 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 = ddsi_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) { if (plist_ret != DDS_RETCODE_UNSUPPORTED) GVWARNING ("SEDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); @@ -1463,7 +1440,7 @@ static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, nn_wctim break; } - nn_plist_fini (&decoded_data); + ddsi_plist_fini (&decoded_data); } } @@ -1473,7 +1450,7 @@ static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, nn_wctim *** *****************************************************************************/ -int sedp_write_topic (struct participant *pp, const struct nn_plist *datap) +int sedp_write_topic (struct participant *pp, const struct ddsi_plist *datap) { struct writer *sedp_wr; struct nn_xmsg *mpayload; @@ -1490,10 +1467,10 @@ 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 (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid, NULL, 0, NN_XMSG_KIND_DATA); - delta = nn_xqos_delta (&datap->qos, &sedp_wr->e.gv->default_xqos_tp, ~(uint64_t)0); + delta = ddsi_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); + ddsi_plist_addtomsg (mpayload, datap, ~(uint64_t)0, delta); nn_xmsg_addpar_sentinel (mpayload); ETRACE (pp, "sedp: write topic %s via "PGUIDFMT"\n", datap->qos.topic_name, PGUID (sedp_wr->e.guid)); @@ -1503,104 +1480,6 @@ int sedp_write_topic (struct participant *pp, const struct nn_plist *datap) } -/****************************************************************************** - *** - *** PrismTech CM data - *** - *****************************************************************************/ - -int sedp_write_cm_participant (struct participant *pp, int alive) -{ - struct writer * sedp_wr; - struct nn_xmsg *mpayload; - nn_plist_t ps; - int ret; - - if (pp->e.onlylocal) { - /* This topic is only locally available. */ - return 0; - } - - sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_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 (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid, NULL, 0, NN_XMSG_KIND_DATA); - nn_plist_init_empty (&ps); - ps.present = PP_PARTICIPANT_GUID; - ps.participant_guid = pp->e.guid; - nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); - nn_plist_fini (&ps); - if (alive) - { - nn_plist_addtomsg (mpayload, pp->plist, - PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | - PP_ENTITY_NAME, - QP_PRISMTECH_ENTITY_FACTORY); - } - nn_xmsg_addpar_sentinel (mpayload); - - 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, ddsi_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) */ - 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) - { - GVLOGDISC (" no payload?\n"); - return; - } - else - { - nn_plist_t decoded_data; - nn_plist_src_t src; - 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 != DDS_RETCODE_UNSUPPORTED) - GVWARNING ("SEDP_CM (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); - return; - } - - /* ignore: dispose/unregister is tied to deleting the participant, which will take care of the dispose/unregister for us */; - if ((statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) == 0) - { - struct proxy_participant *proxypp; - if (!(decoded_data.present & PP_PARTICIPANT_GUID)) - GVWARNING ("SEDP_CM (vendor %u.%u): missing participant GUID\n", src.vendorid.id[0], src.vendorid.id[1]); - else - { - if ((proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, &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, 0, &decoded_data, UPD_PROXYPP_CM, timestamp); - } - } - - nn_plist_fini (&decoded_data); - } - GVLOGDISC ("\n"); -} - /****************************************************************************** *****************************************************************************/ @@ -1637,7 +1516,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 ddsi_guid_t *rdguid), UNUSED_ARG (void *qarg)) { - struct q_globals * const gv = sampleinfo->rst->gv; + struct ddsi_domaingv * const gv = sampleinfo->rst->gv; struct proxy_writer *pwr; struct { struct CDRHeader cdr; @@ -1650,7 +1529,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str ddsi_guid_t srcguid; Data_DataFrag_common_t *msg; unsigned char data_smhdr_flags; - nn_plist_t qos; + ddsi_plist_t qos; unsigned char *datap; int needs_free; uint32_t datasz = sampleinfo->size; @@ -1694,12 +1573,12 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str need_keyhash = (datasz == 0 || (data_smhdr_flags & (DATA_FLAG_KEYFLAG | DATA_FLAG_DATAFLAG)) == 0); if (!(sampleinfo->complex_qos || need_keyhash)) { - nn_plist_init_empty (&qos); + ddsi_plist_init_empty (&qos); statusinfo = sampleinfo->statusinfo; } else { - nn_plist_src_t src; + ddsi_plist_src_t src; size_t qos_offset = NN_RDATA_SUBMSG_OFF (fragchain) + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->octetsToInlineQos) + msg->octetsToInlineQos; dds_return_t plist_ret; src.protocol_version = sampleinfo->rst->protocol_version; @@ -1710,7 +1589,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str 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 = ddsi_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH, 0, &src)) < 0) { if (plist_ret != DDS_RETCODE_UNSUPPORTED) GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", @@ -1773,14 +1652,9 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str switch (srcguid.entityid.u) { case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: pid = PID_PARTICIPANT_GUID; break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - pid = PID_GROUP_GUID; - break; case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: @@ -1836,9 +1710,6 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: handle_pmd_message (sampleinfo->rst, timestamp, statusinfo, datap, datasz); break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: - handle_SEDP_CM (sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz); - break; #ifdef DDSI_INCLUDE_SECURITY case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: /* TODO: Handshake */ diff --git a/src/core/ddsi/src/q_debmon.c b/src/core/ddsi/src/q_debmon.c index 6f6bf69..fbf33a0 100644 --- a/src/core/ddsi/src/q_debmon.c +++ b/src/core/ddsi/src/q_debmon.c @@ -25,9 +25,9 @@ #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_entity_index.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_ddsi_discovery.h" @@ -52,7 +52,7 @@ struct debug_monitor { ddsi_tran_listener_t servsock; ddsrt_mutex_t lock; ddsrt_cond_t cond; - struct q_globals *gv; + struct ddsi_domaingv *gv; struct plugin *plugins; int stop; }; @@ -88,7 +88,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 (arg->conn->m_base.gv, buf, sizeof(buf), n)); + arg->count += cpf (arg->conn, " %s", ddsi_locator_to_string (buf, sizeof(buf), n)); } static int print_addrset (ddsi_tran_conn_t conn, const char *prefix, struct addrset *as, const char *suffix) @@ -142,7 +142,7 @@ static int print_proxy_endpoint_common (ddsi_tran_conn_t conn, const char *label } -static int print_participants (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn) +static int print_participants (struct thread_state1 * const ts1, struct ddsi_domaingv *gv, ddsi_tran_conn_t conn) { struct entidx_enum_participant e; struct participant *p; @@ -227,7 +227,7 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global return x; } -static int print_proxy_participants (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn) +static int print_proxy_participants (struct thread_state1 * const ts1, struct ddsi_domaingv *gv, ddsi_tran_conn_t conn) { struct entidx_enum_proxy_participant e; struct proxy_participant *p; @@ -346,7 +346,7 @@ static uint32_t debmon_main (void *vdm) return 0; } -struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port) +struct debug_monitor *new_debug_monitor (struct ddsi_domaingv *gv, int32_t port) { struct debug_monitor *dm; @@ -381,7 +381,7 @@ struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port) nn_locator_t loc; char buf[DDSI_LOCSTRLEN]; (void) ddsi_listener_locator(dm->servsock, &loc); - GVLOG (DDS_LC_CONFIG, "debmon at %s\n", ddsi_locator_to_string (gv, buf, sizeof(buf), &loc)); + GVLOG (DDS_LC_CONFIG, "debmon at %s\n", ddsi_locator_to_string (buf, sizeof(buf), &loc)); } ddsrt_mutex_init (&dm->lock); diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 53f215e..cf49032 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -26,13 +26,13 @@ #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_log.h" +#include "dds/ddsi/q_bswap.h" #include "dds/ddsrt/avl.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_lease.h" #include "dds/ddsi/q_qosmatch.h" #include "dds/ddsi/ddsi_entity_index.h" -#include "dds/ddsi/q_globals.h" -#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_xevent.h" /* qxev_spdp, &c. */ #include "dds/ddsi/q_ddsi_discovery.h" /* spdp_write, &c. */ @@ -70,7 +70,7 @@ struct deleted_participants_admin { int64_t delay; }; -struct proxy_writer_alive_state { +struct alive_state { bool alive; uint32_t vclock; }; @@ -100,10 +100,6 @@ static const unsigned builtin_writers_besmask = NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER | NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER | NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; -static const unsigned prismtech_builtin_writers_besmask = - NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER | - NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | - NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_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); @@ -115,7 +111,7 @@ static struct entity_common *entity_common_from_proxy_endpoint_common (const str #ifdef DDSI_INCLUDE_SECURITY static const unsigned BES_MASK_NON_SECURITY = 0xf000ffff; -static void handshake_end_cb(struct q_globals const * const gv, struct ddsi_handshake *handshake, const struct ddsi_guid *lpguid, const struct ddsi_guid *ppguid, enum ddsi_handshake_state result); +static void handshake_end_cb(struct ddsi_domaingv const * const gv, struct ddsi_handshake *handshake, const struct ddsi_guid *lpguid, const struct ddsi_guid *ppguid, enum ddsi_handshake_state result); static void downgrade_to_nonsecure(struct proxy_participant *proxypp); #endif @@ -232,7 +228,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, struct q_globals *gv, const struct ddsi_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal) +static int compare_ldur (const void *va, const void *vb) +{ + const struct ldur_fhnode *a = va; + const struct ldur_fhnode *b = vb; + return (a->ldur == b->ldur) ? 0 : (a->ldur < b->ldur) ? -1 : 1; +} + +/* used in participant for keeping writer liveliness renewal */ +const ddsrt_fibheap_def_t ldur_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct ldur_fhnode, heapnode), compare_ldur); +/* used in (proxy)participant for writer liveliness monitoring */ +const ddsrt_fibheap_def_t lease_fhdef_pp = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, pp_heapnode), compare_lease_tdur); + +static void entity_common_init (struct entity_common *e, struct ddsi_domaingv *gv, const struct ddsi_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; @@ -282,10 +290,28 @@ static void local_reader_ary_fini (struct local_reader_ary *x) static void local_reader_ary_insert (struct local_reader_ary *x, struct reader *rd) { ddsrt_mutex_lock (&x->rdary_lock); + x->rdary = ddsrt_realloc (x->rdary, (x->n_readers + 2) * sizeof (*x->rdary)); + if (x->n_readers <= 1 || rd->topic == x->rdary[x->n_readers - 1]->topic) + { + /* if the first or second reader, or if the topic is the same as that of + the last one in the list simply appending the new will maintain order */ + x->rdary[x->n_readers] = rd; + } + else + { + uint32_t i; + for (i = 0; i < x->n_readers; i++) + if (x->rdary[i]->topic == rd->topic) + break; + if (i < x->n_readers) + { + /* shift any with the same topic plus whichever follow to make room */ + memmove (&x->rdary[i + 1], &x->rdary[i], (x->n_readers - i) * sizeof (x->rdary[i])); + } + x->rdary[i] = rd; + } + x->rdary[x->n_readers + 1] = NULL; x->n_readers++; - x->rdary = ddsrt_realloc (x->rdary, (x->n_readers + 1) * sizeof (*x->rdary)); - x->rdary[x->n_readers - 1] = rd; - x->rdary[x->n_readers] = NULL; ddsrt_mutex_unlock (&x->rdary_lock); } @@ -294,13 +320,20 @@ static void local_reader_ary_remove (struct local_reader_ary *x, struct reader * uint32_t i; ddsrt_mutex_lock (&x->rdary_lock); for (i = 0; i < x->n_readers; i++) - { if (x->rdary[i] == rd) break; - } assert (i < x->n_readers); - /* if i == N-1 copy is a no-op */ - x->rdary[i] = x->rdary[x->n_readers-1]; + if (i + 1 < x->n_readers) + { + /* dropping the final one never requires any fixups; dropping one that has + the same topic as the last is as simple as moving the last one in the + removed one's location; else shift all following readers to keep it + grouped by topic */ + if (rd->topic == x->rdary[x->n_readers - 1]->topic) + x->rdary[i] = x->rdary[x->n_readers - 1]; + else + memmove (&x->rdary[i], &x->rdary[i + 1], (x->n_readers - i - 1) * sizeof (x->rdary[i])); + } x->n_readers--; x->rdary[x->n_readers] = NULL; x->rdary = ddsrt_realloc (x->rdary, (x->n_readers + 1) * sizeof (*x->rdary)); @@ -448,22 +481,11 @@ static void remove_deleted_participant_guid (struct deleted_participants_admin * } /* PARTICIPANT ------------------------------------------------------ */ - -static int compare_ldur (const void *va, const void *vb) -{ - const struct ldur_fhnode *a = va; - const struct ldur_fhnode *b = vb; - return (a->ldur == b->ldur) ? 0 : (a->ldur < b->ldur) ? -1 : 1; -} - -/* used in participant for keeping writer liveliness renewal */ -const ddsrt_fibheap_def_t ldur_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct ldur_fhnode, heapnode), compare_ldur); - 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; + mask = ddsi_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; @@ -476,7 +498,7 @@ static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, cons !!(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); + ddsi_xqos_log (DDS_LC_DISCOVERY, &e->gv->logconfig, xqos); EELOGDISC (e, "}\n"); if (mask == 0) @@ -484,8 +506,8 @@ static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, cons return false; ddsrt_mutex_lock (&e->qos_lock); - nn_xqos_fini_mask (ent_qos, mask); - nn_xqos_mergein_missing (ent_qos, xqos, mask); + ddsi_xqos_fini_mask (ent_qos, mask); + ddsi_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; @@ -517,7 +539,7 @@ static void pp_release_entityid(struct participant *pp, ddsi_entityid_t id) ddsrt_mutex_unlock (&pp->e.lock); } -static void force_as_disc_address(struct q_globals *gv, const ddsi_guid_t *subguid) +static void force_as_disc_address(struct ddsi_domaingv *gv, const ddsi_guid_t *subguid) { struct writer *wr = entidx_lookup_writer_guid (gv->entity_index, subguid); assert (wr != NULL); @@ -530,36 +552,48 @@ static void force_as_disc_address(struct q_globals *gv, const ddsi_guid_t *subgu } #ifdef DDSI_INCLUDE_SECURITY -static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, const ddsi_guid_t *group_guid, struct q_globals *gv, bool add_writers, bool add_readers) +static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, const ddsi_guid_t *group_guid, struct ddsi_domaingv *gv, bool add_writers, bool add_readers) { if (add_writers) { + struct whc_writer_info *wrinfo; + subguid->entityid = to_entityid (NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ force_as_disc_address(gv, subguid); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_stateless_xqos_wr, whc_new(gv, 0, 1, 1), NULL, NULL); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_stateless_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_stateless_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_volatile_xqos_wr, whc_new(gv, 0, 0, 0), NULL, NULL); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_volatile_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER; + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); pp->bes |= NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, 1, 1, 1), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); pp->bes |= NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER; + + whc_free_wrinfo (wrinfo); } if (add_readers) @@ -598,7 +632,7 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t * #ifdef DDSI_INCLUDE_SECURITY -static void connect_participant_secure(struct q_globals *gv, struct participant *pp) +static void connect_participant_secure(struct ddsi_domaingv *gv, struct participant *pp) { struct proxy_participant *proxypp; struct entidx_enum_proxy_participant it; @@ -622,7 +656,7 @@ static void disconnect_participant_secure(struct participant *pp) { struct proxy_participant *proxypp; struct entidx_enum_proxy_participant it; - struct q_globals * const gv = pp->e.gv; + struct ddsi_domaingv * const gv = pp->e.gv; if (q_omg_participant_is_secure(pp)) { @@ -636,10 +670,86 @@ static void disconnect_participant_secure(struct participant *pp) } #endif -dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) +static void gc_participant_lease (struct gcreq *gcreq) +{ + lease_free (gcreq->arg); + gcreq_free (gcreq); +} + +static void participant_replace_minl (struct participant *pp, struct lease *lnew) +{ + /* By loading/storing the pointer atomically, we ensure we always + read a valid (or once valid) lease. By delaying freeing the lease + through the garbage collector, we ensure whatever lease update + occurs in parallel completes before the memory is released. */ + struct gcreq *gcreq = gcreq_new (pp->e.gv->gcreq_queue, gc_participant_lease); + struct lease *lease_old = ddsrt_atomic_ldvoidp (&pp->minl_man); + assert (lease_old != NULL); + lease_unregister (lease_old); /* ensures lease will not expire while it is replaced */ + gcreq->arg = lease_old; + gcreq_enqueue (gcreq); + ddsrt_atomic_stvoidp (&pp->minl_man, lnew); +} + +static void participant_add_wr_lease_locked (struct participant * pp, const struct writer * wr) +{ + struct lease *minl_prev; + struct lease *minl_new; + + assert (wr->lease != NULL); + minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); + ddsrt_fibheap_insert (&lease_fhdef_pp, &pp->leaseheap_man, wr->lease); + minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); + /* if inserted lease is new shortest lease */ + if (minl_prev != minl_new) + { + nn_etime_t texp = add_duration_to_etime (now_et (), minl_new->tdur); + struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity); + if (minl_prev == NULL) + { + assert (ddsrt_atomic_ldvoidp (&pp->minl_man) == NULL); + ddsrt_atomic_stvoidp (&pp->minl_man, lnew); + } + else + { + participant_replace_minl (pp, lnew); + } + lease_register (lnew); + } +} + +static void participant_remove_wr_lease_locked (struct participant * pp, struct writer * wr) +{ + struct lease *minl; + + assert (wr->lease != NULL); + assert (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT); + minl = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); + ddsrt_fibheap_delete (&lease_fhdef_pp, &pp->leaseheap_man, wr->lease); + /* if writer with min lease is removed: update participant lease to use new minimal duration */ + if (wr->lease == minl) + { + if ((minl = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man)) != NULL) + { + dds_duration_t trem = minl->tdur - wr->lease->tdur; + assert (trem >= 0); + nn_etime_t texp = add_duration_to_etime (now_et(), trem); + struct lease *lnew = lease_new (texp, minl->tdur, minl->entity); + participant_replace_minl (pp, lnew); + lease_register (lnew); + } + else + { + participant_replace_minl (pp, NULL); + } + } +} + +dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) { struct participant *pp; ddsi_guid_t subguid, group_guid; + struct whc_writer_info *wrinfo; dds_return_t ret = DDS_RETCODE_OK; /* no reserved bits may be set */ @@ -694,8 +804,8 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * pp->lease_duration = gv->config.lease_duration; ddsrt_fibheap_init (&ldur_fhdef, &pp->ldur_auto_wr); pp->plist = ddsrt_malloc (sizeof (*pp->plist)); - nn_plist_copy (pp->plist, plist); - nn_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0); + ddsi_plist_copy (pp->plist, plist); + ddsi_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0); #ifdef DDSI_INCLUDE_SECURITY /* @@ -706,7 +816,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * * and return if any is found */ { bool ready_to_load_security = false; - if (nn_xqos_has_prop(&pp->plist->qos, "dds.sec.", true, false)) { + if (ddsi_xqos_has_prop(&pp->plist->qos, "dds.sec.", true, false)) { char *req[] = {DDS_SEC_PROP_AUTH_IDENTITY_CA, DDS_SEC_PROP_AUTH_PRIV_KEY, DDS_SEC_PROP_AUTH_IDENTITY_CERT, @@ -729,7 +839,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * /* check if all required security properties exist in qos */ for (size_t i = 0; i < sizeof(req) / sizeof(req[0]); i++) { - if (!nn_xqos_has_prop(&pp->plist->qos, req[i], false, true)) { + if (!ddsi_xqos_has_prop(&pp->plist->qos, req[i], false, true)) { GVERROR ("new_participant(" PGUIDFMT "): required security property %s missing in Property QoS\n", PGUID(*ppguid), req[i]); @@ -747,7 +857,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * GVLOGDISC ("new_participant(" PGUIDFMT "): using security settings from configuration\n", PGUID(*ppguid)); - nn_xqos_mergein_security_config(&pp->plist->qos, &gv->config.omg_security_configuration->cfg); + ddsi_xqos_mergein_security_config(&pp->plist->qos, &gv->config.omg_security_configuration->cfg); ready_to_load_security = true; } @@ -774,7 +884,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * if (gv->logconfig.c.mask & DDS_LC_DISCOVERY) { GVLOGDISC ("PARTICIPANT "PGUIDFMT" QOS={", PGUID (pp->e.guid)); - nn_log_xqos (DDS_LC_DISCOVERY, &gv->logconfig, &pp->plist->qos); + ddsi_xqos_log (DDS_LC_DISCOVERY, &gv->logconfig, &pp->plist->qos); GVLOGDISC ("}\n"); } @@ -788,6 +898,9 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * pp->m_conn = NULL; } + ddsrt_fibheap_init (&lease_fhdef_pp, &pp->leaseheap_man); + ddsrt_atomic_stvoidp (&pp->minl_man, NULL); + /* Before we create endpoints -- and may call unref_participant if things go wrong -- we must initialize all that unref_participant depends on. */ @@ -796,18 +909,18 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * /* Create built-in endpoints (note: these have no GID, and no group GUID). */ pp->bes = 0; - pp->prismtech_bes = 0; subguid.prefix = pp->e.guid.prefix; memset (&group_guid, 0, sizeof (group_guid)); - /* SPDP writer */ -#define LAST_WR_PARAMS NULL, NULL + /* SPDP writer */ /* Note: skip SEDP <=> skip SPDP because of the way ddsi_discovery.c does things currently. */ 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(gv, 1, 1, 1), LAST_WR_PARAMS); + wrinfo = whc_make_wrinfo (NULL, &gv->spdp_endpoint_xqos); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ force_as_disc_address(gv, &subguid); @@ -818,34 +931,23 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * entidx_insert_participant_guid (gv->entity_index, pp); /* SEDP writers: */ + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); 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(gv, 1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); 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(gv, 1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); 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(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(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(gv, 1, 1, 1), LAST_WR_PARAMS); - pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; } 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(gv, 1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER; } @@ -853,10 +955,12 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * 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(gv, 1, 1, 1), LAST_WR_PARAMS); + new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; } + whc_free_wrinfo (wrinfo); + /* SPDP, SEDP, PMD readers: */ if (!(flags & RTPS_PF_NO_BUILTIN_READERS)) { @@ -875,19 +979,6 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * 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); 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); - 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); - 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); - pp->prismtech_bes |= NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER; - } #ifdef DDSI_INCLUDE_SECURITY @@ -897,8 +988,6 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * } #endif -#undef LAST_WR_PARAMS - /* If the participant doesn't have the full set of builtin writers it depends on the privileged participant, which must exist, hence the reference count of the privileged participant is incremented. @@ -907,8 +996,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * Except when the participant is only locally available. */ if (!(flags & RTPS_PF_ONLY_LOCAL)) { 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) + if ((pp->bes & builtin_writers_besmask) != 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 @@ -956,10 +1044,6 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * 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 - need to write it once (or when it changes, I suppose) */ - sedp_write_cm_participant (pp, 1); - { nn_mtime_t tsched; tsched.v = (pp->lease_duration == T_NEVER) ? T_NEVER : 0; @@ -972,13 +1056,12 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals * connect_participant_secure (gv, pp); } #endif - return ret; #ifdef DDSI_INCLUDE_SECURITY not_allowed: new_pp_err_secprop: - nn_plist_fini (pp->plist); + ddsi_plist_fini (pp->plist); ddsrt_free (pp->plist); inverse_uint32_set_fini (&pp->avail_entityids.x); ddsrt_mutex_destroy (&pp->refc_lock); @@ -992,7 +1075,7 @@ new_pp_err: return ret; } -dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) +dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) { union { uint64_t u64; uint32_t u32[2]; } u; u.u32[0] = gv->ppguid_base.prefix.u[1]; @@ -1005,7 +1088,7 @@ dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsig return new_participant_guid (p_ppguid, gv, flags, plist); } -void update_participant_plist (struct participant *pp, const nn_plist_t *plist) +void update_participant_plist (struct participant *pp, const ddsi_plist_t *plist) { ddsrt_mutex_lock (&pp->e.lock); if (update_qos_locked (&pp->e, &pp->plist->qos, &plist->qos, now ())) @@ -1013,7 +1096,7 @@ void update_participant_plist (struct participant *pp, const nn_plist_t *plist) ddsrt_mutex_unlock (&pp->e.lock); } -static void delete_builtin_endpoint (struct q_globals *gv, const struct ddsi_guid *ppguid, unsigned entityid) +static void delete_builtin_endpoint (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, unsigned entityid) { ddsi_guid_t guid; guid.prefix = ppguid->prefix; @@ -1070,13 +1153,6 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER, - /* PrismTech ones: */ - NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER, - NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER, - NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER, - NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER, - NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER, - NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER }; ddsi_guid_t stguid; @@ -1095,7 +1171,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g 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) + if (pp->user_refc == 0 && pp->bes != 0 && !pp->builtins_deleted) { int i; @@ -1131,9 +1207,6 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g scheduled for deletion when it runs into an empty WHC */ spdp_dispose_unregister (pp); - /* We don't care, but other implementations might: */ - sedp_write_cm_participant (pp, 0); - /* If this happens to be the privileged_pp, clear it */ ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); if (pp == pp->e.gv->privileged_pp) @@ -1149,8 +1222,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g if (!(pp->e.onlylocal)) { - if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask || - (pp->prismtech_bes & prismtech_builtin_writers_besmask) != prismtech_builtin_writers_besmask) + if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask) { /* Participant doesn't have a full complement of built-in writers, therefore, it relies on gv->privileged_pp, and @@ -1187,7 +1259,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g while longer for it to wakeup. */ ddsi_conn_free (pp->m_conn); } - nn_plist_fini (pp->plist); + ddsi_plist_fini (pp->plist); ddsrt_free (pp->plist); ddsrt_mutex_destroy (&pp->refc_lock); entity_common_fini (&pp->e); @@ -1209,7 +1281,7 @@ static void gc_delete_participant (struct gcreq *gcreq) unref_participant (pp, NULL); } -dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *ppguid) +dds_return_t delete_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid) { struct participant *pp; GVLOGDISC ("delete_participant("PGUIDFMT")\n", PGUID (*ppguid)); @@ -1228,7 +1300,7 @@ dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *p struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid) { ddsi_guid_t bwr_guid; - unsigned bes_mask = 0, prismtech_bes_mask = 0; + uint32_t bes_mask = 0; if (pp->e.onlylocal) { return NULL; @@ -1257,15 +1329,6 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: - prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - prismtech_bes_mask = NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; - break; case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: bes_mask = NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER; break; @@ -1286,7 +1349,7 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity return NULL; } - if ((pp->bes & bes_mask) || (pp->prismtech_bes & prismtech_bes_mask)) + if (pp->bes & bes_mask) { /* Participant has this SEDP writer => use it. */ bwr_guid.prefix = pp->e.guid.prefix; @@ -1496,13 +1559,13 @@ static void rebuild_make_locs_nrds(int **locs_nrds, int nreaders, int nlocs, con *locs_nrds = ln; } -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) +static void rebuild_trace_covered(const struct ddsi_domaingv *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(gv, buf, sizeof(buf), &locs[i]); + ddsi_locator_to_string(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) @@ -1513,7 +1576,7 @@ static void rebuild_trace_covered(const struct q_globals *gv, int nreaders, int } } -static int rebuild_select(const struct q_globals *gv, int nlocs, const nn_locator_t *locs, const int *locs_nrds, bool prefer_multicast) +static int rebuild_select(const struct ddsi_domaingv *gv, int nlocs, const nn_locator_t *locs, const int *locs_nrds, bool prefer_multicast) { int i, j; if (nlocs == 0) @@ -1536,12 +1599,12 @@ static int rebuild_select(const struct q_globals *gv, int nlocs, const nn_locato return (locs_nrds[j] > 0) ? j : -1; } -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) +static void rebuild_add(const struct ddsi_domaingv *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(gv, str, sizeof(str), &locs[locidx]); + ddsi_locator_to_string(str, sizeof(str), &locs[locidx]); GVLOGDISC (" simple %s\n", str); add_to_addrset(gv, newas, &locs[locidx]); } @@ -1560,7 +1623,7 @@ static void rebuild_add(const struct q_globals *gv, struct addrset *newas, int l iph |= 1u << covered[i * nlocs + locidx]; ipn = htonl(iph); memcpy(l.address + 12, &ipn, 4); - ddsi_locator_to_string(gv, str, sizeof(str), &l); + ddsi_locator_to_string(str, sizeof(str), &l); GVLOGDISC (" mcgen %s\n", str); add_to_addrset(gv, newas, &l); } @@ -1639,7 +1702,7 @@ static void rebuild_writer_addrset (struct writer *wr) ELOGDISC (wr, "\n"); } -void rebuild_or_clear_writer_addrsets (struct q_globals *gv, int rebuild) +void rebuild_or_clear_writer_addrsets (struct ddsi_domaingv *gv, int rebuild) { struct entidx_enum_writer est; struct writer *wr; @@ -1683,7 +1746,7 @@ static void free_wr_prd_match (struct wr_prd_match *m) } } -static void free_rd_pwr_match (struct q_globals *gv, struct rd_pwr_match *m) +static void free_rd_pwr_match (struct ddsi_domaingv *gv, struct rd_pwr_match *m) { if (m) { @@ -1728,13 +1791,26 @@ static void free_wr_rd_match (struct wr_rd_match *m) if (m) ddsrt_free (m); } -static void proxy_writer_get_alive_state_locked (struct proxy_writer *pwr, struct proxy_writer_alive_state *st) +static void writer_get_alive_state_locked (struct writer *wr, struct alive_state *st) +{ + st->alive = wr->alive; + st->vclock = wr->alive_vclock; +} + +static void writer_get_alive_state (struct writer *wr, struct alive_state *st) +{ + ddsrt_mutex_lock (&wr->e.lock); + writer_get_alive_state_locked (wr, st); + ddsrt_mutex_unlock (&wr->e.lock); +} + +static void proxy_writer_get_alive_state_locked (struct proxy_writer *pwr, struct alive_state *st) { st->alive = pwr->alive; st->vclock = pwr->alive_vclock; } -static void proxy_writer_get_alive_state (struct proxy_writer *pwr, struct proxy_writer_alive_state *st) +static void proxy_writer_get_alive_state (struct proxy_writer *pwr, struct alive_state *st) { ddsrt_mutex_lock (&pwr->e.lock); proxy_writer_get_alive_state_locked (pwr, st); @@ -1798,7 +1874,73 @@ static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struc } } -static void reader_update_notify_pwr_alive_state (struct reader *rd, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state) +static void reader_update_notify_alive_state_invoke_cb (struct reader *rd, uint64_t iid, bool notify, int delta, const struct alive_state *alive_state) +{ + /* Liveliness changed events can race each other and can, potentially, be delivered + in a different order. */ + if (notify && rd->status_cb) + { + status_cb_data_t data; + data.handle = iid; + data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID; + if (delta < 0) { + data.extra = (uint32_t) LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE; + (rd->status_cb) (rd->status_cb_entity, &data); + } else if (delta > 0) { + data.extra = (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE; + (rd->status_cb) (rd->status_cb_entity, &data); + } else { + /* Twitch: the resulting (proxy)writer state is unchanged, but there has been + a transition to another state and back to the current state. So we'll call + the callback twice in this case. */ + static const enum liveliness_changed_data_extra x[] = { + LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE, + LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE + }; + data.extra = (uint32_t) x[alive_state->alive]; + (rd->status_cb) (rd->status_cb_entity, &data); + data.extra = (uint32_t) x[!alive_state->alive]; + (rd->status_cb) (rd->status_cb_entity, &data); + } + } +} + +static void reader_update_notify_wr_alive_state (struct reader *rd, const struct writer *wr, const struct alive_state *alive_state) +{ + struct rd_wr_match *m; + bool notify = false; + int delta = 0; /* -1: alive -> not_alive; 0: unchanged; 1: not_alive -> alive */ + ddsrt_mutex_lock (&rd->e.lock); + if ((m = ddsrt_avl_lookup (&rd_local_writers_treedef, &rd->local_writers, &wr->e.guid)) != NULL) + { + if ((int32_t) (alive_state->vclock - m->wr_alive_vclock) > 0) + { + delta = (int) alive_state->alive - (int) m->wr_alive; + notify = true; + m->wr_alive = alive_state->alive; + m->wr_alive_vclock = alive_state->vclock; + } + } + ddsrt_mutex_unlock (&rd->e.lock); + + if (delta < 0 && rd->rhc) + { + struct ddsi_writer_info wrinfo; + ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos, NN_STATUSINFO_UNREGISTER); + ddsi_rhc_unregister_wr (rd->rhc, &wrinfo); + } + + reader_update_notify_alive_state_invoke_cb (rd, wr->e.iid, notify, delta, alive_state); +} + +static void reader_update_notify_wr_alive_state_guid (const struct ddsi_guid *rd_guid, const struct writer *wr, const struct alive_state *alive_state) +{ + struct reader *rd; + if ((rd = entidx_lookup_reader_guid (wr->e.gv->entity_index, rd_guid)) != NULL) + reader_update_notify_wr_alive_state (rd, wr, alive_state); +} + +static void reader_update_notify_pwr_alive_state (struct reader *rd, const struct proxy_writer *pwr, const struct alive_state *alive_state) { struct rd_pwr_match *m; bool notify = false; @@ -1823,24 +1965,10 @@ static void reader_update_notify_pwr_alive_state (struct reader *rd, const struc ddsi_rhc_unregister_wr (rd->rhc, &wrinfo); } - /* Liveliness changed events can race each other and can, potentially, be delivered - in a different order. */ - if (notify && rd->status_cb) - { - status_cb_data_t data; - data.handle = pwr->e.iid; - if (delta == 0) - data.extra = (uint32_t) LIVELINESS_CHANGED_TWITCH; - else if (delta < 0) - data.extra = (uint32_t) LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE; - else - data.extra = (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE; - data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID; - (rd->status_cb) (rd->status_cb_entity, &data); - } + reader_update_notify_alive_state_invoke_cb (rd, pwr->e.iid, notify, delta, alive_state); } -static void reader_update_notify_pwr_alive_state_guid (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state) +static void reader_update_notify_pwr_alive_state_guid (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, const struct alive_state *alive_state) { struct reader *rd; if ((rd = entidx_lookup_reader_guid (pwr->e.gv->entity_index, rd_guid)) != NULL) @@ -1907,7 +2035,7 @@ static void reader_drop_local_connection (const struct ddsi_guid *rd_guid, const status_cb_data_t data; data.handle = wr->e.iid; data.add = false; - data.extra = (uint32_t) LIVELINESS_CHANGED_REMOVE_ALIVE; + data.extra = (uint32_t) (m->wr_alive ? LIVELINESS_CHANGED_REMOVE_ALIVE : LIVELINESS_CHANGED_REMOVE_NOT_ALIVE); data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID; (rd->status_cb) (rd->status_cb_entity, &data); @@ -2149,7 +2277,7 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd) } } -static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct proxy_writer_alive_state *alive_state) +static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct alive_state *alive_state) { struct rd_pwr_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; @@ -2223,12 +2351,14 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, } } -static void reader_add_local_connection (struct reader *rd, struct writer *wr) +static void reader_add_local_connection (struct reader *rd, struct writer *wr, const struct alive_state *alive_state) { struct rd_wr_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; m->wr_guid = wr->e.guid; + m->wr_alive = alive_state->alive; + m->wr_alive_vclock = alive_state->vclock; ddsrt_mutex_lock (&rd->e.lock); @@ -2251,7 +2381,7 @@ static void reader_add_local_connection (struct reader *rd, struct writer *wr) status_cb_data_t data; data.handle = wr->e.iid; data.add = true; - data.extra = (uint32_t) LIVELINESS_CHANGED_ADD_ALIVE; + data.extra = (uint32_t) (alive_state->alive ? LIVELINESS_CHANGED_ADD_ALIVE : LIVELINESS_CHANGED_ADD_NOT_ALIVE); data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID; (rd->status_cb) (rd->status_cb_entity, &data); @@ -2470,24 +2600,6 @@ static ddsi_entityid_t builtin_entityid_match (ddsi_entityid_t x) res.u = NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER; break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER; - break; - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - res.u = NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER; - break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER; break; @@ -2580,7 +2692,7 @@ void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_rea void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow) { nn_count_t init_count; - struct proxy_writer_alive_state alive_state; + struct alive_state alive_state; /* Initialize the reader's tracking information for the writer liveliness state to something sensible, but that may be outdated by the time the reader gets added to the writer's list @@ -2634,7 +2746,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r const int isb1 = (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); dds_qos_policy_id_t reason; nn_count_t init_count; - struct proxy_writer_alive_state alive_state; + struct alive_state alive_state; if (isb0 != isb1) return; if (rd->e.onlylocal) @@ -2699,6 +2811,7 @@ static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, static void connect_writer_with_reader (struct writer *wr, struct reader *rd, nn_mtime_t tnow) { dds_qos_policy_id_t reason; + struct alive_state alive_state; (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; @@ -2710,8 +2823,17 @@ static void connect_writer_with_reader (struct writer *wr, struct reader *rd, nn reader_qos_mismatch (rd, reason); return; } - reader_add_local_connection (rd, wr); + /* Initialze the reader's tracking information for the writer liveliness state to something + sensible, but that may be outdated by the time the reader gets added to the writer's list + of matching readers. */ + writer_get_alive_state (wr, &alive_state); + reader_add_local_connection (rd, wr, &alive_state); writer_add_local_connection (wr, rd); + + /* Once everything is set up: update with the latest state, any updates to the alive state + happening in parallel will cause this to become a no-op. */ + writer_get_alive_state (wr, &alive_state); + reader_update_notify_wr_alive_state (rd, wr, &alive_state); } static void connect_writer_with_proxy_reader_wrapper (struct entity_common *vwr, struct entity_common *vprd, nn_mtime_t tnow) @@ -3054,7 +3176,7 @@ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const topic ? topic->type_name : "(null)"); } -static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal) +static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct ddsi_domaingv *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal) { entity_common_init (e, gv, guid, NULL, kind, now (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal); c->pp = ref_participant (pp, &e->guid); @@ -3267,10 +3389,8 @@ unsigned remove_acked_messages (struct writer *wr, struct whc_state *whcst, stru assert (wr->e.guid.entityid.u != NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); ASSERT_MUTEX_HELD (&wr->e.lock); n = whc_remove_acked_messages (wr->whc, writer_max_drop_seq (wr), whcst, deferred_free_list); - /* when transitioning from >= low-water to < low-water, signal - anyone waiting in throttle_writer() */ - if (wr->throttling && whcst->unacked_bytes <= wr->whc_low) - ddsrt_cond_broadcast (&wr->throttle_cond); + /* trigger anyone waiting in throttle_writer() or wait_for_acks() */ + ddsrt_cond_broadcast (&wr->throttle_cond); if (wr->retransmitting && whcst->unacked_bytes == 0) writer_clear_retransmitting (wr); if (wr->state == WRST_LINGERING && whcst->unacked_bytes == 0) @@ -3281,6 +3401,91 @@ unsigned remove_acked_messages (struct writer *wr, struct whc_state *whcst, stru return n; } +static void writer_notify_liveliness_change_may_unlock (struct writer *wr) +{ + struct alive_state alive_state; + writer_get_alive_state_locked (wr, &alive_state); + + struct ddsi_guid rdguid; + struct pwr_rd_match *m; + memset (&rdguid, 0, sizeof (rdguid)); + while (wr->alive_vclock == alive_state.vclock && + (m = ddsrt_avl_lookup_succ (&wr_local_readers_treedef, &wr->local_readers, &rdguid)) != NULL) + { + rdguid = m->rd_guid; + ddsrt_mutex_unlock (&wr->e.lock); + /* unlocking pwr means alive state may have changed already; we break out of the loop once we + detect this but there for the reader in the current iteration, anything is possible */ + reader_update_notify_wr_alive_state_guid (&rdguid, wr, &alive_state); + ddsrt_mutex_lock (&wr->e.lock); + } +} + +void writer_set_alive_may_unlock (struct writer *wr, bool notify) +{ + /* Caller has wr->e.lock, so we can safely read wr->alive. Updating wr->alive requires + also taking wr->c.pp->e.lock because wr->alive <=> (wr->lease in pp's lease heap). */ + assert (!wr->alive); + + /* check that writer still exists (when deleting it is removed from guid hash) */ + if (entidx_lookup_writer_guid (wr->e.gv->entity_index, &wr->e.guid) == NULL) + { + ELOGDISC (wr, "writer_set_alive_may_unlock("PGUIDFMT") - not in entity index, wr deleting\n", PGUID (wr->e.guid)); + return; + } + + ddsrt_mutex_lock (&wr->c.pp->e.lock); + wr->alive = true; + wr->alive_vclock++; + if (wr->xqos->liveliness.lease_duration != T_NEVER) + { + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT) + participant_add_wr_lease_locked (wr->c.pp, wr); + else if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC) + lease_set_expiry (wr->lease, add_duration_to_etime (now_et (), wr->lease->tdur)); + } + ddsrt_mutex_unlock (&wr->c.pp->e.lock); + + if (notify) + writer_notify_liveliness_change_may_unlock (wr); +} + +static int writer_set_notalive_locked (struct writer *wr, bool notify) +{ + if (!wr->alive) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + /* To update wr->alive, both wr->e.lock and wr->c.pp->e.lock + should be taken */ + ddsrt_mutex_lock (&wr->c.pp->e.lock); + wr->alive = false; + wr->alive_vclock++; + if (wr->xqos->liveliness.lease_duration != T_NEVER && wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT) + participant_remove_wr_lease_locked (wr->c.pp, wr); + ddsrt_mutex_unlock (&wr->c.pp->e.lock); + + if (notify) + { + if (wr->status_cb) + { + status_cb_data_t data; + data.handle = wr->e.iid; + data.raw_status_id = (int) DDS_LIVELINESS_LOST_STATUS_ID; + (wr->status_cb) (wr->status_cb_entity, &data); + } + writer_notify_liveliness_change_may_unlock (wr); + } + return DDS_RETCODE_OK; +} + +int writer_set_notalive (struct writer *wr, bool notify) +{ + ddsrt_mutex_lock (&wr->e.lock); + int ret = writer_set_notalive_locked(wr, notify); + ddsrt_mutex_unlock (&wr->e.lock); + return ret; +} + 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); @@ -3303,6 +3508,8 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->rexmit_count = 0; wr->rexmit_lost_count = 0; wr->force_md5_keyhash = 0; + wr->alive = 1; + wr->alive_vclock = 0; wr->status_cb = status_cb; wr->status_cb_entity = status_entity; @@ -3310,13 +3517,13 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se /* Copy QoS, merging in defaults */ wr->xqos = ddsrt_malloc (sizeof (*wr->xqos)); - nn_xqos_copy (wr->xqos, xqos); - nn_xqos_mergein_missing (wr->xqos, &wr->e.gv->default_xqos_wr, ~(uint64_t)0); + ddsi_xqos_copy (wr->xqos, xqos); + ddsi_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); ELOGDISC (wr, "WRITER "PGUIDFMT" QOS={", PGUID (wr->e.guid)); - nn_log_xqos (DDS_LC_DISCOVERY, &wr->e.gv->logconfig, wr->xqos); + ddsi_xqos_log (DDS_LC_DISCOVERY, &wr->e.gv->logconfig, wr->xqos); ELOGDISC (wr, "}\n"); assert (wr->xqos->present & QP_RELIABILITY); @@ -3417,7 +3624,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se } assert (wr->xqos->present & QP_LIVELINESS); - if (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC && wr->xqos->liveliness.lease_duration != T_NEVER) + if (wr->xqos->liveliness.lease_duration != T_NEVER) { wr->lease_duration = ddsrt_malloc (sizeof(*wr->lease_duration)); wr->lease_duration->ldur = wr->xqos->liveliness.lease_duration; @@ -3497,22 +3704,38 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g if (wr->lease_duration != NULL) { assert (wr->lease_duration->ldur != T_NEVER); - assert (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC); assert (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)); + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC) + { + /* Store writer lease duration in participant's heap in case of automatic liveliness */ + ddsrt_mutex_lock (&pp->e.lock); + ddsrt_fibheap_insert (&ldur_fhdef, &pp->ldur_auto_wr, wr->lease_duration); + ddsrt_mutex_unlock (&pp->e.lock); - /* Store writer lease duration in participant's heap in case of automatic liveliness */ - ddsrt_mutex_lock (&pp->e.lock); - ddsrt_fibheap_insert (&ldur_fhdef, &pp->ldur_auto_wr, wr->lease_duration); - ddsrt_mutex_unlock (&pp->e.lock); - - /* Trigger pmd update */ - (void) resched_xevent_if_earlier (pp->pmd_update_xevent, now_mt ()); + /* Trigger pmd update */ + (void) resched_xevent_if_earlier (pp->pmd_update_xevent, now_mt ()); + } + else + { + nn_etime_t texpire = add_duration_to_etime (now_et (), wr->lease_duration->ldur); + wr->lease = lease_new (texpire, wr->lease_duration->ldur, &wr->e); + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT) + { + ddsrt_mutex_lock (&pp->e.lock); + participant_add_wr_lease_locked (pp, wr); + ddsrt_mutex_unlock (&pp->e.lock); + } + else + { + lease_register (wr->lease); + } + } } return 0; } -dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_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_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_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; @@ -3534,7 +3757,7 @@ dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct dd 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 (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc) +struct local_orphan_writer *new_local_orphan_writer (struct ddsi_domaingv *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc) { ddsi_guid_t guid; struct local_orphan_writer *lowr; @@ -3603,23 +3826,23 @@ static void gc_delete_writer (struct gcreq *gcreq) { assert (wr->lease_duration->ldur == DDS_DURATION_INVALID); ddsrt_free (wr->lease_duration); + if (wr->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC) + lease_free (wr->lease); } /* Do last gasp on SEDP and free writer. */ if (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) sedp_dispose_unregister_writer (wr); - if (wr->status_cb) - { - (wr->status_cb) (wr->status_cb_entity, NULL); - } - whc_free (wr->whc); + if (wr->status_cb) + (wr->status_cb) (wr->status_cb_entity, NULL); + #ifdef DDSI_INCLUDE_SSM if (wr->ssm_as) unref_addrset (wr->ssm_as); #endif unref_addrset (wr->as); /* must remain until readers gone (rebuilding of addrset) */ - nn_xqos_fini (wr->xqos); + ddsi_xqos_fini (wr->xqos); ddsrt_free (wr->xqos); local_reader_ary_fini (&wr->rdary); ddsrt_cond_destroy (&wr->throttle_cond); @@ -3660,7 +3883,7 @@ static void writer_set_state (struct writer *wr, enum writer_state newstate) wr->state = newstate; } -dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid) +dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid) { struct writer *wr; assert (is_writer_entityid (guid->entityid)); @@ -3676,6 +3899,20 @@ dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_g return 0; } +dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout) +{ + dds_return_t rc; + seqno_t ref_seq; + ddsrt_mutex_lock (&wr->e.lock); + ref_seq = wr->seq; + while (wr->state == WRST_OPERATIONAL && ref_seq > writer_max_drop_seq (wr)) + if (!ddsrt_cond_waituntil (&wr->throttle_cond, &wr->e.lock, abstimeout)) + break; + rc = (ref_seq <= writer_max_drop_seq (wr)) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; + ddsrt_mutex_unlock (&wr->e.lock); + return rc; +} + dds_return_t delete_writer_nolinger_locked (struct writer *wr) { ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid)); @@ -3685,17 +3922,27 @@ dds_return_t delete_writer_nolinger_locked (struct writer *wr) entidx_remove_writer_guid (wr->e.gv->entity_index, wr); writer_set_state (wr, WRST_DELETING); if (wr->lease_duration != NULL) { - ddsrt_mutex_lock (&wr->c.pp->e.lock); - ddsrt_fibheap_delete (&ldur_fhdef, &wr->c.pp->ldur_auto_wr, wr->lease_duration); - ddsrt_mutex_unlock (&wr->c.pp->e.lock); wr->lease_duration->ldur = DDS_DURATION_INVALID; - resched_xevent_if_earlier (wr->c.pp->pmd_update_xevent, now_mt ()); + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC) + { + ddsrt_mutex_lock (&wr->c.pp->e.lock); + ddsrt_fibheap_delete (&ldur_fhdef, &wr->c.pp->ldur_auto_wr, wr->lease_duration); + ddsrt_mutex_unlock (&wr->c.pp->e.lock); + resched_xevent_if_earlier (wr->c.pp->pmd_update_xevent, now_mt ()); + } + else + { + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC) + lease_unregister (wr->lease); + if (writer_set_notalive_locked (wr, false) != DDS_RETCODE_OK) + ELOGDISC (wr, "writer_set_notalive failed for "PGUIDFMT"\n", PGUID (wr->e.guid)); + } } gcreq_writer (wr); return 0; } -dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid) +dds_return_t delete_writer_nolinger (struct ddsi_domaingv *gv, const struct ddsi_guid *guid) { struct writer *wr; /* We take no care to ensure application writers are not deleted @@ -3725,7 +3972,7 @@ void delete_local_orphan_writer (struct local_orphan_writer *lowr) ddsrt_mutex_unlock (&lowr->wr.e.lock); } -dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid) +dds_return_t delete_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid) { struct writer *wr; struct whc_state whcst; @@ -3766,7 +4013,7 @@ dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid) /* READER ----------------------------------------------------------- */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS -static struct addrset *get_as_from_mapping (const struct q_globals *gv, const char *partition, const char *topic) +static struct addrset *get_as_from_mapping (const struct ddsi_domaingv *gv, const char *partition, const char *topic) { struct config_partitionmapping_listelem *pm; struct addrset *as = new_addrset (); @@ -3782,13 +4029,13 @@ static struct addrset *get_as_from_mapping (const struct q_globals *gv, const ch struct join_leave_mcast_helper_arg { ddsi_tran_conn_t conn; - struct q_globals *gv; + struct ddsi_domaingv *gv; }; static void join_mcast_helper (const nn_locator_t *n, void *varg) { struct join_leave_mcast_helper_arg *arg = varg; - struct q_globals *gv = arg->gv; + struct ddsi_domaingv *gv = arg->gv; if (ddsi_is_mcaddr (gv, n)) { if (n->kind != NN_LOCATOR_KIND_UDPv4MCGEN) @@ -3830,7 +4077,7 @@ static void join_mcast_helper (const nn_locator_t *n, void *varg) static void leave_mcast_helper (const nn_locator_t *n, void *varg) { struct join_leave_mcast_helper_arg *arg = varg; - struct q_globals *gv = arg->gv; + struct ddsi_domaingv *gv = arg->gv; if (ddsi_is_mcaddr (gv, n)) { if (n->kind != NN_LOCATOR_KIND_UDPv4MCGEN) @@ -3902,15 +4149,15 @@ static dds_return_t new_reader_guid /* Copy QoS, merging in defaults */ rd->xqos = ddsrt_malloc (sizeof (*rd->xqos)); - nn_xqos_copy (rd->xqos, xqos); - nn_xqos_mergein_missing (rd->xqos, &pp->e.gv->default_xqos_rd, ~(uint64_t)0); + ddsi_xqos_copy (rd->xqos, xqos); + ddsi_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 (rd->e.gv->logconfig.c.mask & DDS_LC_DISCOVERY) { ELOGDISC (rd, "READER "PGUIDFMT" QOS={", PGUID (rd->e.guid)); - nn_log_xqos (DDS_LC_DISCOVERY, &rd->e.gv->logconfig, rd->xqos); + ddsi_xqos_log (DDS_LC_DISCOVERY, &rd->e.gv->logconfig, rd->xqos); ELOGDISC (rd, "}\n"); } assert (rd->xqos->present & QP_RELIABILITY); @@ -4017,7 +4264,7 @@ static dds_return_t new_reader_guid dds_return_t new_reader ( struct reader **rd_out, - struct q_globals *gv, + struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, @@ -4086,7 +4333,7 @@ static void gc_delete_reader (struct gcreq *gcreq) } ddsi_sertopic_unref ((struct ddsi_sertopic *) rd->topic); - nn_xqos_fini (rd->xqos); + ddsi_xqos_fini (rd->xqos); ddsrt_free (rd->xqos); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS unref_addrset (rd->as); @@ -4096,7 +4343,7 @@ static void gc_delete_reader (struct gcreq *gcreq) ddsrt_free (rd); } -dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid) +dds_return_t delete_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *guid) { struct reader *rd; assert (!is_writer_entityid (guid->entityid)); @@ -4121,21 +4368,13 @@ void update_reader_qos (struct reader *rd, const dds_qos_t *xqos) } /* PROXY-PARTICIPANT ------------------------------------------------ */ -const ddsrt_fibheap_def_t lease_fhdef_proxypp = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, pp_heapnode), compare_lease_tdur); - -static void gc_proxy_participant_lease (struct gcreq *gcreq) -{ - lease_free (gcreq->arg); - gcreq_free (gcreq); -} - static void proxy_participant_replace_minl (struct proxy_participant *proxypp, bool manbypp, struct lease *lnew) { /* By loading/storing the pointer atomically, we ensure we always read a valid (or once valid) lease. By delaying freeing the lease through the garbage collector, we ensure whatever lease update occurs in parallel completes before the memory is released. */ - struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease); + struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_participant_lease); struct lease *lease_old = ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto); lease_unregister (lease_old); /* ensures lease will not expire while it is replaced */ gcreq->arg = lease_old; @@ -4148,11 +4387,11 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct ddsrt_mutex_lock (&proxypp->e.lock); if (proxypp->owns_lease) { - struct lease *minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto); - ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease); + struct lease *minl = ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_auto); + ddsrt_fibheap_delete (&lease_fhdef_pp, &proxypp->leaseheap_auto, proxypp->lease); if (minl == proxypp->lease) { - if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto)) != NULL) + if ((minl = ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_auto)) != NULL) { dds_duration_t trem = minl->tdur - proxypp->lease->tdur; assert (trem >= 0); @@ -4179,7 +4418,7 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct The lease_unregister call ensures the lease will never expire while we are messing with it. */ - struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease); + struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_participant_lease); lease_unregister (proxypp->lease); gcreq->arg = proxypp->lease; gcreq_enqueue (gcreq); @@ -4197,7 +4436,7 @@ struct bestab { }; static void create_proxy_builtin_endpoints( - struct q_globals *gv, + struct ddsi_domaingv *gv, const struct bestab *bestab, int nbes, const struct ddsi_guid *ppguid, @@ -4206,16 +4445,16 @@ static void create_proxy_builtin_endpoints( dds_qos_t *xqos_wr, dds_qos_t *xqos_rd) { - nn_plist_t plist_rd, plist_wr; + ddsi_plist_t plist_rd, plist_wr; int i; /* Note: no entity name or group GUID supplied, but that shouldn't * matter, as these are internal to DDSI and don't use group * coherency */ - nn_plist_init_empty (&plist_wr); - nn_plist_init_empty (&plist_rd); - nn_xqos_copy (&plist_wr.qos, xqos_wr); - nn_xqos_copy (&plist_rd.qos, xqos_rd); + ddsi_plist_init_empty (&plist_wr); + ddsi_plist_init_empty (&plist_rd); + ddsi_xqos_copy (&plist_wr.qos, xqos_wr); + ddsi_xqos_copy (&plist_rd.qos, xqos_rd); for (i = 0; i < nbes; i++) { const struct bestab *te = &bestab[i]; @@ -4240,13 +4479,13 @@ static void create_proxy_builtin_endpoints( } } } - nn_plist_fini (&plist_wr); - nn_plist_fini (&plist_rd); + ddsi_plist_fini (&plist_wr); + ddsi_plist_fini (&plist_rd); } static void add_proxy_builtin_endpoints( - struct q_globals *gv, + struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, struct proxy_participant *proxypp, nn_wctime_t timestamp) @@ -4273,12 +4512,6 @@ static void add_proxy_builtin_endpoints( LTE (PARTICIPANT_MESSAGE_DATA_READER, P2P, PARTICIPANT_MESSAGE_READER), TE (DISC_, TOPIC_ANNOUNCER, SEDP, TOPIC_WRITER), TE (DISC_, TOPIC_DETECTOR, SEDP, TOPIC_READER), - PT_TE (DISC_, CM_PARTICIPANT_READER, SEDP, CM_PARTICIPANT_READER), - PT_TE (DISC_, CM_PARTICIPANT_WRITER, SEDP, CM_PARTICIPANT_WRITER), - PT_TE (DISC_, CM_PUBLISHER_READER, SEDP, CM_PUBLISHER_READER), - PT_TE (DISC_, CM_PUBLISHER_WRITER, SEDP, CM_PUBLISHER_WRITER), - PT_TE (DISC_, CM_SUBSCRIBER_READER, SEDP, CM_SUBSCRIBER_READER), - PT_TE (DISC_, CM_SUBSCRIBER_WRITER, SEDP, CM_SUBSCRIBER_WRITER) }; create_proxy_builtin_endpoints(gv, bestab_default, @@ -4339,15 +4572,15 @@ static void add_proxy_builtin_endpoints( &gv->builtin_stateless_xqos_rd); #endif + /* write DCPSParticipant topic before the lease can expire */ + builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true); + /* Register lease for auto liveliness, but be careful not to accidentally re-register DDSI2's lease, as we may have become dependent on DDSI2 any time after entidx_insert_proxy_participant_guid even if privileged_pp_guid was NULL originally */ ddsrt_mutex_lock (&proxypp->e.lock); - if (proxypp->owns_lease) lease_register (ddsrt_atomic_ldvoidp (&proxypp->minl_auto)); - - builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true); ddsrt_mutex_unlock (&proxypp->e.lock); #undef PT_TE @@ -4365,9 +4598,9 @@ static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * p assert (pwr->lease != NULL); manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT); lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto; - minl_prev = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh); - ddsrt_fibheap_insert (&lease_fhdef_proxypp, lh, pwr->lease); - minl_new = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh); + minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, lh); + ddsrt_fibheap_insert (&lease_fhdef_pp, lh, pwr->lease); + minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, lh); /* if inserted lease is new shortest lease */ if (proxypp->owns_lease && minl_prev != minl_new) { @@ -4396,12 +4629,12 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant assert (pwr->lease != NULL); manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT); lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto; - minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh); - ddsrt_fibheap_delete (&lease_fhdef_proxypp, lh, pwr->lease); + minl = ddsrt_fibheap_min (&lease_fhdef_pp, lh); + ddsrt_fibheap_delete (&lease_fhdef_pp, lh, pwr->lease); /* if pwr with min lease is removed: update proxypp lease to use new minimal duration */ if (proxypp->owns_lease && pwr->lease == minl) { - if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh)) != NULL) + if ((minl = ddsrt_fibheap_min (&lease_fhdef_pp, lh)) != NULL) { dds_duration_t trem = minl->tdur - pwr->lease->tdur; assert (trem >= 0); @@ -4421,7 +4654,7 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant void handshake_end_cb ( - struct q_globals const * const gv, + struct ddsi_domaingv const * const gv, struct ddsi_handshake *handshake, const struct ddsi_guid *lpguid, const struct ddsi_guid *ppguid, @@ -4492,7 +4725,7 @@ void handshake_end_cb } } -static int proxy_participant_check_security_info(struct q_globals *gv, struct proxy_participant *proxypp) +static int proxy_participant_check_security_info(struct ddsi_domaingv *gv, struct proxy_participant *proxypp) { int r = 0; struct participant *pp; @@ -4510,7 +4743,7 @@ static int proxy_participant_check_security_info(struct q_globals *gv, struct pr } -static void proxy_participant_create_handshakes(struct q_globals *gv, struct proxy_participant *proxypp) +static void proxy_participant_create_handshakes(struct ddsi_domaingv *gv, struct proxy_participant *proxypp) { struct participant *pp; struct entidx_enum_participant est; @@ -4527,48 +4760,32 @@ static void proxy_participant_create_handshakes(struct q_globals *gv, struct pro #endif -#ifdef DDSI_INCLUDE_SECURITY - static void free_proxy_participant(struct proxy_participant *proxypp) { - q_omg_security_deregister_remote_participant(proxypp); - unref_addrset (proxypp->as_default); - unref_addrset (proxypp->as_meta); - nn_plist_fini (proxypp->plist); - ddsrt_free (proxypp->plist); if (proxypp->owns_lease) { struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto); - ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease); - assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL); - assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL); + ddsrt_fibheap_delete (&lease_fhdef_pp, &proxypp->leaseheap_auto, proxypp->lease); + assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_auto) == NULL); + assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_man) == NULL); assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL); assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid)); lease_unregister (minl_auto); lease_free (minl_auto); lease_free (proxypp->lease); } +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_remote_participant(proxypp); +#endif + unref_addrset (proxypp->as_default); + unref_addrset (proxypp->as_meta); + ddsi_plist_fini (proxypp->plist); + ddsrt_free (proxypp->plist); entity_common_fini (&proxypp->e); ddsrt_free (proxypp); } -#endif -void new_proxy_participant -( - struct q_globals *gv, - const struct ddsi_guid *ppguid, - unsigned bes, - unsigned prismtech_bes, - const struct ddsi_guid *privileged_pp_guid, - struct addrset *as_default, - struct addrset *as_meta, - const nn_plist_t *plist, - dds_duration_t tlease_dur, - nn_vendorid_t vendor, - unsigned custom_flags, - nn_wctime_t timestamp, - seqno_t seq -) +void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const ddsi_plist_t *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq) { /* No locking => iff all participants use unique guids, and sedp runs on a single thread, it can't go wrong. FIXME, maybe? The @@ -4592,7 +4809,6 @@ void new_proxy_participant proxypp->deleting = 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; @@ -4616,8 +4832,8 @@ void new_proxy_participant struct proxy_participant *privpp; privpp = entidx_lookup_proxy_participant_guid (gv->entity_index, &proxypp->privileged_pp_guid); - ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_auto); - ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_man); + ddsrt_fibheap_init (&lease_fhdef_pp, &proxypp->leaseheap_auto); + ddsrt_fibheap_init (&lease_fhdef_pp, &proxypp->leaseheap_man); ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL); if (privpp != NULL && privpp->is_ddsi2_pp) @@ -4643,7 +4859,7 @@ void new_proxy_participant /* Add the proxypp lease to heap so that monitoring liveliness will include this lease and uses the shortest duration for proxypp and all its pwr's (with automatic liveliness) */ - ddsrt_fibheap_insert (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease); + ddsrt_fibheap_insert (&lease_fhdef_pp, &proxypp->leaseheap_auto, proxypp->lease); /* Set the shortest lease for auto liveliness: clone proxypp's lease and store the clone in proxypp->minl_auto. As there are no pwr's at this point, the proxy pp's lease is the @@ -4657,8 +4873,8 @@ void new_proxy_participant proxypp->as_default = as_default; 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); + proxypp->plist = ddsi_plist_dup (plist); + ddsi_xqos_mergein_missing (&proxypp->plist->qos, &gv->default_plist_pp.qos, ~(uint64_t)0); ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups); #ifdef DDSI_INCLUDE_SECURITY @@ -4686,14 +4902,6 @@ void new_proxy_participant proxypp->proxypp_have_spdp = 0; else proxypp->proxypp_have_spdp = 1; - /* Non-PrismTech doesn't implement the PT extensions and therefore won't generate - a CMParticipant; if a PT peer does not implement a CMParticipant writer, then it - presumably also is a handicapped implementation (perhaps simply an old one) */ - if (!vendor_is_eclipse_or_prismtech(proxypp->vendor) || - (proxypp->bes != 0 && !(proxypp->prismtech_bes & NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER))) - proxypp->proxypp_have_cm = 1; - else - proxypp->proxypp_have_cm = 0; #ifdef DDSI_INCLUDE_SECURITY if (secure) @@ -4743,39 +4951,31 @@ void new_proxy_participant #endif } -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_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, nn_wctime_t timestamp) { - 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); - if (seq > proxypp->seq) + { proxypp->seq = seq; - switch (source) - { - case UPD_PROXYPP_SPDP: - (void) 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; + struct ddsi_domaingv * const gv = proxypp->e.gv; + const uint64_t pmask = PP_ENTITY_NAME; + const uint64_t qmask = QP_USER_DATA; + ddsi_plist_t *new_plist = ddsrt_malloc (sizeof (*new_plist)); + ddsi_plist_init_empty (new_plist); + ddsi_plist_mergein_missing (new_plist, datap, pmask, qmask); + ddsi_plist_mergein_missing (new_plist, &gv->default_plist_pp, ~(uint64_t)0, ~(uint64_t)0); + (void) update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp); + ddsi_plist_fini (new_plist); + ddsrt_free (new_plist); + proxypp->proxypp_have_spdp = 1; } return 0; } -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) +int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, nn_wctime_t timestamp) { ddsrt_mutex_lock (&proxypp->e.lock); - update_proxy_participant_plist_locked (proxypp, seq, datap, source, timestamp); + update_proxy_participant_plist_locked (proxypp, seq, datap, timestamp); ddsrt_mutex_unlock (&proxypp->e.lock); return 0; } @@ -4823,32 +5023,13 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p if (refc == 0) { + struct ddsi_domaingv * const gv = proxypp->e.gv; + const ddsi_guid_t pp_guid = proxypp->e.guid; assert (proxypp->endpoints == NULL); - if (proxypp->owns_lease) - { - struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto); - ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease); - assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL); - assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL); - assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL); - assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid)); - lease_unregister (minl_auto); - lease_free (minl_auto); - lease_free (proxypp->lease); - } ddsrt_mutex_unlock (&proxypp->e.lock); ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid)); - -#ifdef DDSI_INCLUDE_SECURITY - q_omg_security_deregister_remote_participant(proxypp); -#endif - unref_addrset (proxypp->as_default); - unref_addrset (proxypp->as_meta); - nn_plist_fini (proxypp->plist); - ddsrt_free (proxypp->plist); - entity_common_fini (&proxypp->e); - remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE); - ddsrt_free (proxypp); + free_proxy_participant (proxypp); + remove_deleted_participant_guid (gv->deleted_participants, &pp_guid, DPG_LOCAL | DPG_REMOTE); } else if (proxypp->endpoints == NULL && proxypp->implicitly_created) { @@ -5032,7 +5213,7 @@ static void purge_helper (const nn_locator_t *n, void * varg) delete_proxy_participant_by_guid (data->proxypp->e.gv, &data->proxypp->e.guid, data->timestamp, 1); } -void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc) +void purge_proxy_participants (struct ddsi_domaingv *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. */ @@ -5055,7 +5236,7 @@ void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bo thread_state_asleep (ts1); } -int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_participant_by_guid (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) { struct proxy_participant *ppt; @@ -5078,7 +5259,7 @@ int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_gu return 0; } -uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid) +uint64_t get_entity_instance_id (const struct ddsi_domaingv *gv, const struct ddsi_guid *guid) { struct thread_state1 *ts1 = lookup_thread_state (); struct entity_common *e; @@ -5092,7 +5273,7 @@ uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_g /* PROXY-ENDPOINT --------------------------------------------------- */ -static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist) +static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const ddsi_plist_t *plist) { const char *name; int ret; @@ -5104,7 +5285,7 @@ static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_end name = (plist->present & PP_ENTITY_NAME) ? plist->entity_name : ""; entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false); - c->xqos = nn_xqos_dup (&plist->qos); + c->xqos = ddsi_xqos_dup (&plist->qos); c->as = ref_addrset (as); c->vendor = proxypp->vendor; c->seq = seq; @@ -5121,7 +5302,7 @@ static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_end if ((ret = ref_proxy_participant (proxypp, c)) != DDS_RETCODE_OK) { - nn_xqos_fini (c->xqos); + ddsi_xqos_fini (c->xqos); ddsrt_free (c->xqos); unref_addrset (c->as); entity_common_fini (e); @@ -5134,7 +5315,7 @@ static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_end static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_endpoint_common *c) { unref_proxy_participant (c->proxypp, c); - nn_xqos_fini (c->xqos); + ddsi_xqos_fini (c->xqos); ddsrt_free (c->xqos); unref_addrset (c->as); entity_common_fini (e); @@ -5156,7 +5337,7 @@ get_proxy_writer_reorder_mode(const ddsi_entityid_t pwr_entityid, int isreliable return NN_REORDER_MODE_MONOTONICALLY_INCREASING; } -int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq) +int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const ddsi_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; @@ -5400,7 +5581,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq) /* First stage in deleting the proxy writer. In this function the pwr and its member pointers will remain valid. The real cleaning-up is done async in gc_delete_proxy_writer. */ -int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) { struct proxy_writer *pwr; DDSRT_UNUSED_ARG (isimplicit); @@ -5434,7 +5615,7 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_ static void proxy_writer_notify_liveliness_change_may_unlock (struct proxy_writer *pwr) { - struct proxy_writer_alive_state alive_state; + struct alive_state alive_state; proxy_writer_get_alive_state_locked (pwr, &alive_state); struct ddsi_guid rdguid; @@ -5469,8 +5650,13 @@ void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify) ddsrt_mutex_lock (&pwr->c.proxypp->e.lock); pwr->alive = true; pwr->alive_vclock++; - if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC) - proxy_participant_add_pwr_lease_locked (pwr->c.proxypp, pwr); + if (pwr->c.xqos->liveliness.lease_duration != T_NEVER) + { + if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC) + proxy_participant_add_pwr_lease_locked (pwr->c.proxypp, pwr); + else + lease_set_expiry (pwr->lease, add_duration_to_etime (now_et (), pwr->lease->tdur)); + } ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock); if (notify) @@ -5501,23 +5687,9 @@ int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify) return DDS_RETCODE_OK; } -void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify) -{ - struct proxy_writer *pwr; - if ((pwr = entidx_lookup_proxy_writer_guid (gv->entity_index, pwrguid)) == NULL) - GVLOGDISC (" "PGUIDFMT"?\n", PGUID (*pwrguid)); - else - { - GVLOGDISC ("proxy_writer_set_notalive_guid ("PGUIDFMT")", PGUID (*pwrguid)); - if (proxy_writer_set_notalive (pwr, notify) == DDS_RETCODE_PRECONDITION_NOT_MET) - GVLOGDISC (" pwr was not alive"); - GVLOGDISC ("\n"); - } -} - /* PROXY-READER ----------------------------------------------------- */ -int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq +int new_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const ddsi_plist_t *plist, nn_wctime_t timestamp, seqno_t seq #ifdef DDSI_INCLUDE_SSM , int favours_ssm #endif @@ -5639,7 +5811,7 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq) ddsrt_free (prd); } -int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) +int delete_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit) { struct proxy_reader *prd; (void)isimplicit; diff --git a/src/core/ddsi/src/q_freelist.c b/src/core/ddsi/src/q_freelist.c index 9d1a1bc..28ed6ea 100644 --- a/src/core/ddsi/src/q_freelist.c +++ b/src/core/ddsi/src/q_freelist.c @@ -20,7 +20,7 @@ #if FREELIST_TYPE == FREELIST_NONE -void nn_freelist_init (struct nn_freelist *fl, uint32_t max, off_t linkoff) +void nn_freelist_init (struct nn_freelist *fl, uint32_t max, size_t linkoff) { (void) fl; (void) max; (void) linkoff; } @@ -50,7 +50,7 @@ void *nn_freelist_pop (struct nn_freelist *fl) #elif FREELIST_TYPE == FREELIST_ATOMIC_LIFO -void nn_freelist_init (struct nn_freelist *fl, uint32_t max, off_t linkoff) +void nn_freelist_init (struct nn_freelist *fl, uint32_t max, size_t linkoff) { ddsrt_atomic_lifo_init (&fl->x); ddsrt_atomic_st32(&fl->count, 0); @@ -104,7 +104,7 @@ void *nn_freelist_pop (struct nn_freelist *fl) static ddsrt_thread_local int freelist_inner_idx = -1; -void nn_freelist_init (struct nn_freelist *fl, uint32_t max, off_t linkoff) +void nn_freelist_init (struct nn_freelist *fl, uint32_t max, size_t linkoff) { int i; ddsrt_mutex_init (&fl->lock); diff --git a/src/core/ddsi/src/q_gc.c b/src/core/ddsi/src/q_gc.c index 948510d..4444112 100644 --- a/src/core/ddsi/src/q_gc.c +++ b/src/core/ddsi/src/q_gc.c @@ -24,7 +24,7 @@ #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_lease.h" -#include "dds/ddsi/q_globals.h" /* for mattr, cattr */ +#include "dds/ddsi/ddsi_domaingv.h" /* for mattr, cattr */ #include "dds/ddsi/q_receive.h" /* for trigger_receive_threads */ struct gcreq_queue { @@ -34,11 +34,11 @@ struct gcreq_queue { ddsrt_cond_t cond; int terminate; int32_t count; - struct q_globals *gv; + struct ddsi_domaingv *gv; struct thread_state1 *ts; }; -static void threads_vtime_gather_for_wait (const struct q_globals *gv, unsigned *nivs, struct idx_vtime *ivs) +static void threads_vtime_gather_for_wait (const struct ddsi_domaingv *gv, unsigned *nivs, struct idx_vtime *ivs) { /* copy vtimes of threads, skipping those that are sleeping */ uint32_t i, j; @@ -189,7 +189,7 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q) return 0; } -struct gcreq_queue *gcreq_queue_new (struct q_globals *gv) +struct gcreq_queue *gcreq_queue_new (struct ddsi_domaingv *gv) { struct gcreq_queue *q = ddsrt_malloc (sizeof (*q)); diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index 7765f59..a140b33 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -27,7 +27,7 @@ #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_lat_estim.h" @@ -42,7 +42,7 @@ #include "dds/ddsi/q_gc.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_nwif.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_receive.h" #include "dds/ddsi/q_pcap.h" @@ -64,7 +64,7 @@ #include "dds/ddsi/ddsi_security_omg.h" -static void add_peer_addresses (const struct q_globals *gv, struct addrset *as, const struct config_peer_listelem *list) +static void add_peer_addresses (const struct ddsi_domaingv *gv, struct addrset *as, const struct config_peer_listelem *list) { while (list) { @@ -79,7 +79,7 @@ enum make_uc_sockets_ret { MUSRET_NOSOCKET }; -static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid) +static enum make_uc_sockets_ret make_uc_sockets (struct ddsi_domaingv *gv, uint32_t * pdisc, uint32_t * pdata, int ppid) { if (gv->config.many_sockets_mode == MSM_NO_UNICAST) { @@ -129,7 +129,7 @@ static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) { - nn_xqos_copy (q, template); + ddsi_xqos_copy (q, template); q->reliability.kind = DDS_RELIABILITY_RELIABLE; q->reliability.max_blocking_time = 100 * T_MILLISECOND; q->durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL; @@ -138,7 +138,7 @@ static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) #ifdef DDSI_INCLUDE_SECURITY static void make_builtin_volatile_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) { - nn_xqos_copy (q, template); + ddsi_xqos_copy (q, template); q->reliability.kind = DDS_RELIABILITY_RELIABLE; q->reliability.max_blocking_time = 100 * T_MILLISECOND; q->durability.kind = DDS_DURABILITY_VOLATILE; @@ -158,7 +158,7 @@ static void add_property_to_xqos(dds_qos_t *q, const char *name, const char *val } #endif -static int set_recvips (struct q_globals *gv) +static int set_recvips (struct ddsi_domaingv *gv) { gv->recvips = NULL; @@ -263,7 +263,7 @@ static int set_recvips (struct q_globals *gv) * 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 (const struct q_globals *gv, nn_locator_t *loc, const char *string, uint32_t port, int mc, const char *tag) +static int string_to_default_locator (const struct ddsi_domaingv *gv, nn_locator_t *loc, const char *string, uint32_t port, int mc, const char *tag) { if (strspn (string, " \t") == strlen (string)) { @@ -302,11 +302,12 @@ static int string_to_default_locator (const struct q_globals *gv, nn_locator_t * return 1; } -static int set_spdp_address (struct q_globals *gv) +static int set_spdp_address (struct ddsi_domaingv *gv) { const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0); int rc = 0; /* FIXME: FIXME: FIXME: */ + gv->loc_spdp_mc.tran = NULL; gv->loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID; if (strcmp (gv->config.spdpMulticastAddressString, "239.255.0.1") != 0) { @@ -334,7 +335,7 @@ static int set_spdp_address (struct q_globals *gv) return 0; } -static int set_default_mc_address (struct q_globals *gv) +static int set_default_mc_address (struct ddsi_domaingv *gv) { const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0); int rc; @@ -348,7 +349,7 @@ static int set_default_mc_address (struct q_globals *gv) return 0; } -static int set_ext_address_and_mask (struct q_globals *gv) +static int set_ext_address_and_mask (struct ddsi_domaingv *gv) { nn_locator_t loc; int rc; @@ -367,6 +368,7 @@ static int set_ext_address_and_mask (struct q_globals *gv) if (!gv->config.externalMaskString || strcmp (gv->config.externalMaskString, "0.0.0.0") == 0) { memset(&gv->extmask.address, 0, sizeof(gv->extmask.address)); + gv->extmask.tran = NULL; gv->extmask.kind = NN_LOCATOR_KIND_INVALID; gv->extmask.port = NN_LOCATOR_PORT_INVALID; } @@ -384,7 +386,7 @@ static int set_ext_address_and_mask (struct q_globals *gv) } #ifdef DDSI_INCLUDE_NETWORK_CHANNELS -static int known_channel_p (const struct q_globals *gv, const char *name) +static int known_channel_p (const struct ddsi_domaingv *gv, const char *name) { const struct config_channel_listelem *c; for (c = gv->config.channels; c; c = c->next) @@ -394,7 +396,7 @@ static int known_channel_p (const struct q_globals *gv, const char *name) } #endif -static int check_thread_properties (const struct q_globals *gv) +static int check_thread_properties (const struct ddsi_domaingv *gv) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", "fsm", NULL }; @@ -434,7 +436,7 @@ static int check_thread_properties (const struct q_globals *gv) return ok; } -int rtps_config_open_trace (struct q_globals *gv) +int rtps_config_open_trace (struct ddsi_domaingv *gv) { DDSRT_WARNING_MSVC_OFF(4996); int status; @@ -470,7 +472,7 @@ int rtps_config_open_trace (struct q_globals *gv) DDSRT_WARNING_MSVC_ON(4996); } -int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst) +int rtps_config_prep (struct ddsi_domaingv *gv, struct cfgst *cfgst) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS unsigned num_channels = 0; @@ -636,7 +638,7 @@ err_config_late_error: } struct joinleave_spdp_defmcip_helper_arg { - struct q_globals *gv; + struct ddsi_domaingv *gv; int errcount; int dojoin; }; @@ -662,7 +664,7 @@ static void joinleave_spdp_defmcip_helper (const nn_locator_t *loc, void *varg) } } -int joinleave_spdp_defmcip (struct q_globals *gv, int dojoin) +int joinleave_spdp_defmcip (struct ddsi_domaingv *gv, int dojoin) { /* Addrset provides an easy way to filter out duplicates */ struct joinleave_spdp_defmcip_helper_arg arg; @@ -684,7 +686,7 @@ int joinleave_spdp_defmcip (struct q_globals *gv, int dojoin) return 0; } -int create_multicast_sockets (struct q_globals *gv) +int create_multicast_sockets (struct ddsi_domaingv *gv) { ddsi_tran_qos_t qos = ddsi_tran_create_qos (); ddsi_tran_conn_t disc, data; @@ -734,7 +736,7 @@ err_disc: return 0; } -static void rtps_term_prep (struct q_globals *gv) +static void rtps_term_prep (struct ddsi_domaingv *gv) { /* Stop all I/O */ ddsrt_mutex_lock (&gv->lock); @@ -749,7 +751,7 @@ static void rtps_term_prep (struct q_globals *gv) } struct wait_for_receive_threads_helper_arg { - struct q_globals *gv; + struct ddsi_domaingv *gv; unsigned count; }; @@ -762,7 +764,7 @@ static void wait_for_receive_threads_helper (struct xevent *xev, void *varg, nn_ (void) resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND)); } -static void wait_for_receive_threads (struct q_globals *gv) +static void wait_for_receive_threads (struct ddsi_domaingv *gv) { struct xevent *trigev; struct wait_for_receive_threads_helper_arg cbarg; @@ -790,7 +792,7 @@ static void wait_for_receive_threads (struct q_globals *gv) } } -static struct ddsi_sertopic *make_special_topic (struct serdatapool *serpool, uint16_t enc_id, const struct ddsi_serdata_ops *ops) +static struct ddsi_sertopic *make_special_topic (const char *name, 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 @@ -802,27 +804,63 @@ static struct ddsi_sertopic *make_special_topic (struct serdatapool *serpool, ui (kinda natural if they stop being "default" ones) */ struct ddsi_sertopic_default *st = ddsrt_malloc (sizeof (*st)); memset (st, 0, sizeof (*st)); - ddsi_sertopic_init_anon (&st->c, &ddsi_sertopic_ops_default, ops, false); + ddsi_sertopic_init (&st->c, name, name, &ddsi_sertopic_ops_default, ops, false); st->native_encoding_identifier = enc_id; st->serpool = serpool; - st->nkeys = 1; return (struct ddsi_sertopic *) st; } -static void make_special_topics (struct q_globals *gv) -{ - 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 (struct q_globals *gv) +static void free_special_topics (struct ddsi_domaingv *gv) { ddsi_sertopic_unref (gv->plist_topic); ddsi_sertopic_unref (gv->rawcdr_topic); } -static int setup_and_start_recv_threads (struct q_globals *gv) +static void make_special_topics (struct ddsi_domaingv *gv) { + gv->plist_topic = make_special_topic ("plist", gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? PL_CDR_LE : PL_CDR_BE, &ddsi_serdata_ops_plist); + gv->rawcdr_topic = make_special_topic ("rawcdr", gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE, &ddsi_serdata_ops_rawcdr); + + ddsrt_mutex_lock (&gv->sertopics_lock); + ddsi_sertopic_register_locked (gv, gv->plist_topic); + ddsi_sertopic_register_locked (gv, gv->rawcdr_topic); + ddsrt_mutex_unlock (&gv->sertopics_lock); + + /* register increments refcount (which is reasonable), but at some point + one needs to get rid of that reference */ + free_special_topics (gv); +} + +static bool use_multiple_receive_threads (const struct config *cfg) +{ + /* Under some unknown circumstances Windows (at least Windows 10) exhibits + the interesting behaviour of losing its ability to let us send packets + to our own sockets. When that happens, dedicated receive threads can no + longer be stopped and Cyclone hangs in shutdown. So until someone + figures out why this happens, it is probably best have a different + default on Windows. */ +#if _WIN32 + const bool def = false; +#else + const bool def = true; +#endif + switch (cfg->multiple_recv_threads) + { + case BOOLDEF_FALSE: + return false; + case BOOLDEF_TRUE: + return true; + case BOOLDEF_DEFAULT: + return def; + } + assert (0); + return false; +} + +static int setup_and_start_recv_threads (struct ddsi_domaingv *gv) +{ + const bool multi_recv_thr = use_multiple_receive_threads (&gv->config); + for (uint32_t i = 0; i < MAX_RECV_THREADS; i++) { gv->recv_threads[i].ts = NULL; @@ -837,7 +875,7 @@ static int setup_and_start_recv_threads (struct q_globals *gv) 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 (gv->m_factory->m_connless && gv->config.many_sockets_mode != MSM_NO_UNICAST && multi_recv_thr) { if (ddsi_is_mcaddr (gv, &gv->loc_default_mc) && !ddsi_is_ssm_mcaddr (gv, &gv->loc_default_mc) && (gv->config.allowMulticast & AMC_ASM)) { @@ -903,7 +941,17 @@ fail: return -1; } -int rtps_init (struct q_globals *gv) +static int ddsi_sertopic_equal_wrap (const void *a, const void *b) +{ + return ddsi_sertopic_equal (a, b); +} + +static uint32_t ddsi_sertopic_hash_wrap (const void *tp) +{ + return ddsi_sertopic_hash (tp); +} + +int rtps_init (struct ddsi_domaingv *gv) { uint32_t port_disc_uc = 0; uint32_t port_data_uc = 0; @@ -911,7 +959,7 @@ int rtps_init (struct q_globals *gv) gv->tstart = now (); /* wall clock time, used in logs */ - nn_plist_init_tables (); + ddsi_plist_init_tables (); gv->disc_conn_uc = NULL; gv->data_conn_uc = NULL; @@ -982,7 +1030,7 @@ int rtps_init (struct q_globals *gv) { if (!gv->interfaces[gv->selected_interface].mc_capable) { - GVWARNING ("selected interface is not multicast-capable: disabling multicast\n"); + GVWARNING ("selected interface \"%s\" is not multicast-capable: disabling multicast\n", gv->interfaces[gv->selected_interface].name); 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 @@ -1021,12 +1069,11 @@ int rtps_init (struct q_globals *gv) { 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 */ - 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)); + GVLOG (DDS_LC_CONFIG, "ownip: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv->ownloc)); + GVLOG (DDS_LC_CONFIG, "extip: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv->extloc)); + GVLOG (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)" : ""); + GVLOG (DDS_LC_CONFIG, "SPDP MC: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv->loc_spdp_mc)); + GVLOG (DDS_LC_CONFIG, "default MC: %s\n", ddsi_locator_to_string_no_port (buf, sizeof(buf), &gv->loc_default_mc)); #ifdef DDSI_INCLUDE_SSM GVLOG (DDS_LC_CONFIG, "SSM support included\n"); #endif @@ -1059,23 +1106,23 @@ int rtps_init (struct q_globals *gv) gv->xmsgpool = nn_xmsgpool_new (); gv->serpool = ddsi_serdatapool_new (); - 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); + ddsi_plist_init_default_participant (&gv->default_plist_pp); + ddsi_plist_init_default_participant (&gv->default_local_plist_pp); + ddsi_xqos_init_default_reader (&gv->default_xqos_rd); + ddsi_xqos_init_default_writer (&gv->default_xqos_wr); + ddsi_xqos_init_default_writer_noautodispose (&gv->default_xqos_wr_nad); + ddsi_xqos_init_default_topic (&gv->default_xqos_tp); + ddsi_xqos_init_default_subscriber (&gv->default_xqos_sub); + ddsi_xqos_init_default_publisher (&gv->default_xqos_pub); + ddsi_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); #ifdef DDSI_INCLUDE_SECURITY make_builtin_volatile_endpoint_xqos(&gv->builtin_volatile_xqos_rd, &gv->default_xqos_rd); make_builtin_volatile_endpoint_xqos(&gv->builtin_volatile_xqos_wr, &gv->default_xqos_wr); - nn_xqos_copy (&gv->builtin_stateless_xqos_rd, &gv->default_xqos_rd); - nn_xqos_copy (&gv->builtin_stateless_xqos_wr, &gv->default_xqos_wr); + ddsi_xqos_copy (&gv->builtin_stateless_xqos_rd, &gv->default_xqos_rd); + ddsi_xqos_copy (&gv->builtin_stateless_xqos_wr, &gv->default_xqos_wr); gv->builtin_stateless_xqos_wr.reliability.kind = DDS_RELIABILITY_BEST_EFFORT; gv->builtin_stateless_xqos_wr.durability.kind = DDS_DURABILITY_VOLATILE; @@ -1083,10 +1130,12 @@ int rtps_init (struct q_globals *gv) * the entities (see DDS Security spec chapter 8.8.8.1). */ add_property_to_xqos(&gv->builtin_volatile_xqos_rd, "dds.sec.builtin_endpoint_name", "BuiltinParticipantVolatileMessageSecureReader"); add_property_to_xqos(&gv->builtin_volatile_xqos_wr, "dds.sec.builtin_endpoint_name", "BuiltinParticipantVolatileMessageSecureWriter"); - + q_omg_security_init( &gv->security_context, &gv->logconfig ); #endif + ddsrt_mutex_init (&gv->sertopics_lock); + gv->sertopics = ddsrt_hh_new (1, ddsi_sertopic_hash_wrap, ddsi_sertopic_equal_wrap); make_special_topics (gv); ddsrt_mutex_init (&gv->participant_set_lock); @@ -1354,7 +1403,7 @@ int rtps_init (struct q_globals *gv) { struct config_peer_listelem peer_local; char local_addr[DDSI_LOCSTRLEN]; - ddsi_locator_to_string_no_port (gv, local_addr, sizeof (local_addr), &gv->interfaces[gv->selected_interface].loc); + ddsi_locator_to_string_no_port (local_addr, sizeof (local_addr), &gv->interfaces[gv->selected_interface].loc); peer_local.next = NULL; peer_local.peer = local_addr; add_peer_addresses (gv, gv->as_disc, &peer_local); @@ -1419,25 +1468,34 @@ err_unicast_sockets: ddsrt_cond_destroy (&gv->participant_set_cond); ddsrt_mutex_destroy (&gv->participant_set_lock); free_special_topics (gv); +#ifndef NDEBUG + { + struct ddsrt_hh_iter it; + assert (ddsrt_hh_iter_first (gv->sertopics, &it) == NULL); + } +#endif + ddsrt_hh_free (gv->sertopics); + ddsrt_mutex_destroy (&gv->sertopics_lock); #ifdef DDSI_INCLUDE_SECURITY - nn_xqos_fini (&gv->builtin_stateless_xqos_wr); - nn_xqos_fini (&gv->builtin_stateless_xqos_rd); - nn_xqos_fini (&gv->builtin_volatile_xqos_wr); - nn_xqos_fini (&gv->builtin_volatile_xqos_rd); - + ddsi_xqos_fini (&gv->builtin_stateless_xqos_wr); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_rd); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); + q_omg_security_deinit( &gv->security_context ); #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_local_plist_pp); - nn_plist_fini (&gv->default_plist_pp); + ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); + ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); + ddsi_xqos_fini (&gv->spdp_endpoint_xqos); + ddsi_xqos_fini (&gv->default_xqos_pub); + ddsi_xqos_fini (&gv->default_xqos_sub); + ddsi_xqos_fini (&gv->default_xqos_tp); + ddsi_xqos_fini (&gv->default_xqos_wr_nad); + ddsi_xqos_fini (&gv->default_xqos_wr); + ddsi_xqos_fini (&gv->default_xqos_rd); + ddsi_plist_fini (&gv->default_local_plist_pp); + ddsi_plist_fini (&gv->default_plist_pp); + ddsi_serdatapool_free (gv->serpool); nn_xmsgpool_free (gv->xmsgpool); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS @@ -1472,7 +1530,7 @@ static void stop_all_xeventq_upto (struct config_channel_listelem *chptr) } #endif -int rtps_start (struct q_globals *gv) +int rtps_start (struct ddsi_domaingv *gv) { if (xeventq_start (gv->xevents, NULL) < 0) return -1; @@ -1538,7 +1596,7 @@ static void builtins_dqueue_ready_cb (void *varg) ddsrt_mutex_unlock (&arg->lock); } -void rtps_stop (struct q_globals *gv) +void rtps_stop (struct ddsi_domaingv *gv) { struct thread_state1 * const ts1 = lookup_thread_state (); @@ -1669,7 +1727,7 @@ void rtps_stop (struct q_globals *gv) ddsrt_mutex_destroy (&gv->privileged_pp_lock); } -void rtps_fini (struct q_globals *gv) +void rtps_fini (struct ddsi_domaingv *gv) { /* Shut down the GC system -- no new requests will be added */ gcreq_queue_free (gv->gcreq_queue); @@ -1765,25 +1823,34 @@ void rtps_fini (struct q_globals *gv) ddsrt_cond_destroy (&gv->participant_set_cond); free_special_topics (gv); +#ifndef NDEBUG + { + struct ddsrt_hh_iter it; + assert (ddsrt_hh_iter_first (gv->sertopics, &it) == NULL); + } +#endif + ddsrt_hh_free (gv->sertopics); + ddsrt_mutex_destroy (&gv->sertopics_lock); + #ifdef DDSI_INCLUDE_SECURITY - nn_xqos_fini (&gv->builtin_stateless_xqos_wr); - nn_xqos_fini (&gv->builtin_stateless_xqos_rd); - nn_xqos_fini (&gv->builtin_volatile_xqos_wr); - nn_xqos_fini (&gv->builtin_volatile_xqos_rd); - + ddsi_xqos_fini (&gv->builtin_stateless_xqos_wr); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_rd); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); + q_omg_security_deinit( &gv->security_context); #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_local_plist_pp); - nn_plist_fini (&gv->default_plist_pp); + ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); + ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); + ddsi_xqos_fini (&gv->spdp_endpoint_xqos); + ddsi_xqos_fini (&gv->default_xqos_pub); + ddsi_xqos_fini (&gv->default_xqos_sub); + ddsi_xqos_fini (&gv->default_xqos_tp); + ddsi_xqos_fini (&gv->default_xqos_wr_nad); + ddsi_xqos_fini (&gv->default_xqos_wr); + ddsi_xqos_fini (&gv->default_xqos_rd); + ddsi_plist_fini (&gv->default_local_plist_pp); + ddsi_plist_fini (&gv->default_plist_pp); ddsrt_mutex_destroy (&gv->lock); diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c index a903ab2..7e8f9f3 100644 --- a/src/core/ddsi/src/q_lease.c +++ b/src/core/ddsi/src/q_lease.c @@ -24,7 +24,7 @@ #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_xevent.h" #include "dds/ddsi/q_addrset.h" @@ -32,7 +32,7 @@ #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_transmit.h" @@ -64,13 +64,13 @@ int compare_lease_tdur (const void *va, const void *vb) return (a->tdur == b->tdur) ? 0 : (a->tdur < b->tdur) ? -1 : 1; } -void lease_management_init (struct q_globals *gv) +void lease_management_init (struct ddsi_domaingv *gv) { ddsrt_mutex_init (&gv->leaseheap_lock); ddsrt_fibheap_init (&lease_fhdef, &gv->leaseheap); } -void lease_management_term (struct q_globals *gv) +void lease_management_term (struct ddsi_domaingv *gv) { assert (ddsrt_fibheap_min (&lease_fhdef, &gv->leaseheap) == NULL); ddsrt_mutex_destroy (&gv->leaseheap_lock); @@ -105,7 +105,7 @@ struct lease *lease_clone (const struct lease *l) void lease_register (struct lease *l) /* FIXME: make lease admin struct */ { - struct q_globals * const gv = l->entity->gv; + struct ddsi_domaingv * 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); @@ -123,7 +123,7 @@ void lease_register (struct lease *l) /* FIXME: make lease admin struct */ void lease_unregister (struct lease *l) { - struct q_globals * const gv = l->entity->gv; + struct ddsi_domaingv * const gv = l->entity->gv; GVTRACE ("lease_unregister(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) @@ -139,11 +139,27 @@ void lease_unregister (struct lease *l) void lease_free (struct lease *l) { - struct q_globals * const gv = l->entity->gv; + struct ddsi_domaingv * const gv = l->entity->gv; GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid)); ddsrt_free (l); } +static void trace_lease_renew (const struct lease *l, const char *tag, nn_etime_t tend_new) +{ + struct ddsi_domaingv const * gv = l->entity->gv; + if (gv->logconfig.c.mask & DDS_LC_TRACE) + { + int32_t tsec, tusec; + GVTRACE (" L(%s", tag); + if (l->entity->guid.entityid.u == NN_ENTITYID_PARTICIPANT) + GVTRACE (":%"PRIx32, l->entity->guid.entityid.u); + else + GVTRACE (""PGUIDFMT"", PGUID (l->entity->guid)); + etime_to_sec_usec (&tsec, &tusec, tend_new); + GVTRACE (" %"PRId32".%06"PRId32")", tsec, tusec); + } +} + void lease_renew (struct lease *l, nn_etime_t tnowE) { nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur); @@ -160,23 +176,12 @@ void lease_renew (struct lease *l, nn_etime_t tnowE) * lease (i.e. the entity still exists). In cases where dereferencing l->entity->gv * is not safe (e.g. the deletion of entities), the early out in the loop above * will be the case because tend is set to T_NEVER. */ - struct q_globals const * gv = l->entity->gv; - if (gv->logconfig.c.mask & DDS_LC_TRACE) - { - int32_t tsec, tusec; - GVTRACE (" L("); - if (l->entity->guid.entityid.u == NN_ENTITYID_PARTICIPANT) - GVTRACE (":%"PRIx32, l->entity->guid.entityid.u); - else - GVTRACE (""PGUIDFMT"", PGUID (l->entity->guid)); - etime_to_sec_usec (&tsec, &tusec, tend_new); - GVTRACE (" %"PRId32".%06"PRId32")", tsec, tusec); - } + trace_lease_renew (l, "", tend_new); } void lease_set_expiry (struct lease *l, nn_etime_t when) { - struct q_globals * const gv = l->entity->gv; + struct ddsi_domaingv * const gv = l->entity->gv; bool trigger = false; assert (when.v >= 0); ddsrt_mutex_lock (&gv->leaseheap_lock); @@ -189,6 +194,7 @@ void lease_set_expiry (struct lease *l, nn_etime_t when) TSCHED_NOT_ON_HEAP == INT64_MIN) */ l->tsched = when; ddsrt_fibheap_decrease_key (&lease_fhdef, &gv->leaseheap, l); + trace_lease_renew (l, "earlier ", when); trigger = true; } else if (l->tsched.v == TSCHED_NOT_ON_HEAP && when.v < T_NEVER) @@ -196,6 +202,7 @@ void lease_set_expiry (struct lease *l, nn_etime_t when) /* not currently scheduled, with a finite new expiry time */ l->tsched = when; ddsrt_fibheap_insert (&lease_fhdef, &gv->leaseheap, l); + trace_lease_renew (l, "insert ", when); trigger = true; } ddsrt_mutex_unlock (&gv->leaseheap_lock); @@ -205,7 +212,7 @@ void lease_set_expiry (struct lease *l, nn_etime_t when) force_lease_check (gv->gcreq_queue); } -int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnowE) +int64_t check_and_handle_lease_expiration (struct ddsi_domaingv *gv, nn_etime_t tnowE) { struct lease *l; int64_t delay; @@ -281,11 +288,13 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow delete_proxy_participant_by_guid (gv, &g, now(), 1); break; case EK_PROXY_WRITER: - proxy_writer_set_notalive_guid (gv, &g, true); + proxy_writer_set_notalive ((struct proxy_writer *) l->entity, true); + break; + case EK_WRITER: + writer_set_notalive ((struct writer *) l->entity, true); break; case EK_PARTICIPANT: case EK_READER: - case EK_WRITER: case EK_PROXY_READER: assert (false); break; diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c index c5c4c85..7b96a2f 100644 --- a/src/core/ddsi/src/q_nwif.c +++ b/src/core/ddsi/src/q_nwif.c @@ -24,7 +24,7 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_nwif.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_misc.h" @@ -214,7 +214,7 @@ static int set_reuse_options (const struct ddsrt_log_cfg *logcfg, ddsrt_socket_t return 0; } -static int bind_socket (ddsrt_socket_t socket, unsigned short port, const struct q_globals *gv) +static int bind_socket (ddsrt_socket_t socket, unsigned short port, const struct ddsi_domaingv *gv) { dds_return_t rc = DDS_RETCODE_ERROR; @@ -249,7 +249,7 @@ static int bind_socket (ddsrt_socket_t socket, unsigned short port, const struct } #if DDSRT_HAVE_IPV6 -static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket, const struct q_globals *gv) +static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket, const struct ddsi_domaingv *gv) { unsigned interfaceNo = gv->interfaceNo; unsigned ttl = (unsigned) gv->config.multicast_ttl; @@ -274,7 +274,7 @@ static int set_mc_options_transmit_ipv6 (ddsrt_socket_t socket, const struct q_g } #endif -static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket, const struct q_globals *gv) +static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket, const struct ddsi_domaingv *gv) { unsigned char ttl = (unsigned char) gv->config.multicast_ttl; unsigned char loop; @@ -319,7 +319,7 @@ static int set_mc_options_transmit_ipv4 (ddsrt_socket_t socket, const struct q_g return 0; } -static int set_mc_options_transmit (ddsrt_socket_t socket, const struct q_globals *gv) +static int set_mc_options_transmit (ddsrt_socket_t socket, const struct ddsi_domaingv *gv) { #if DDSRT_HAVE_IPV6 if (gv->config.transport_selector == TRANS_TCP6 || gv->config.transport_selector == TRANS_UDP6) @@ -338,7 +338,7 @@ static int set_mc_options_transmit (ddsrt_socket_t socket, const struct q_global } } -int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, const struct q_globals *gv) +int make_socket (ddsrt_socket_t *sock, uint16_t port, bool stream, bool reuse, const struct ddsi_domaingv *gv) { /* FIXME: this stuff has to move to the transports */ int rc = -2; @@ -433,7 +433,7 @@ static int multicast_override(const char *ifname, const struct config *config) #include #endif -int find_own_ip (struct q_globals *gv, const char *requested_address) +int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address) { const char *sep = " "; char last_if_name[80] = ""; @@ -504,9 +504,9 @@ int find_own_ip (struct q_globals *gv, 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->m_factory, &gv->interfaces[gv->n_interfaces].loc, ifa->addr, gv->m_factory->m_kind); } - ddsi_locator_to_string_no_port(gv, addrbuf, sizeof(addrbuf), &gv->interfaces[gv->n_interfaces].loc); + ddsi_locator_to_string_no_port(addrbuf, sizeof(addrbuf), &gv->interfaces[gv->n_interfaces].loc); GVLOG (DDS_LC_CONFIG, " %s(", addrbuf); if (!(ifa->flags & IFF_MULTICAST) && multicast_override (if_name, &gv->config)) @@ -568,7 +568,7 @@ int find_own_ip (struct q_globals *gv, 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->m_factory, &gv->interfaces[gv->n_interfaces].netmask, ifa->netmask, gv->m_factory->m_kind); } else { @@ -593,7 +593,7 @@ int find_own_ip (struct q_globals *gv, const char *requested_address) const int idx = maxq_list[0]; char *names; int p; - ddsi_locator_to_string_no_port (gv, addrbuf, sizeof(addrbuf), &gv->interfaces[idx].loc); + ddsi_locator_to_string_no_port (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++) diff --git a/src/core/ddsi/src/q_pcap.c b/src/core/ddsi/src/q_pcap.c index 1ac6117..42b2824 100644 --- a/src/core/ddsi/src/q_pcap.c +++ b/src/core/ddsi/src/q_pcap.c @@ -16,7 +16,7 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_pcap.h" @@ -127,7 +127,7 @@ static uint16_t calc_ipv4_checksum (const uint16_t *x) return (uint16_t) ~s; } -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_received (struct ddsi_domaingv *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, const struct sockaddr_storage *dst, unsigned char *buf, size_t sz) { if (gv->config.transport_selector == TRANS_UDP) { @@ -160,7 +160,7 @@ void write_pcap_received (struct q_globals *gv, nn_wctime_t tstamp, const struct } } -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) +void write_pcap_sent (struct ddsi_domaingv *gv, nn_wctime_t tstamp, const struct sockaddr_storage *src, const ddsrt_msghdr_t *hdr, size_t sz) { if (gv->config.transport_selector == TRANS_UDP) { diff --git a/src/core/ddsi/src/q_qosmatch.c b/src/core/ddsi/src/q_qosmatch.c index 721a010..7c951e1 100644 --- a/src/core/ddsi/src/q_qosmatch.c +++ b/src/core/ddsi/src/q_qosmatch.c @@ -13,7 +13,7 @@ #include #include "dds/ddsi/q_time.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_qosmatch.h" diff --git a/src/core/ddsi/src/q_radmin.c b/src/core/ddsi/src/q_radmin.c index 6265a0f..184838b 100644 --- a/src/core/ddsi/src/q_radmin.c +++ b/src/core/ddsi/src/q_radmin.c @@ -36,12 +36,12 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_bitset.h" #include "dds/ddsi/q_thread.h" -#include "dds/ddsi/q_globals.h" /* for mattr, cattr */ +#include "dds/ddsi/ddsi_domaingv.h" /* for mattr, cattr */ /* OVERVIEW ------------------------------------------------------------ @@ -2453,7 +2453,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); + struct ddsi_domaingv const * const gv = ddsrt_atomic_ldvoidp (&ts1->gv); nn_mtime_t next_thread_cputime = { 0 }; int keepgoing = 1; ddsi_guid_t rdguid, *prdguid = NULL; @@ -2540,7 +2540,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q) return 0; } -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 *nn_dqueue_new (const char *name, const struct ddsi_domaingv *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg) { struct nn_dqueue *q; char *thrname; diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index 42f874d..7cc6f7b 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -22,13 +22,13 @@ #include "dds/ddsrt/static_assert.h" #include "dds/ddsrt/avl.h" -#include "dds__stream.h" +#include "dds/ddsi/ddsi_cdrstream.h" #include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_lat_estim.h" @@ -45,9 +45,10 @@ #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_receive.h" #include "dds/ddsi/ddsi_rhc.h" +#include "dds/ddsi/ddsi_deliver_locally.h" #include "dds/ddsi/q_transmit.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_init.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_mcgroup.h" @@ -366,7 +367,7 @@ static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, D ptr = (unsigned char *) msg + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->x.octetsToInlineQos) + msg->x.octetsToInlineQos; if (msg->x.smhdr.flags & DATA_FLAG_INLINE_QOS) { - nn_plist_src_t src; + ddsi_plist_src_t src; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = (msg->x.smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; @@ -375,7 +376,7 @@ static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, D 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) + if ((ptr = ddsi_plist_quickscan (sampleinfo, rmsg, &src)) == NULL) return 0; } else @@ -470,7 +471,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms ptr = (unsigned char *) msg + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->x.octetsToInlineQos) + msg->x.octetsToInlineQos; if (msg->x.smhdr.flags & DATAFRAG_FLAG_INLINE_QOS) { - nn_plist_src_t src; + ddsi_plist_src_t src; src.protocol_version = rst->protocol_version; src.vendorid = rst->vendor; src.encoding = (msg->x.smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; @@ -479,7 +480,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms 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) + if ((ptr = ddsi_plist_quickscan (sampleinfo, rmsg, &src)) == NULL) return 0; } else @@ -618,7 +619,7 @@ void nn_gap_info_init(struct nn_gap_info *gi) memset(gi->gapbits, 0, sizeof(gi->gapbits)); } -void nn_gap_info_update(struct q_globals *gv, struct nn_gap_info *gi, int64_t seqnr) +void nn_gap_info_update(struct ddsi_domaingv *gv, struct nn_gap_info *gi, int64_t seqnr) { if (gi->gapstart == -1) { @@ -1184,7 +1185,8 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct dst.prefix = rst->dst_guid_prefix; dst.entityid = msg->readerId; - RSTTRACE ("HEARTBEAT(%s#%"PRId32":%"PRId64"..%"PRId64" ", msg->smhdr.flags & HEARTBEAT_FLAG_FINAL ? "F" : "", msg->count, firstseq, lastseq); + RSTTRACE ("HEARTBEAT(%s%s#%"PRId32":%"PRId64"..%"PRId64" ", msg->smhdr.flags & HEARTBEAT_FLAG_FINAL ? "F" : "", + msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS ? "L" : "", msg->count, firstseq, lastseq); if (!rst->forme) { @@ -1210,7 +1212,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst)); ddsrt_mutex_lock (&pwr->e.lock); if (msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS && - pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && + pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC && pwr->c.xqos->liveliness.lease_duration != T_NEVER) { if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL) @@ -1862,12 +1864,30 @@ static struct ddsi_serdata *get_serdata (struct ddsi_sertopic const * const topi return sd; } -static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **tk1, struct q_globals *gv, const struct nn_rsample_info *sampleinfo, unsigned char data_smhdr_flags, const nn_plist_t *qos, const struct nn_rdata *fragchain, unsigned statusinfo, nn_wctime_t tstamp, struct ddsi_sertopic const * const topic) +struct remote_sourceinfo { + const struct nn_rsample_info *sampleinfo; + unsigned char data_smhdr_flags; + const ddsi_plist_t *qos; + const struct nn_rdata *fragchain; + unsigned statusinfo; + nn_wctime_t tstamp; +}; + +static struct ddsi_serdata *remote_make_sample (struct ddsi_tkmap_instance **tk, struct ddsi_domaingv *gv, struct ddsi_sertopic const * const topic, void *vsourceinfo) { + /* hopefully the compiler figures out that these are just aliases and doesn't reload them + unnecessarily from memory */ + const struct remote_sourceinfo * __restrict si = vsourceinfo; + const struct nn_rsample_info * __restrict sampleinfo = si->sampleinfo; + const struct nn_rdata * __restrict fragchain = si->fragchain; + const uint32_t statusinfo = si->statusinfo; + const unsigned char data_smhdr_flags = si->data_smhdr_flags; + const nn_wctime_t tstamp = si->tstamp; + const ddsi_plist_t * __restrict qos = si->qos; const char *failmsg = NULL; struct ddsi_serdata *sample = NULL; - if (statusinfo == 0) + if (si->statusinfo == 0) { /* normal write */ if (!(data_smhdr_flags & DATA_FLAG_DATAFLAG) || sampleinfo->size == 0) @@ -1881,7 +1901,7 @@ static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **t "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); + si->data_smhdr_flags, sampleinfo->size); return NULL; } sample = get_serdata (topic, fragchain, sampleinfo->size, 0, statusinfo, tstamp); @@ -1936,7 +1956,7 @@ static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **t } else { - if ((*tk1 = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, sample)) == NULL) + if ((*tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, sample)) == NULL) { ddsi_serdata_unref (sample); sample = NULL; @@ -1960,12 +1980,6 @@ static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **t return sample; } -static void free_sample_after_store (struct q_globals *gv, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk) -{ - ddsi_tkmap_instance_unref (gv->m_tkmap, tk); - ddsi_serdata_unref (sample); -} - unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr) { switch ((SubmessageKind_t) smhdr->submessageId) @@ -1987,35 +2001,58 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr) } } -static struct reader *proxy_writer_first_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it) +static struct reader *proxy_writer_first_in_sync_reader (struct entity_index *entity_index, struct entity_common *pwrcmn, ddsrt_avl_iter_t *it) { + assert (pwrcmn->kind == EK_PROXY_WRITER); + struct proxy_writer *pwr = (struct proxy_writer *) pwrcmn; struct pwr_rd_match *m; struct reader *rd; for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, it); m != NULL; m = ddsrt_avl_iter_next (it)) - if (m->in_sync == PRMSS_SYNC && (rd = entidx_lookup_reader_guid (pwr->e.gv->entity_index, &m->rd_guid)) != NULL) + if (m->in_sync == PRMSS_SYNC && (rd = entidx_lookup_reader_guid (entity_index, &m->rd_guid)) != NULL) return rd; return NULL; } -static struct reader *proxy_writer_next_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it) +static struct reader *proxy_writer_next_in_sync_reader (struct entity_index *entity_index, ddsrt_avl_iter_t *it) { struct pwr_rd_match *m; struct reader *rd; for (m = ddsrt_avl_iter_next (it); m != NULL; m = ddsrt_avl_iter_next (it)) - if (m->in_sync == PRMSS_SYNC && (rd = entidx_lookup_reader_guid (pwr->e.gv->entity_index, &m->rd_guid)) != NULL) + if (m->in_sync == PRMSS_SYNC && (rd = entidx_lookup_reader_guid (entity_index, &m->rd_guid)) != NULL) return rd; return NULL; } +static dds_return_t remote_on_delivery_failure_fastpath (struct entity_common *source_entity, bool source_entity_locked, struct local_reader_ary *fastpath_rdary, void *vsourceinfo) +{ + (void) vsourceinfo; + ddsrt_mutex_unlock (&fastpath_rdary->rdary_lock); + if (source_entity_locked) + ddsrt_mutex_unlock (&source_entity->lock); + + dds_sleepfor (DDS_MSECS (10)); + + if (source_entity_locked) + ddsrt_mutex_lock (&source_entity->lock); + ddsrt_mutex_lock (&fastpath_rdary->rdary_lock); + return DDS_RETCODE_TRY_AGAIN; +} + static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, int pwr_locked) { + static const struct deliver_locally_ops deliver_locally_ops = { + .makesample = remote_make_sample, + .first_reader = proxy_writer_first_in_sync_reader, + .next_reader = proxy_writer_next_in_sync_reader, + .on_failure_fastpath = remote_on_delivery_failure_fastpath + }; struct receiver_state const * const rst = sampleinfo->rst; - struct q_globals * const gv = rst->gv; + struct ddsi_domaingv * const gv = rst->gv; struct proxy_writer * const pwr = sampleinfo->pwr; unsigned statusinfo; Data_DataFrag_common_t *msg; unsigned char data_smhdr_flags; - nn_plist_t qos; + ddsi_plist_t qos; int need_keyhash; if (pwr->ddsi2direct_cb) @@ -2051,12 +2088,12 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st need_keyhash = (sampleinfo->size == 0 || (data_smhdr_flags & (DATA_FLAG_KEYFLAG | DATA_FLAG_DATAFLAG)) == 0); if (!(sampleinfo->complex_qos || need_keyhash) || !(data_smhdr_flags & DATA_FLAG_INLINE_QOS)) { - nn_plist_init_empty (&qos); + ddsi_plist_init_empty (&qos); statusinfo = sampleinfo->statusinfo; } else { - nn_plist_src_t src; + ddsi_plist_src_t src; size_t qos_offset = NN_RDATA_SUBMSG_OFF (fragchain) + offsetof (Data_DataFrag_common_t, octetsToInlineQos) + sizeof (msg->octetsToInlineQos) + msg->octetsToInlineQos; dds_return_t plist_ret; src.protocol_version = rst->protocol_version; @@ -2067,7 +2104,7 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st 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 | PP_COHERENT_SET, 0, &src)) < 0) + if ((plist_ret = ddsi_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET, 0, &src)) < 0) { if (plist_ret != DDS_RETCODE_UNSUPPORTED) GVWARNING ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", @@ -2082,109 +2119,23 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st struct ddsi_writer_info wrinfo; ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos, statusinfo); - if (rdguid == NULL) - { - /* FIXME: 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; - if (rdary[0]) - { - struct ddsi_serdata *payload; - struct ddsi_tkmap_instance *tk; - if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rdary[0]->topic)) != NULL) - { - ETRACE (pwr, " => EVERYONE\n"); - uint32_t i = 0; - do { - if (!ddsi_rhc_store (rdary[i]->rhc, &wrinfo, payload, tk)) - { - if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); - /* It is painful to drop the sample, but there is no guarantee that the readers - will still be there after unlocking; indeed, it is even possible that the - topic definition got replaced in the meantime. Fortunately, this is in - the midst of a FIXME for many other reasons. */ - free_sample_after_store (gv, payload, tk); - dds_sleepfor (DDS_MSECS (10)); - if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); - goto retry; - } - } while (rdary[++i]); - free_sample_after_store (gv, payload, tk); - } - } - 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 reader *rd; - ddsrt_mutex_unlock (&pwr->rdary.rdary_lock); - if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); - if ((rd = proxy_writer_first_in_sync_reader (pwr, &it)) != NULL) - { - struct ddsi_serdata *payload; - struct ddsi_tkmap_instance *tk; - if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL) - { - ETRACE (pwr, " =>"); - do { - ETRACE (pwr, " "PGUIDFMT, PGUID (rd->e.guid)); - (void) ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk); - rd = proxy_writer_next_in_sync_reader (pwr, &it); - } while (rd != NULL); - free_sample_after_store (gv, payload, tk); - ETRACE (pwr, "\n"); - } - } - if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - } - - ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1)); - } + struct remote_sourceinfo sourceinfo = { + .sampleinfo = sampleinfo, + .data_smhdr_flags = data_smhdr_flags, + .qos = &qos, + .fragchain = fragchain, + .statusinfo = statusinfo, + .tstamp = tstamp + }; + if (rdguid) + (void) deliver_locally_one (gv, &pwr->e, pwr_locked != 0, rdguid, &wrinfo, &deliver_locally_ops, &sourceinfo); else { - struct reader *rd = entidx_lookup_reader_guid (gv->entity_index, rdguid); - if (rd != NULL) - { - struct ddsi_serdata *payload; - struct ddsi_tkmap_instance *tk; - if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL) - { - ETRACE (pwr, " =>"PGUIDFMT"\n", PGUID (*rdguid)); - /* FIXME: why look up rd,pwr again? Their states remains valid while the thread stays - "awake" (although a delete can be initiated), and blocking like this is a stopgap - anyway -- quite possibly to abort once either is deleted */ - while (!ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk)) - { - if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock); - dds_sleepfor (DDS_MSECS (1)); - if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock); - if (entidx_lookup_reader_guid (gv->entity_index, rdguid) == NULL || - entidx_lookup_proxy_writer_guid (gv->entity_index, &pwr->e.guid) == NULL) - { - /* give up when reader or proxy writer no longer accessible */ - break; - } - } - free_sample_after_store (gv, payload, tk); - } - } + (void) deliver_locally_allinsync (gv, &pwr->e, pwr_locked != 0, &pwr->rdary, &wrinfo, &deliver_locally_ops, &sourceinfo); + ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, (uint32_t) (sampleinfo->seq + 1)); } - nn_plist_fini (&qos); + + ddsi_plist_fini (&qos); return 0; } @@ -2466,7 +2417,7 @@ 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 ddsi_domaingv * const gv = sampleinfo->rst->gv; struct nn_rsample *rsample; struct nn_rsample_chain sc; struct nn_rdata *fragchain; @@ -2688,7 +2639,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct return 1; } -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 +static void malformed_packet_received_nosubmsg (const struct ddsi_domaingv *gv, const unsigned char * msg, ssize_t len, const char *state, nn_vendorid_t vendorid ) { char tmp[1024]; @@ -2705,7 +2656,7 @@ static void malformed_packet_received_nosubmsg (const struct q_globals *gv, cons GVWARNING ("%s\n", tmp); } -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) +static void malformed_packet_received (const struct ddsi_domaingv *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; @@ -2820,7 +2771,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, + struct ddsi_domaingv *gv, ddsi_tran_conn_t conn, const nn_locator_t *srcloc, nn_wctime_t tnowWC, @@ -3154,7 +3105,7 @@ malformed_asleep: return -1; } -static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const ddsi_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool) +static bool do_packet (struct thread_state1 * const ts1, struct ddsi_domaingv *gv, ddsi_tran_conn_t conn, const ddsi_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool) { /* UDP max packet size is 64kB */ @@ -3261,7 +3212,7 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d if (gv->logconfig.c.mask & DDS_LC_TRACE) { char addrstr[DDSI_LOCSTRLEN]; - ddsi_locator_to_string(gv, addrstr, sizeof(addrstr), &srcloc); + ddsi_locator_to_string(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); } @@ -3359,7 +3310,7 @@ 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 q_globals *gv, struct local_participant_set *lps) +static void rebuild_local_participant_set (struct thread_state1 * const ts1, struct ddsi_domaingv *gv, struct local_participant_set *lps) { struct entidx_enum_participant est; struct participant *pp; @@ -3427,7 +3378,7 @@ static void rebuild_local_participant_set (struct thread_state1 * const ts1, str uint32_t listen_thread (struct ddsi_tran_listener *listener) { - struct q_globals *gv = listener->m_base.gv; + struct ddsi_domaingv *gv = listener->m_base.gv; ddsi_tran_conn_t conn; while (ddsrt_atomic_ld32 (&gv->rtps_keepgoing)) @@ -3450,7 +3401,7 @@ static int recv_thread_waitset_add_conn (os_sockWaitset ws, ddsi_tran_conn_t con return 0; else { - struct q_globals *gv = conn->m_base.gv; + struct ddsi_domaingv *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; @@ -3469,7 +3420,7 @@ struct local_deaf_state { nn_mtime_t tnext; }; -static int check_and_handle_deafness_recover (struct q_globals *gv, struct local_deaf_state *st, unsigned num_fixed_uc) +static int check_and_handle_deafness_recover (struct ddsi_domaingv *gv, struct local_deaf_state *st, unsigned num_fixed_uc) { int rebuildws = 0; if (now_mt().v < st->tnext.v) @@ -3524,7 +3475,7 @@ error: return rebuildws; } -static int check_and_handle_deafness (struct q_globals *gv, struct local_deaf_state *st, unsigned num_fixed_uc) +static int check_and_handle_deafness (struct ddsi_domaingv *gv, struct local_deaf_state *st, unsigned num_fixed_uc) { const int gv_deaf = gv->deaf; assert (gv_deaf == 0 || gv_deaf == 1); @@ -3549,7 +3500,7 @@ static int check_and_handle_deafness (struct q_globals *gv, struct local_deaf_st } } -void trigger_recv_threads (const struct q_globals *gv) +void trigger_recv_threads (const struct ddsi_domaingv *gv) { for (uint32_t i = 0; i < gv->n_recv_threads; i++) { @@ -3564,7 +3515,7 @@ void trigger_recv_threads (const struct q_globals *gv) ddsrt_iovec_t iov; iov.iov_base = &dummy; iov.iov_len = 1; - GVTRACE ("trigger_recv_threads: %d single %s\n", i, ddsi_locator_to_string (gv, buf, sizeof (buf), dst)); + GVTRACE ("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); break; } @@ -3581,7 +3532,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 ddsi_domaingv * 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 }; diff --git a/src/core/ddsi/src/q_thread.c b/src/core/ddsi/src/q_thread.c index 1c0c144..a8190fa 100644 --- a/src/core/ddsi/src/q_thread.c +++ b/src/core/ddsi/src/q_thread.c @@ -25,7 +25,7 @@ #include "dds/ddsi/ddsi_threadmon.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/sysdeps.h" struct thread_states thread_states; @@ -39,12 +39,12 @@ 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, const struct q_globals *gv); +extern inline void thread_state_awake (struct thread_state1 *ts1, const struct ddsi_domaingv *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, const struct q_globals *gv, enum thread_state state); +static struct thread_state1 *init_thread_state (const char *tname, const struct ddsi_domaingv *gv, enum thread_state state); static void reap_thread_state (struct thread_state1 *ts1); static void *ddsrt_malloc_aligned_cacheline (size_t size) @@ -213,7 +213,7 @@ static uint32_t create_thread_wrapper (void *ptr) { uint32_t ret; struct thread_context *ctx = ptr; - struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&ctx->self->gv); + struct ddsi_domaingv 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 (); @@ -240,7 +240,7 @@ const struct config_thread_properties_listelem *lookup_thread_properties (const return e; } -static struct thread_state1 *init_thread_state (const char *tname, const struct q_globals *gv, enum thread_state state) +static struct thread_state1 *init_thread_state (const char *tname, const struct ddsi_domaingv *gv, enum thread_state state) { int cand; struct thread_state1 *ts; @@ -249,7 +249,7 @@ static struct thread_state1 *init_thread_state (const char *tname, const struct return NULL; ts = &thread_states.ts[cand]; - ddsrt_atomic_stvoidp (&ts->gv, (struct q_globals *) gv); + ddsrt_atomic_stvoidp (&ts->gv, (struct ddsi_domaingv *) gv); assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts->vtime))); (void) ddsrt_strlcpy (ts->name, tname, sizeof (ts->name)); ts->state = state; @@ -257,7 +257,7 @@ static struct thread_state1 *init_thread_state (const char *tname, const struct return ts; } -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) +static dds_return_t create_thread_int (struct thread_state1 **ts1, const struct ddsi_domaingv *gv, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg) { ddsrt_threadattr_t tattr; ddsrt_thread_t tid; @@ -308,7 +308,7 @@ dds_return_t create_thread_with_properties (struct thread_state1 **ts1, struct c 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) +dds_return_t create_thread (struct thread_state1 **ts1, const struct ddsi_domaingv *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); @@ -337,7 +337,7 @@ void reset_thread_state (struct thread_state1 *ts1) reap_thread_state (ts1); } -void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct q_globals *gv) +void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct ddsi_domaingv *gv) { for (uint32_t i = 0; i < thread_states.nthreads; i++) { diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c index b229713..063d2a1 100644 --- a/src/core/ddsi/src/q_transmit.c +++ b/src/core/ddsi/src/q_transmit.c @@ -28,12 +28,13 @@ #include "dds/ddsi/q_xevent.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.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_receive.h" +#include "dds/ddsi/q_lease.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" @@ -81,7 +82,7 @@ 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 ddsi_domaingv const * const gv = wr->e.gv; struct hbcontrol const * const hbc = &wr->hbcontrol; int64_t ret = gv->config.const_hb_intv_sched; size_t n_unacked; @@ -107,8 +108,8 @@ int64_t writer_hbcontrol_intv (const struct writer *wr, const struct whc_state * void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow) { + struct ddsi_domaingv const * const gv = wr->e.gv; struct hbcontrol * const hbc = &wr->hbcontrol; - struct q_globals const * const gv = wr->e.gv; nn_mtime_t tnext; /* Reset number of heartbeats since last write: that means the @@ -136,7 +137,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 ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg *msg; const ddsi_guid_t *prd_guid; @@ -235,7 +236,7 @@ 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 ddsi_domaingv const * const gv = wr->e.gv; struct hbcontrol const * const hbc = &wr->hbcontrol; const int64_t hb_intv_ack = gv->config.const_hb_intv_sched; assert(wr->heartbeat_xevent != NULL && whcst != NULL); @@ -327,7 +328,7 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_ #ifdef DDSI_INCLUDE_SECURITY struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *whcst, int hbansreq, struct proxy_reader *prd) { - struct q_globals const * const gv = wr->e.gv; + struct ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg *msg; ASSERT_MUTEX_HELD (&wr->e.lock); @@ -367,7 +368,7 @@ struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state * void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync) { - struct q_globals const * const gv = wr->e.gv; + struct ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; Heartbeat_t * hb; seqno_t max = 0, min = 1; @@ -443,7 +444,7 @@ static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t s /* 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 ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; unsigned char contentflag = 0; Data_t *data; @@ -512,7 +513,7 @@ static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t s return 0; } -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) +dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct ddsi_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 @@ -528,7 +529,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru 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 ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; void *sm; Data_DataFrag_common_t *ddcmn; @@ -696,7 +697,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru 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 ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg_marker sm_marker; HeartbeatFrag_t *hbf; ASSERT_MUTEX_HELD (&wr->e.lock); @@ -740,11 +741,13 @@ static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragn } } -dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp) +dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp) { struct nn_xmsg *msg = NULL; struct whc_state whcst; struct thread_state1 * const ts1 = lookup_thread_state (); + struct lease *lease; + thread_state_awake (ts1, gv); struct writer *wr = entidx_lookup_writer_guid (gv->entity_index, wr_guid); if (wr == NULL) @@ -752,6 +755,12 @@ dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid GVTRACE ("write_hb_liveliness("PGUIDFMT") - writer not found\n", PGUID (*wr_guid)); return DDS_RETCODE_PRECONDITION_NOT_MET; } + + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT && ((lease = ddsrt_atomic_ldvoidp (&wr->c.pp->minl_man)) != NULL)) + lease_renew (lease, now_et()); + else if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && wr->lease != NULL) + lease_renew (wr->lease, now_et()); + if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) return DDS_RETCODE_OUT_OF_RESOURCES; ddsrt_mutex_lock (&wr->e.lock); @@ -791,7 +800,7 @@ 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, uint32_t nfrags) +static void transmit_sample_lgmsg_unlocked (struct nn_xpack *xp, struct writer *wr, const struct whc_state *whcst, seqno_t seq, const struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew, uint32_t nfrags) { #if 0 const char *frags_to_skip = getenv ("SKIPFRAGS"); @@ -848,10 +857,10 @@ 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) +static void transmit_sample_unlocks_wr (struct nn_xpack *xp, struct writer *wr, const struct whc_state *whcst, seqno_t seq, const struct ddsi_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 ddsi_domaingv const * const gv = wr->e.gv; struct nn_xmsg *fmsg; uint32_t sz; assert(xp); @@ -891,9 +900,9 @@ 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) +int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew) { - struct q_globals const * const gv = wr->e.gv; + struct ddsi_domaingv const * const gv = wr->e.gv; uint32_t i, sz, nfrags; int enqueued = 1; @@ -946,10 +955,11 @@ int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_ return enqueued ? 0 : -1; } -static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) +static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) { /* returns: < 0 on error, 0 if no need to insert in whc, > 0 if inserted */ - int do_insert, insres, res; + int insres, res = 0; + bool wr_deadline = false; ASSERT_MUTEX_HELD (&wr->e.lock); @@ -970,17 +980,15 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist } assert (wr->reliable || have_reliable_subs (wr) == 0); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + /* If deadline missed duration is not infinite, the sample is inserted in + the whc so that the instance is created (or renewed) in the whc and the deadline + missed event is registered. The sample is removed immediately after inserting it + as we don't want to store it. */ + wr_deadline = wr->xqos->deadline.deadline != DDS_INFINITY; +#endif - if (wr->reliable && have_reliable_subs (wr)) - do_insert = 1; - else if (wr->handle_as_transient_local) - do_insert = 1; - else - do_insert = 0; - - if (!do_insert) - res = 0; - else + if ((wr->reliable && have_reliable_subs (wr)) || wr_deadline || wr->handle_as_transient_local) { nn_mtime_t exp = NN_MTIME_NEVER; #ifdef DDSI_INCLUDE_LIFESPAN @@ -991,6 +999,20 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct nn_plist exp = add_duration_to_mtime(serdata->twrite, wr->xqos->lifespan.duration); #endif res = ((insres = whc_insert (wr->whc, writer_max_drop_seq (wr), seq, exp, plist, serdata, tk)) < 0) ? insres : 1; + +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (!(wr->reliable && have_reliable_subs (wr)) && !wr->handle_as_transient_local) + { + /* Sample was inserted only because writer has deadline, so we'll remove the sample from whc */ + struct whc_node *deferred_free_list = NULL; + struct whc_state whcst; + uint32_t n = whc_remove_acked_messages (wr->whc, seq, &whcst, &deferred_free_list); + (void)n; + assert (n <= 1); + assert (whcst.min_seq == -1 && whcst.max_seq == -1); + whc_free_deferred_free_list (wr->whc, deferred_free_list); + } +#endif } #ifndef NDEBUG @@ -1047,7 +1069,7 @@ static dds_return_t throttle_writer (struct thread_state1 * const ts1, struct nn resent to them, until a ACKNACK is received from that reader. This implicitly clears the whc and unblocks the writer. */ - struct q_globals const * const gv = wr->e.gv; + struct ddsi_domaingv 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, wr->xqos->reliability.max_blocking_time); @@ -1118,7 +1140,7 @@ static dds_return_t throttle_writer (struct thread_state1 * const ts1, struct nn static int maybe_grow_whc (struct writer *wr) { - struct q_globals const * const gv = wr->e.gv; + struct ddsi_domaingv 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(); @@ -1134,9 +1156,9 @@ static int maybe_grow_whc (struct writer *wr) return 0; } -int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd) +int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd) { - struct q_globals * const gv = wr->e.gv; + struct ddsi_domaingv * const gv = wr->e.gv; int r; nn_mtime_t tnow; int rexmit = 1; @@ -1193,12 +1215,13 @@ int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct nn_plist return r; } -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) +static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr, struct ddsi_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; + struct ddsi_domaingv const * const gv = wr->e.gv; int r; seqno_t seq; nn_mtime_t tnow; + struct lease *lease; /* 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 == DDS_HISTORY_KEEP_LAST && wr->whc_low == INT32_MAX)); @@ -1220,8 +1243,16 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * goto drop; } + if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT && ((lease = ddsrt_atomic_ldvoidp (&wr->c.pp->minl_man)) != NULL)) + lease_renew (lease, now_et()); + else if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && wr->lease != NULL) + lease_renew (wr->lease, now_et()); + ddsrt_mutex_lock (&wr->e.lock); + if (!wr->alive) + writer_set_alive_may_unlock (wr, true); + if (end_of_txn) { wr->cs_seq = 0; @@ -1271,7 +1302,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * if (plist == NULL) { plist = ddsrt_malloc (sizeof (*plist)); - nn_plist_init_empty (plist); + ddsi_plist_init_empty (plist); } assert (!(plist->present & PP_COHERENT_SET)); plist->present |= PP_COHERENT_SET; @@ -1284,7 +1315,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * ddsrt_mutex_unlock (&wr->e.lock); if (plist != NULL) { - nn_plist_fini (plist); + ddsi_plist_fini (plist); ddsrt_free (plist); } } @@ -1300,7 +1331,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * ddsrt_mutex_unlock (&wr->e.lock); if (plist != NULL) { - nn_plist_fini (plist); + ddsi_plist_fini (plist); ddsrt_free (plist); } } @@ -1315,14 +1346,14 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * * creating the message, the WHC will free the plist (if any). Currently, * plist's are only used for coherent sets, which is assumed to be rare, * which in turn means that an extra copy doesn't hurt too badly ... */ - nn_plist_t plist_stk, *plist_copy; + ddsi_plist_t plist_stk, *plist_copy; struct whc_state whcst, *whcstptr; if (plist == NULL) plist_copy = NULL; else { plist_copy = &plist_stk; - nn_plist_copy (plist_copy, plist); + ddsi_plist_copy (plist_copy, plist); } if (wr->heartbeat_xevent == NULL) whcstptr = NULL; @@ -1333,7 +1364,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * } transmit_sample_unlocks_wr (xp, wr, whcstptr, seq, plist_copy, serdata, NULL, 1); if (plist_copy) - nn_plist_fini (plist_copy); + ddsi_plist_fini (plist_copy); } else { @@ -1346,7 +1377,7 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * /* If not actually inserted, WHC didn't take ownership of plist */ if (r == 0 && plist != NULL) { - nn_plist_fini (plist); + ddsi_plist_fini (plist); ddsrt_free (plist); } } diff --git a/src/core/ddsi/src/q_whc.c b/src/core/ddsi/src/q_whc.c index 0a7d1c8..457045d 100644 --- a/src/core/ddsi/src/q_whc.c +++ b/src/core/ddsi/src/q_whc.c @@ -21,7 +21,7 @@ extern inline void whc_return_sample (struct whc *whc, struct whc_borrowed_sampl extern inline void whc_sample_iter_init (const struct whc *whc, struct whc_sample_iter *it); extern inline bool whc_sample_iter_borrow_next (struct whc_sample_iter *it, struct whc_borrowed_sample *sample); extern inline void whc_free (struct whc *whc); -extern int whc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct nn_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); +extern int whc_insert (struct whc *whc, seqno_t max_drop_seq, seqno_t seq, nn_mtime_t exp, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk); extern unsigned whc_downgrade_to_volatile (struct whc *whc, struct whc_state *st); extern unsigned whc_remove_acked_messages (struct whc *whc, seqno_t max_drop_seq, struct whc_state *whcst, struct whc_node **deferred_free_list); extern void whc_free_deferred_free_list (struct whc *whc, struct whc_node *deferred_free_list); diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c index 3c852d5..41b91a7 100644 --- a/src/core/ddsi/src/q_xevent.c +++ b/src/core/ddsi/src/q_xevent.c @@ -27,7 +27,7 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_unused.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_transmit.h" #include "dds/ddsi/q_bswap.h" @@ -145,7 +145,7 @@ struct xeventq { size_t max_queued_rexmit_msgs; int terminate; struct thread_state1 *ts; - struct q_globals *gv; + struct ddsi_domaingv *gv; ddsrt_mutex_t lock; ddsrt_cond_t cond; ddsi_tran_conn_t tev_conn; @@ -343,14 +343,20 @@ void delete_xevent_callback (struct xevent *ev) struct xeventq *evq = ev->evq; assert (ev->kind == XEVK_CALLBACK); ddsrt_mutex_lock (&evq->lock); - if (ev->tsched.v != T_NEVER) + /* wait until neither scheduled nor executing; loop in case the callback reschedules the event */ + while (ev->tsched.v != T_NEVER || ev->u.callback.executing) { - assert (ev->tsched.v != TSCHED_DELETE); - ddsrt_fibheap_delete (&evq_xevents_fhdef, &evq->xevents, ev); - ev->tsched.v = TSCHED_DELETE; + if (ev->tsched.v != T_NEVER) + { + assert (ev->tsched.v != TSCHED_DELETE); + ddsrt_fibheap_delete (&evq_xevents_fhdef, &evq->xevents, ev); + ev->tsched.v = T_NEVER; + } + if (ev->u.callback.executing) + { + ddsrt_cond_wait (&evq->cond, &evq->lock); + } } - while (ev->u.callback.executing) - ddsrt_cond_wait (&evq->cond, &evq->lock); ddsrt_mutex_unlock (&evq->lock); free_xevent (evq, ev); } @@ -656,7 +662,7 @@ static void send_heartbeat_to_all_readers(struct nn_xpack *xp, struct xevent *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 ddsi_domaingv const * const gv = ev->evq->gv; struct nn_xmsg *msg; struct writer *wr; nn_mtime_t t_next; @@ -946,7 +952,7 @@ static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, nn_mtim 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 ddsi_domaingv *gv = ev->evq->gv; struct proxy_writer *pwr; struct nn_xmsg *msg; struct pwr_rd_match *rwn; @@ -1049,16 +1055,16 @@ static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_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; + struct ddsi_domaingv *gv = wr->e.gv; bool sample_found; - nn_plist_t ps; - nn_plist_init_empty (&ps); + ddsi_plist_t ps; + ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = *guid; struct nn_xmsg *mpayload = nn_xmsg_new (gv->xmsgpool, guid, wr->c.pp, 0, NN_XMSG_KIND_DATA); - nn_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); + ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); nn_xmsg_addpar_sentinel (mpayload); - nn_plist_fini (&ps); + ddsi_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); @@ -1085,7 +1091,7 @@ static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_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 ddsi_domaingv *gv = ev->evq->gv; struct participant *pp; struct proxy_reader *prd; struct writer *spdp_wr; @@ -1199,7 +1205,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e 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 ddsi_domaingv * const gv = ev->evq->gv; struct participant *pp; dds_duration_t intv; nn_mtime_t tnext; @@ -1234,7 +1240,7 @@ 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. */ - struct q_globals * const gv = ev->evq->gv; + struct ddsi_domaingv * 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); @@ -1455,7 +1461,7 @@ void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg) void qxev_prd_entityid (struct proxy_reader *prd, const ddsi_guid_t *guid) { - struct q_globals * const gv = prd->e.gv; + struct ddsi_domaingv * const gv = prd->e.gv; struct nn_xmsg *msg; struct xevent_nt *ev; @@ -1483,7 +1489,7 @@ void qxev_prd_entityid (struct proxy_reader *prd, const ddsi_guid_t *guid) void qxev_pwr_entityid (struct proxy_writer *pwr, const ddsi_guid_t *guid) { - struct q_globals * const gv = pwr->e.gv; + struct ddsi_domaingv * const gv = pwr->e.gv; struct nn_xmsg *msg; struct xevent_nt *ev; @@ -1511,7 +1517,7 @@ void qxev_pwr_entityid (struct proxy_writer *pwr, const ddsi_guid_t *guid) int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int force) { - struct q_globals * const gv = evq->gv; + struct ddsi_domaingv * const gv = evq->gv; size_t msg_size = nn_xmsg_size (msg); struct xevent_nt *ev; diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index 0e964e5..695c47d 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -27,7 +27,7 @@ #include "dds/ddsrt/thread_pool.h" #include "dds/ddsi/q_protocol.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_addrset.h" @@ -37,7 +37,7 @@ #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_entity.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_freelist.h" #include "dds/ddsi/ddsi_serdata_default.h" @@ -208,7 +208,7 @@ struct nn_xpack size_t niov; ddsrt_iovec_t *iov; enum nn_xmsg_dstmode dstmode; - struct q_globals *gv; + struct ddsi_domaingv *gv; union { @@ -709,7 +709,7 @@ void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t of } } -void nn_xmsg_setdst1 (struct q_globals *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *loc) +void nn_xmsg_setdst1 (struct ddsi_domaingv *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *loc) { assert (m->dstmode == NN_XMSG_DST_UNSET); m->dstmode = NN_XMSG_DST_ONE; @@ -809,7 +809,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 q_globals *gv, struct nn_xmsg *m, const struct nn_xmsg *madd) +int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct ddsi_domaingv *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); @@ -993,7 +993,7 @@ int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg * m) pointer we compute the address of the xmsg from the address of the chain element, &c. */ -static void nn_xmsg_chain_release (struct q_globals *gv, struct nn_xmsg_chain *chain) +static void nn_xmsg_chain_release (struct ddsi_domaingv *gv, struct nn_xmsg_chain *chain) { ddsi_guid_t wrguid; memset (&wrguid, 0, sizeof (wrguid)); @@ -1051,7 +1051,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 q_globals const * const gv, struct nn_bw_limiter *this, ssize_t size) +static void nn_bw_limit_sleep_if_needed (struct ddsi_domaingv const * const gv, struct nn_bw_limiter *this, ssize_t size) { if ( this->bandwidth > 0 ) { nn_mtime_t tnow = now_mt(); @@ -1210,13 +1210,13 @@ static ssize_t nn_xpack_send_rtps(struct nn_xpack * xp, const nn_locator_t *loc) static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) { struct nn_xpack *xp = varg; - struct q_globals const * const gv = xp->gv; + struct ddsi_domaingv const * const gv = xp->gv; ssize_t nbytes = 0; if (gv->logconfig.c.mask & DDS_LC_TRACE) { char buf[DDSI_LOCSTRLEN]; - GVTRACE (" %s", ddsi_locator_to_string (gv, buf, sizeof(buf), loc)); + GVTRACE (" %s", ddsi_locator_to_string (buf, sizeof(buf), loc)); } if (gv->config.xmit_lossiness > 0) @@ -1299,7 +1299,7 @@ static void nn_xpack_send1_threaded (const nn_locator_t *loc, void * varg) static void nn_xpack_send_real (struct nn_xpack *xp) { - struct q_globals const * const gv = xp->gv; + struct ddsi_domaingv const * const gv = xp->gv; size_t calls; assert (xp->niov <= NN_XMSG_MAX_MESSAGE_IOVECS); @@ -1379,7 +1379,7 @@ static void nn_xpack_send_real (struct nn_xpack *xp) static uint32_t nn_xpack_sendq_thread (void *vgv) { - struct q_globals *gv = vgv; + struct ddsi_domaingv *gv = vgv; ddsrt_mutex_lock (&gv->sendq_lock); while (!(gv->sendq_stop && gv->sendq_head == NULL)) { @@ -1403,7 +1403,7 @@ static uint32_t nn_xpack_sendq_thread (void *vgv) return 0; } -void nn_xpack_sendq_init (struct q_globals *gv) +void nn_xpack_sendq_init (struct ddsi_domaingv *gv) { gv->sendq_stop = 0; gv->sendq_head = NULL; @@ -1413,13 +1413,13 @@ void nn_xpack_sendq_init (struct q_globals *gv) ddsrt_cond_init (&gv->sendq_cond); } -void nn_xpack_sendq_start (struct q_globals *gv) +void nn_xpack_sendq_start (struct ddsi_domaingv *gv) { if (create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL) != DDS_RETCODE_OK) GVERROR ("nn_xpack_sendq_start: can't create nn_xpack_sendq_thread\n"); } -void nn_xpack_sendq_stop (struct q_globals *gv) +void nn_xpack_sendq_stop (struct ddsi_domaingv *gv) { ddsrt_mutex_lock (&gv->sendq_lock); gv->sendq_stop = 1; @@ -1427,7 +1427,7 @@ void nn_xpack_sendq_stop (struct q_globals *gv) ddsrt_mutex_unlock (&gv->sendq_lock); } -void nn_xpack_sendq_fini (struct q_globals *gv) +void nn_xpack_sendq_fini (struct ddsi_domaingv *gv) { assert (gv->sendq_head == NULL); join_thread (gv->sendq_ts); @@ -1443,7 +1443,7 @@ void nn_xpack_send (struct nn_xpack *xp, bool immediately) } else { - struct q_globals * const gv = xp->gv; + struct ddsi_domaingv * const gv = xp->gv; struct nn_xpack *xp1 = ddsrt_malloc (sizeof (*xp)); memcpy (xp1, xp, sizeof (*xp1)); nn_xpack_reinit (xp); @@ -1549,7 +1549,7 @@ static int nn_xpack_mayaddmsg (const struct nn_xpack *xp, const struct nn_xmsg * 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; + struct ddsi_domaingv const * const gv = xp->gv; static InfoDST_t static_zero_dst = { { SMID_INFO_DST, (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? SMFLAG_ENDIANNESS : 0), sizeof (ddsi_guid_prefix_t) }, { { 0,0,0,0, 0,0,0,0, 0,0,0,0 } } diff --git a/src/core/ddsi/src/sysdeps.c b/src/core/ddsi/src/sysdeps.c index e7b2915..b1ce8c3 100644 --- a/src/core/ddsi/src/sysdeps.c +++ b/src/core/ddsi/src/sysdeps.c @@ -18,7 +18,7 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/sysdeps.h" -#if DDSRT_WITH_FREERTOS || !(defined __APPLE__ || defined __linux) || (__GNUC__ > 0 && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40100) +#if DDSRT_WITH_FREERTOS || !(defined __APPLE__ || (defined __linux && (defined __GLIBC__ || defined __UCLIBC__))) || (__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); diff --git a/src/core/ddsi/tests/plist.c b/src/core/ddsi/tests/plist.c index a9b96a0..8227831 100644 --- a/src/core/ddsi/tests/plist.c +++ b/src/core/ddsi/tests/plist.c @@ -14,18 +14,17 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" #include "dds/ddsrt/endian.h" -#include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/ddsi_xqos.h" +#include "dds/ddsi/ddsi_plist.h" CU_Test (ddsi_plist, unalias_copy_merge) { - /* one int, one string, one string sequence and one struct sequence covers most cases */ - nn_plist_t p0, p0memcpy; + /* one int, one string and one string sequence covers most cases */ + ddsi_plist_t p0, p0memcpy; char *p0strs[7]; - nn_plist_init_empty (&p0); - p0.present = PP_PRISMTECH_PROCESS_ID | PP_ENTITY_NAME; + ddsi_plist_init_empty (&p0); + p0.present = PP_ENTITY_NAME; p0.aliased = PP_ENTITY_NAME; - p0.process_id = 0x12345678; p0.entity_name = "nemo"; p0.qos.present = QP_PARTITION; p0.qos.aliased = QP_PARTITION; @@ -52,14 +51,14 @@ CU_Test (ddsi_plist, unalias_copy_merge) memcpy (&p0memcpy, &p0, sizeof (p0)); /* manually alias one, so we can free it*/ - nn_plist_t p0alias; + ddsi_plist_t p0alias; memcpy (&p0alias, &p0, sizeof (p0)); p0alias.qos.partition.strs = ddsrt_memdup (p0alias.qos.partition.strs, p0.qos.partition.n * sizeof (*p0.qos.partition.strs)); #ifdef DDSI_INCLUDE_SECURITY p0alias.identity_token.properties.props = ddsrt_memdup (p0alias.identity_token.properties.props, p0.identity_token.properties.n * sizeof (*p0.identity_token.properties.props)); #endif - nn_plist_fini (&p0alias); + ddsi_plist_fini (&p0alias); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT_STRING_EQUAL (p0.entity_name, "nemo"); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]); @@ -73,15 +72,14 @@ CU_Test (ddsi_plist, unalias_copy_merge) #endif /* copy an aliased one; the original must be unchanged, the copy unaliased */ - nn_plist_t p1; - nn_plist_init_empty (&p1); - nn_plist_copy (&p1, &p0); + ddsi_plist_t p1; + ddsi_plist_init_empty (&p1); + ddsi_plist_copy (&p1, &p0); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT (p1.present == p0.present); CU_ASSERT (p1.aliased == 0); CU_ASSERT (p1.qos.present == p0.qos.present); CU_ASSERT (p1.qos.aliased == 0); - CU_ASSERT (p1.process_id == p0.process_id); CU_ASSERT (p1.entity_name != p0.entity_name); CU_ASSERT_STRING_EQUAL (p1.entity_name, p0.entity_name); CU_ASSERT (p1.qos.partition.n == p0.qos.partition.n); @@ -114,19 +112,18 @@ CU_Test (ddsi_plist, unalias_copy_merge) /* merge-in missing ones from an aliased copy: original must remain unchanged; existing ones should stay without touching "aliased" only new ones are added as unaliased ones */ - nn_plist_t p2, p2memcpy; - nn_plist_init_empty (&p2); + ddsi_plist_t p2, p2memcpy; + ddsi_plist_init_empty (&p2); p2.present = PP_ENTITY_NAME; p2.aliased = PP_ENTITY_NAME; p2.entity_name = "omen"; memcpy (&p2memcpy, &p2, sizeof (p2)); - nn_plist_mergein_missing (&p2, &p0, p0.present, p0.qos.present); + ddsi_plist_mergein_missing (&p2, &p0, p0.present, p0.qos.present); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT (p2.present == p0.present); CU_ASSERT (p2.aliased == p2memcpy.aliased); CU_ASSERT (p2.qos.present == p0.qos.present); CU_ASSERT (p2.qos.aliased == p2memcpy.qos.aliased); - CU_ASSERT (p2.process_id == p0.process_id); CU_ASSERT (p2.entity_name == p2memcpy.entity_name); CU_ASSERT_STRING_EQUAL (p2.entity_name, "omen"); CU_ASSERT (p2.qos.partition.n == p0.qos.partition.n); @@ -157,12 +154,11 @@ CU_Test (ddsi_plist, unalias_copy_merge) #endif /* unalias of p0, partition.strs mustn't change, because it, unlike its elements, wasn't aliased */ - nn_plist_unalias (&p0); + ddsi_plist_unalias (&p0); CU_ASSERT (p0.present == p0memcpy.present); CU_ASSERT (p0.aliased == 0); CU_ASSERT (p0.qos.present == p0memcpy.qos.present); CU_ASSERT (p0.qos.aliased == 0); - CU_ASSERT (p0.process_id == p0memcpy.process_id); CU_ASSERT (p0.entity_name != p0memcpy.entity_name); CU_ASSERT_STRING_EQUAL (p0.entity_name, p0memcpy.entity_name); CU_ASSERT (p0.qos.partition.n == p0memcpy.qos.partition.n); @@ -187,15 +183,14 @@ CU_Test (ddsi_plist, unalias_copy_merge) memcpy (&p0memcpy, &p0, sizeof (p0)); /* copy an aliased one; the original must be unchanged, the copy unaliased */ - nn_plist_t p3; - nn_plist_init_empty (&p3); - nn_plist_copy (&p3, &p0); + ddsi_plist_t p3; + ddsi_plist_init_empty (&p3); + ddsi_plist_copy (&p3, &p0); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT (p3.present == p0.present); CU_ASSERT (p3.aliased == 0); CU_ASSERT (p3.qos.present == p0.qos.present); CU_ASSERT (p3.qos.aliased == 0); - CU_ASSERT (p3.process_id == p0.process_id); CU_ASSERT (p3.entity_name != p0.entity_name); CU_ASSERT_STRING_EQUAL (p3.entity_name, p0.entity_name); CU_ASSERT (p3.qos.partition.n == p0.qos.partition.n); @@ -228,19 +223,18 @@ CU_Test (ddsi_plist, unalias_copy_merge) /* merge-in missing ones from an aliased copy: original must remain unchanged; existing ones should stay without touching "aliased" only new ones are added as unaliased ones */ - nn_plist_t p4, p4memcpy; - nn_plist_init_empty (&p4); + ddsi_plist_t p4, p4memcpy; + ddsi_plist_init_empty (&p4); p4.present = PP_ENTITY_NAME; p4.aliased = PP_ENTITY_NAME; p4.entity_name = "omen"; memcpy (&p4memcpy, &p4, sizeof (p4)); - nn_plist_mergein_missing (&p4, &p0, p0.present, p0.qos.present); + ddsi_plist_mergein_missing (&p4, &p0, p0.present, p0.qos.present); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT (p4.present == p0.present); CU_ASSERT (p4.aliased == p4memcpy.aliased); CU_ASSERT (p4.qos.present == p0.qos.present); CU_ASSERT (p4.qos.aliased == p4memcpy.qos.aliased); - CU_ASSERT (p4.process_id == p0.process_id); CU_ASSERT (p4.entity_name == p4memcpy.entity_name); CU_ASSERT_STRING_EQUAL (p4.entity_name, "omen"); CU_ASSERT (p4.qos.partition.n == p0.qos.partition.n); @@ -270,9 +264,9 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT (p4.identity_token.binary_properties.props == NULL); #endif - nn_plist_fini (&p0); - nn_plist_fini (&p1); - nn_plist_fini (&p2); - nn_plist_fini (&p3); - nn_plist_fini (&p4); + ddsi_plist_fini (&p0); + ddsi_plist_fini (&p1); + ddsi_plist_fini (&p2); + ddsi_plist_fini (&p3); + ddsi_plist_fini (&p4); } diff --git a/src/core/ddsi/tests/plist_generic.c b/src/core/ddsi/tests/plist_generic.c index 54f7647..689f2f9 100644 --- a/src/core/ddsi/tests/plist_generic.c +++ b/src/core/ddsi/tests/plist_generic.c @@ -13,7 +13,7 @@ #include "CUnit/Theory.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/endian.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_plist_generic.h" #include "mem_ser.h" diff --git a/src/core/xtests/cdrtest/CMakeLists.txt b/src/core/xtests/cdrtest/CMakeLists.txt index 1535a9c..2021e0b 100644 --- a/src/core/xtests/cdrtest/CMakeLists.txt +++ b/src/core/xtests/cdrtest/CMakeLists.txt @@ -11,6 +11,8 @@ # cmake_minimum_required(VERSION 3.5) +find_package(CycloneDDS COMPONENTS idlc) + 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") diff --git a/src/core/xtests/cdrtest/cdrtest.pl b/src/core/xtests/cdrtest/cdrtest.pl index e850927..f42a7c2 100644 --- a/src/core/xtests/cdrtest/cdrtest.pl +++ b/src/core/xtests/cdrtest/cdrtest.pl @@ -54,7 +54,7 @@ print CYC <[1]_desc; + ddd.type = (struct ddsi_sertopic_default_desc) { + .m_size = $t->[1]_desc.m_size, + .m_align = $t->[1]_desc.m_align, + .m_flagset = $t->[1]_desc.m_flagset, + .m_nkeys = 0, + .m_keys = NULL, + .m_nops = dds_stream_countops ($t->[1]_desc.m_ops), + .m_ops = (uint32_t *) $t->[1]_desc.m_ops + }; for (uint32_t i = 0; i < 1000; i++) { for (size_t j = 0; j < sizeof (garbage); j++) garbage[j] = (unsigned char) ddsrt_random (); diff --git a/src/core/xtests/rhc_torture/rhc_torture.c b/src/core/xtests/rhc_torture/rhc_torture.c index 080f993..b662b7a 100644 --- a/src/core/xtests/rhc_torture/rhc_torture.c +++ b/src/core/xtests/rhc_torture/rhc_torture.c @@ -24,7 +24,7 @@ #include "dds__entity.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_bswap.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_gc.h" @@ -107,7 +107,7 @@ static struct ddsi_serdata *mkkeysample (int32_t keyval, unsigned statusinfo) return sd; } -#ifdef DDSI_INCLUDE_LIFESPAN +#if defined(DDSI_INCLUDE_LIFESPAN) || defined (DDSI_INCLUDE_DEADLINE_MISSED) static nn_mtime_t rand_texp () { nn_mtime_t ret = now_mt(); @@ -116,6 +116,13 @@ static nn_mtime_t rand_texp () } #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED +static dds_duration_t rand_deadline () +{ + return (dds_duration_t) (ddsrt_prng_random (&prng) % DDS_MSECS(500)); +} +#endif + static uint64_t store (struct ddsi_tkmap *tkmap, struct dds_rhc *rhc, struct proxy_writer *wr, struct ddsi_serdata *sd, bool print, bool lifespan_expiry) { #ifndef DDSI_INCLUDE_LIFESPAN @@ -160,7 +167,7 @@ static uint64_t store (struct ddsi_tkmap *tkmap, struct dds_rhc *rhc, struct pro return iid; } -static struct proxy_writer *mkwr (const struct q_globals *gv, bool auto_dispose) +static struct proxy_writer *mkwr (const struct ddsi_domaingv *gv, bool auto_dispose) { struct proxy_writer *pwr; struct dds_qos *xqos; @@ -169,8 +176,8 @@ static struct proxy_writer *mkwr (const struct q_globals *gv, bool auto_dispose) 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, ~(uint64_t)0); + ddsi_xqos_init_empty (xqos); + ddsi_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; @@ -184,16 +191,16 @@ static void fwr (struct proxy_writer *wr) free (wr); } -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) +static struct dds_rhc *mkrhc (struct ddsi_domaingv *gv, dds_reader *rd, dds_history_kind_t hk, int32_t hdepth, dds_destination_order_kind_t dok) { struct dds_rhc *rhc; dds_qos_t rqos; - nn_xqos_init_empty (&rqos); + ddsi_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, ~(uint64_t)0); + ddsi_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); @@ -553,9 +560,9 @@ 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) +static struct ddsi_domaingv *get_gv (dds_entity_t e) { - struct q_globals *gv; + struct ddsi_domaingv *gv; dds_entity *x; if (dds_entity_pin (e, &x) < 0) abort (); @@ -569,6 +576,9 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, dds_qos_t *qos = dds_create_qos (); dds_qset_history (qos, DDS_HISTORY_KEEP_LAST, MAX_HIST_DEPTH); dds_qset_destination_order (qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + dds_qset_deadline (qos, rand_deadline()); +#endif /* two identical readers because we need 63 conditions while we can currently only attach 32 a single reader */ 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]); @@ -584,7 +594,7 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, dds_entity_unlock (x); } - const struct q_globals *gv = get_gv (pp); + const struct ddsi_domaingv *gv = get_gv (pp); struct ddsi_tkmap *tkmap = gv->m_tkmap; struct proxy_writer *wr[] = { mkwr (gv, 0), mkwr (gv, 1), mkwr (gv, 1) }; @@ -673,7 +683,8 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, [9] = "tkc", [10] = "tkc1", [11] = "delwr", - [12] = "drpxp" + [12] = "drpxp", + [13] = "dlmis" }; static const uint32_t opfreqs[] = { [0] = 500, /* write */ @@ -689,9 +700,14 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, [10] = 100, /* take cond, max 1 */ [11] = 1, /* unreg writer */ #ifdef DDSI_INCLUDE_LIFESPAN - [12] = 100 /* drop expired sample */ + [12] = 100, /* drop expired sample */ #else - [12] = 0 /* drop expired sample */ + [12] = 0, /* drop expired sample */ +#endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + [13] = 100 /* deadline missed */ +#else + [13] = 0 /* drop expired sample */ #endif }; uint32_t opthres[sizeof (opfreqs) / sizeof (opfreqs[0])]; @@ -829,6 +845,16 @@ static void test_conditions (dds_entity_t pp, dds_entity_t tp, const int count, for (size_t k = 0; k < nrd; k++) (void) dds_rhc_default_sample_expired_cb (rhc[k], rand_texp()); thread_state_asleep (lookup_thread_state ()); +#endif + break; + } + case 13: { +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + thread_state_awake_domain_ok (lookup_thread_state ()); + /* We can assume that rhc[k] is a dds_rhc_default at this point */ + for (size_t k = 0; k < nrd; k++) + (void) dds_rhc_default_deadline_missed_cb (rhc[k], rand_texp()); + thread_state_asleep (lookup_thread_state ()); #endif break; } @@ -895,15 +921,15 @@ int main (int argc, char **argv) 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(); - mdtopic = dds_topic_lookup(x->m_domain, "RhcTypes_T"); - dds_entity_unlock(x); + struct dds_topic *x; + if (dds_topic_pin (tp, &x) < 0) abort(); + mdtopic = ddsi_sertopic_ref (x->m_stopic); + dds_topic_unpin (x); } if (0 >= first) { - struct q_globals *gv = get_gv (pp); + struct ddsi_domaingv *gv = get_gv (pp); struct ddsi_tkmap *tkmap = gv->m_tkmap; if (print) printf ("************* 0 *************\n"); @@ -954,7 +980,7 @@ int main (int argc, char **argv) if (1 >= first) { - struct q_globals *gv = get_gv (pp); + struct ddsi_domaingv *gv = get_gv (pp); struct ddsi_tkmap *tkmap = gv->m_tkmap; if (print) printf ("************* 1 *************\n"); diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt index 00d51e5..6efefdd 100644 --- a/src/ddsrt/CMakeLists.txt +++ b/src/ddsrt/CMakeLists.txt @@ -101,12 +101,17 @@ set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include") set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/src") list(APPEND headers + "${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" "${include_path}/dds/ddsrt/log.h" "${include_path}/dds/ddsrt/retcode.h" "${include_path}/dds/ddsrt/attributes.h" "${include_path}/dds/ddsrt/endian.h" "${include_path}/dds/ddsrt/arch.h" "${include_path}/dds/ddsrt/misc.h" + "${include_path}/dds/ddsrt/mh3.h" "${include_path}/dds/ddsrt/io.h" "${include_path}/dds/ddsrt/process.h" "${include_path}/dds/ddsrt/dynlib.h" @@ -114,7 +119,8 @@ list(APPEND headers "${include_path}/dds/ddsrt/strtol.h" "${include_path}/dds/ddsrt/types.h" "${include_path}/dds/ddsrt/countargs.h" - "${include_path}/dds/ddsrt/static_assert.h") + "${include_path}/dds/ddsrt/static_assert.h" + "${include_path}/dds/ddsrt/circlist.h") list(APPEND sources "${source_path}/bswap.c" @@ -122,21 +128,15 @@ list(APPEND sources "${source_path}/log.c" "${source_path}/retcode.c" "${source_path}/strtod.c" - "${source_path}/strtol.c") - -list(APPEND headers - "${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}/strtol.c" + "${source_path}/mh3.c" "${source_path}/avl.c" "${source_path}/expand_envvars.c" "${source_path}/fibheap.c" "${source_path}/hopscotch.c" "${source_path}/thread_pool.c" - "${source_path}/xmlparser.c") + "${source_path}/xmlparser.c" + "${source_path}/circlist.c") # Not every target offers the same set of features. For embedded targets the # set of features may even be different between builds. e.g. a FreeRTOS build diff --git a/src/ddsrt/include/dds/ddsrt/circlist.h b/src/ddsrt/include/dds/ddsrt/circlist.h new file mode 100644 index 0000000..767b582 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/circlist.h @@ -0,0 +1,43 @@ +/* + * 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 + */ +#ifndef DDSRT_CIRCLIST_H +#define DDSRT_CIRCLIST_H + +/* Circular doubly linked list implementation */ + +#include +#include +#include "dds/export.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define DDSRT_FROM_CIRCLIST(typ_, member_, cle_) ((typ_ *) ((char *) (cle_) - offsetof (typ_, member_))) + +struct ddsrt_circlist { + struct ddsrt_circlist_elem *latest; /* pointer to latest inserted element */ +}; + +struct ddsrt_circlist_elem { + struct ddsrt_circlist_elem *next; + struct ddsrt_circlist_elem *prev; +}; + +DDS_EXPORT void ddsrt_circlist_init (struct ddsrt_circlist *list); +DDS_EXPORT bool ddsrt_circlist_isempty (const struct ddsrt_circlist *list); +DDS_EXPORT void ddsrt_circlist_append (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem); +DDS_EXPORT void ddsrt_circlist_remove (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem); +DDS_EXPORT struct ddsrt_circlist_elem *ddsrt_circlist_oldest (const struct ddsrt_circlist *list); +DDS_EXPORT struct ddsrt_circlist_elem *ddsrt_circlist_latest (const struct ddsrt_circlist *list); + +#endif /* DDSRT_CIRCLIST_H */ diff --git a/src/ddsrt/include/dds/ddsrt/mh3.h b/src/ddsrt/include/dds/ddsrt/mh3.h new file mode 100644 index 0000000..d22e387 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/mh3.h @@ -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 + */ +#ifndef DDSRT_MH3_H +#define DDSRT_MH3_H + +#include +#include + +#include "dds/export.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +DDS_EXPORT uint32_t +ddsrt_mh3( + const void *key, + size_t len, + uint32_t seed); + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_MH3_H */ diff --git a/src/ddsrt/include/dds/ddsrt/time.h b/src/ddsrt/include/dds/ddsrt/time.h index b5ebd12..43a458b 100644 --- a/src/ddsrt/include/dds/ddsrt/time.h +++ b/src/ddsrt/include/dds/ddsrt/time.h @@ -43,7 +43,7 @@ extern "C" { /** Absolute Time definition */ typedef int64_t dds_time_t; -/** Relative Time definition */ +/** Relative Time definition in nanoseconds */ typedef int64_t dds_duration_t; /** @name Macro definition for time units in nanoseconds. diff --git a/src/ddsrt/include/dds/ddsrt/types/windows.h b/src/ddsrt/include/dds/ddsrt/types/windows.h index 7e81bf8..1171cc7 100644 --- a/src/ddsrt/include/dds/ddsrt/types/windows.h +++ b/src/ddsrt/include/dds/ddsrt/types/windows.h @@ -16,6 +16,10 @@ #define WIN32_LEAN_AND_MEAN #endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include #include #include diff --git a/src/ddsrt/src/atomics.c b/src/ddsrt/src/atomics.c index 829be41..88512da 100644 --- a/src/ddsrt/src/atomics.c +++ b/src/ddsrt/src/atomics.c @@ -119,7 +119,7 @@ extern inline int ddsrt_atomic_cas64 (volatile ddsrt_atomic_uint64_t *x, uint64_ #endif extern inline int ddsrt_atomic_casptr (volatile ddsrt_atomic_uintptr_t *x, uintptr_t exp, uintptr_t des); extern inline int ddsrt_atomic_casvoidp (volatile ddsrt_atomic_voidp_t *x, void *exp, void *des); -#if DDSRT_ATOMIC_LIFO_SUPPORT +#if DDSRT_HAVE_ATOMIC_LIFO extern inline int ddsrt_atomic_casvoidp2 (volatile ddsrt_atomic_uintptr2_t *x, uintptr_t a0, uintptr_t b0, uintptr_t a1, uintptr_t b1); #endif /* FENCES */ @@ -129,7 +129,7 @@ extern inline void ddsrt_atomic_fence_stst (void); extern inline void ddsrt_atomic_fence_acq (void); extern inline void ddsrt_atomic_fence_rel (void); -#if DDSRT_ATOMIC_LIFO_SUPPORT +#if DDSRT_HAVE_ATOMIC_LIFO void ddsrt_atomic_lifo_init (ddsrt_atomic_lifo_t *head) { head->aba_head.s.a = head->aba_head.s.b = 0; diff --git a/src/ddsrt/src/circlist.c b/src/ddsrt/src/circlist.c new file mode 100644 index 0000000..51159bd --- /dev/null +++ b/src/ddsrt/src/circlist.c @@ -0,0 +1,84 @@ +/* + * 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 + */ +#include +#include +#include +#include +#include "dds/ddsrt/circlist.h" + +void ddsrt_circlist_init (struct ddsrt_circlist *list) +{ + list->latest = NULL; +} + +bool ddsrt_circlist_isempty (const struct ddsrt_circlist *list) +{ + return list->latest == NULL; +} + +void ddsrt_circlist_append (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem) +{ + if (list->latest == NULL) + elem->next = elem->prev = elem; + else + { + struct ddsrt_circlist_elem * const hd = list->latest; +#ifndef NDEBUG + { + const struct ddsrt_circlist_elem *x = hd; + do { assert (x != elem); x = x->next; } while (x != hd); + } +#endif + elem->next = hd->next; + elem->prev = hd; + hd->next = elem; + elem->next->prev = elem; + } + list->latest = elem; +} + +void ddsrt_circlist_remove (struct ddsrt_circlist *list, struct ddsrt_circlist_elem *elem) +{ +#ifndef NDEBUG + { + const struct ddsrt_circlist_elem *x = list->latest; + assert (x); + do { if (x == elem) break; x = x->next; } while (x != list->latest); + assert (x == elem); + } +#endif + if (elem->next == elem) + list->latest = NULL; + else + { + struct ddsrt_circlist_elem * const elem_prev = elem->prev; + struct ddsrt_circlist_elem * const elem_next = elem->next; + elem_prev->next = elem_next; + elem_next->prev = elem_prev; + if (list->latest == elem) + list->latest = elem_prev; + } +} + +struct ddsrt_circlist_elem *ddsrt_circlist_oldest (const struct ddsrt_circlist *list) +{ + assert (!ddsrt_circlist_isempty (list)); + return list->latest->next; +} + +struct ddsrt_circlist_elem *ddsrt_circlist_latest (const struct ddsrt_circlist *list) +{ + assert (!ddsrt_circlist_isempty (list)); + return list->latest; +} + + diff --git a/src/ddsrt/src/mh3.c b/src/ddsrt/src/mh3.c new file mode 100644 index 0000000..f186e95 --- /dev/null +++ b/src/ddsrt/src/mh3.c @@ -0,0 +1,69 @@ +/* + * 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/mh3.h" + +#define DDSRT_MH3_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) + +/* Really + http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, + MurmurHash3_x86_32 +*/ +uint32_t ddsrt_mh3 (const void *key, size_t len, uint32_t seed) +{ + const uint8_t *data = (const uint8_t *) key; + const intptr_t nblocks = (intptr_t) (len / 4); + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + uint32_t h1 = seed; + const uint32_t *blocks = (const uint32_t *) (data + nblocks * 4); + for (intptr_t i = -nblocks; i; i++) + { + uint32_t k1 = blocks[i]; + + k1 *= c1; + k1 = DDSRT_MH3_ROTL32 (k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = DDSRT_MH3_ROTL32 (h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + const uint8_t *tail = data + nblocks * 4; + uint32_t k1 = 0; + switch (len & 3) + { + case 3: + k1 ^= (uint32_t) tail[2] << 16; + /* FALLS THROUGH */ + case 2: + k1 ^= (uint32_t) tail[1] << 8; + /* FALLS THROUGH */ + case 1: + k1 ^= (uint32_t) tail[0]; + k1 *= c1; + k1 = DDSRT_MH3_ROTL32 (k1, 15); + k1 *= c2; + h1 ^= k1; + /* FALLS THROUGH */ + }; + + /* finalization */ + h1 ^= (uint32_t) len; + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + return h1; +} diff --git a/src/ddsrt/src/threads/posix/threads.c b/src/ddsrt/src/threads/posix/threads.c index 2affcdb..3244202 100644 --- a/src/ddsrt/src/threads/posix/threads.c +++ b/src/ddsrt/src/threads/posix/threads.c @@ -39,6 +39,7 @@ typedef struct { } thread_context_t; #if defined(__linux) +#include #include #include #define MAXTHREADNAMESIZE (15) /* 16 bytes including null-terminating byte. */ @@ -72,9 +73,10 @@ ddsrt_thread_getname(char *str, size_t size) assert(size > 0); #if defined(__linux) - /* Thread names are limited to 16 bytes on Linux. ERANGE is returned if the - buffer is smaller than 16 bytes. Use an intermediate buffer. */ - (void)pthread_getname_np(pthread_self(), buf, sizeof(buf)); + /* Thread names are limited to 16 bytes on Linux, which the buffer should + allow space for. prctl is favored over pthread_getname_np for + portability. e.g. musl libc. */ + (void)prctl(PR_GET_NAME, (unsigned long)buf, 0UL, 0UL, 0UL); cnt = ddsrt_strlcpy(str, buf, size); #elif defined(__APPLE__) /* pthread_getname_np on APPLE uses strlcpy to copy the thread name, but diff --git a/src/mpt/tests/qos/procs/rw.c b/src/mpt/tests/qos/procs/rw.c index 10cceee..14889cf 100644 --- a/src/mpt/tests/qos/procs/rw.c +++ b/src/mpt/tests/qos/procs/rw.c @@ -23,7 +23,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "rwdata.h" #include "rw.h" @@ -98,7 +98,11 @@ static void setqos (dds_qos_t *q, size_t i, bool isrd, bool create) #else dds_qset_lifespan (q, DDS_INFINITY); #endif +#ifdef DDSI_INCLUDE_DEADLINE_MISSED dds_qset_deadline (q, INT64_C (67890123456789012) + (int32_t) i); +#else + dds_qset_deadline (q, DDS_INFINITY); +#endif 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); @@ -136,14 +140,14 @@ static bool pubsub_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) 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); + uint64_t delta = ddsi_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"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); } dds_delete_qos (b); return delta == 0; @@ -151,7 +155,7 @@ static bool pubsub_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) 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); + return ddsi_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) @@ -164,8 +168,8 @@ static bool reader_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) 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"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); } dds_delete_qos (b); return delta == 0; @@ -173,7 +177,7 @@ static bool reader_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) 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); + return ddsi_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) @@ -186,8 +190,8 @@ static bool writer_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) 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"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, a); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, b); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); } dds_delete_qos (b); return delta == 0; @@ -271,8 +275,8 @@ MPT_ProcessEntry (rw_publisher, 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"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + ddsi_xqos_log (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); @@ -423,8 +427,8 @@ MPT_ProcessEntry (rw_subscriber, 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"); + ddsi_xqos_log (DDS_LC_ERROR, &logcfg, qos); DDS_CLOG (DDS_LC_ERROR, &logcfg, "\n"); + ddsi_xqos_log (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); diff --git a/src/security/core/include/dds/security/core/dds_security_fsm.h b/src/security/core/include/dds/security/core/dds_security_fsm.h index 198c1c4..503c5f6 100644 --- a/src/security/core/include/dds/security/core/dds_security_fsm.h +++ b/src/security/core/include/dds/security/core/dds_security_fsm.h @@ -14,7 +14,7 @@ #define DDS_SECURITY_FSM_H #include "dds/ddsrt/time.h" -#include "dds/ddsi/q_globals.h" +#include "dds/ddsi/ddsi_domaingv.h" #if defined (__cplusplus) extern "C" { @@ -176,7 +176,7 @@ dds_security_fsm_free(struct dds_security_fsm *fsm); * @return Returns the new fsm control on success. Null on failure. */ DDS_EXPORT struct dds_security_fsm_control * -dds_security_fsm_control_create (struct q_globals *gv); +dds_security_fsm_control_create (struct ddsi_domaingv *gv); /** * Frees the fsm control and the allocated fsm's. diff --git a/src/security/core/src/dds_security_fsm.c b/src/security/core/src/dds_security_fsm.c index 4fa9d8e..8413575 100644 --- a/src/security/core/src/dds_security_fsm.c +++ b/src/security/core/src/dds_security_fsm.c @@ -66,7 +66,7 @@ struct dds_security_fsm_control ddsrt_mutex_t lock; ddsrt_cond_t cond; struct thread_state1 *ts; - struct q_globals *gv; + struct ddsi_domaingv *gv; struct dds_security_fsm *first_fsm; struct dds_security_fsm *last_fsm; struct fsm_event *event_queue; @@ -456,7 +456,7 @@ static void fsm_delete (struct dds_security_fsm_control *control, struct dds_sec ddsrt_free(fsm); } -struct dds_security_fsm_control * dds_security_fsm_control_create (struct q_globals *gv) +struct dds_security_fsm_control * dds_security_fsm_control_create (struct ddsi_domaingv *gv) { struct dds_security_fsm_control *control; diff --git a/src/security/core/tests/plugin_loading/security_config.c b/src/security/core/tests/plugin_loading/security_config.c index 5e95683..3c91f60 100644 --- a/src/security/core/tests/plugin_loading/security_config.c +++ b/src/security/core/tests/plugin_loading/security_config.c @@ -20,7 +20,7 @@ #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_misc.h" -#include "dds/ddsi/q_xqos.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/security/dds_security_api_defs.h" @@ -39,6 +39,32 @@ " initFunction=\"init_access_control\"" \ " finalizeFunction=\"finalize_access_control\" />" +#define PROPLIST(auth, crypto, ac, pre_str, post_str, binprops) \ + "property_list={" pre_str \ + "0:\"dds.sec.auth.library.path\":\""auth"\"," \ + "0:\"dds.sec.auth.library.init\":\"init_authentication\"," \ + "0:\"dds.sec.auth.library.finalize\":\"finalize_authentication\"," \ + "0:\"dds.sec.crypto.library.path\":\""crypto"\"," \ + "0:\"dds.sec.crypto.library.init\":\"init_crypto\"," \ + "0:\"dds.sec.crypto.library.finalize\":\"finalize_crypto\"," \ + "0:\"dds.sec.access.library.path\":\""ac"\"," \ + "0:\"dds.sec.access.library.init\":\"init_access_control\"," \ + "0:\"dds.sec.access.library.finalize\":\"finalize_access_control\"," \ + "0:\"dds.sec.auth.identity_ca\":\"testtext_IdentityCA_testtext\"," \ + "0:\"dds.sec.auth.private_key\":\"testtext_PrivateKey_testtext\"," \ + "0:\"dds.sec.auth.identity_certificate\":\"testtext_IdentityCertificate_testtext\"," \ + "0:\"dds.sec.access.permissions_ca\":\"file:Permissions_CA.pem\"," \ + "0:\"dds.sec.access.governance\":\"file:Governance.p7s\"," \ + "0:\"dds.sec.access.permissions\":\"file:Permissions.p7s\"" \ + post_str "}:{" binprops "}" +#define PARTICIPANT_QOS(auth, crypto, ac, pre_str, post_str, binprops) \ + "PARTICIPANT * QOS={*" PROPLIST (auth, crypto, ac, pre_str, post_str, binprops) "*" +#define PARTICIPANT_QOS_ALL_OK(pre_str, post_str, binprops) \ + PARTICIPANT_QOS (MOCKLIB_PATH ("dds_security_authentication_all_ok"), \ + MOCKLIB_PATH ("dds_security_cryptography_all_ok"), \ + MOCKLIB_PATH ("dds_security_access_control_all_ok"), \ + pre_str, post_str, binprops) + #define URI_VARIABLE DDS_PROJECT_NAME_NOSPACE_CAPS"_URI" /* @@ -52,6 +78,7 @@ static uint32_t found; static void logger(void *ptr, const dds_log_data_t *data) { char **expected = (char**)ptr; + fputs (data->message, stdout); for (uint32_t i = 0; expected[i] != NULL; i++) { if (ddsi2_patmatch(expected[i], data->message)) { found |= (uint32_t)(1 << i); @@ -196,23 +223,7 @@ CU_Test(ddsc_security_config, all, .init = ddsrt_init, .fini = ddsrt_fini) "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_crypto*", "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_crypto*", /* The config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}," - "{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,testtext_Password_testtext,0}," - "{dds.sec.auth.trusted_ca_dir,testtext_Dir_testtext,0}}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), NULL }; const char *sec_config = @@ -287,23 +298,7 @@ CU_Test(ddsc_security_config, security, .init = ddsrt_init, .fini = ddsrt_fini) "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_crypto*", "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_crypto*", /* The config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}," - "{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,,0}," - "{dds.sec.auth.trusted_ca_dir,,0}}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"\",0:\"dds.sec.auth.trusted_ca_dir\":\"\"", ""), NULL }; @@ -373,22 +368,7 @@ CU_Test(ddsc_security_config, deprecated, .init = ddsrt_init, .fini = ddsrt_fini "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_crypto*", "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_crypto*", /* The config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={" - "{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0},{dds.sec.access.library.finalize,finalize_access_control,0},{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,testtext_Password_testtext,0}," - "{dds.sec.auth.trusted_ca_dir,testtext_Dir_testtext,0}}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), NULL }; @@ -444,24 +424,7 @@ CU_Test(ddsc_security_config, qos, .init = ddsrt_init, .fini = ddsrt_fini) /* Expected traces when creating participant with the security elements. */ const char *log_expected[] = { /* The config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={" - "{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,testtext_Password_testtext,0}," - "{dds.sec.auth.trusted_ca_dir,file:/test/dir,0}," - "{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"file:/test/dir\"", ""), NULL }; @@ -473,16 +436,9 @@ CU_Test(ddsc_security_config, qos, .init = ddsrt_init, .fini = ddsrt_fini) dds_set_log_sink(&logger, (void*)log_expected); dds_set_trace_sink(&logger, (void*)log_expected); - /* Create the qos */ + /* Create the qos -- the properties are dumped in the order in which they are set, so for + PARTICIPANT_QOS_ALL_OK to work, the order must match that one */ CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); - dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); - dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); - dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); - dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); - dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); dds_qset_prop(qos, "dds.sec.auth.library.path", ""MOCKLIB_PATH("dds_security_authentication_all_ok")""); dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication"); dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication"); @@ -492,6 +448,14 @@ CU_Test(ddsc_security_config, qos, .init = ddsrt_init, .fini = ddsrt_fini) dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); + dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); + dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); + dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); + dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); /* Create participant with security config in qos. */ found = 0; @@ -513,27 +477,8 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) /* Expected traces when creating participant with the security elements. */ const char *log_expected[] = { /* The config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={" - "{test.prop1,testtext_value1_testtext,0}," - "{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,testtext_Password_testtext,0}," - "{dds.sec.auth.trusted_ca_dir,file:/test/dir,0}," - "{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}," - "{test.prop2,testtext_value2_testtext,0}}" - "binary_value={{test.bprop1,(3,*),0}}}*}*", + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"file:/test/dir\",0:\"test.prop1\":\"testtext_value1_testtext\",0:\"test.prop2\":\"testtext_value2_testtext\"", + "0:\"test.bprop1\":3<1,2,3>"), NULL }; @@ -545,19 +490,10 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) dds_set_log_sink(&logger, (void*)log_expected); dds_set_trace_sink(&logger, (void*)log_expected); - /* Create the qos */ + /* Create the qos -- the properties are dumped in the order in which they are set, so for + PARTICIPANT_QOS_ALL_OK to work, the order must match that one */ unsigned char bvalue[3] = { 0x01, 0x02, 0x03 }; CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); - dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); - dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); - dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); - dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); - dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); - dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); - dds_qset_prop(qos, "dds.sec.auth.library.path", ""MOCKLIB_PATH("dds_security_authentication_all_ok")""); dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication"); dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication"); @@ -567,10 +503,17 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); - - dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); + dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); + dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); + dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); + dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); + + dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); + dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); dds_qset_bprop(qos, "test.bprop1", bvalue, 3); @@ -595,23 +538,7 @@ CU_Test(ddsc_security_config, config_qos, .init = ddsrt_init, .fini = ddsrt_fini const char *log_expected[] = { /* The security settings from qos properties should have been parsed into the participant QoS. */ "new_participant(*): using security settings from QoS*", - "PARTICIPANT * QOS={*property_list={value={" - "{dds.sec.auth.identity_ca,testtext_QOS_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_QOS_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_QOS_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:QOS_Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:QOS_Governance.p7s,0}," - "{dds.sec.access.permissions,file:QOS_Permissions.p7s,0}," - "{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}" - "}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("", "", ""), NULL }; @@ -633,23 +560,24 @@ CU_Test(ddsc_security_config, config_qos, .init = ddsrt_init, .fini = ddsrt_fini dds_entity_t participant; dds_qos_t * qos; + /* Create the qos -- the properties are dumped in the order in which they are set, so for + PARTICIPANT_QOS_ALL_OK to work, the order must match that one */ CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_QOS_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_QOS_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_QOS_IdentityCertificate_testtext"); - dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:QOS_Permissions_CA.pem"); - dds_qset_prop(qos, "dds.sec.access.governance", "file:QOS_Governance.p7s"); - dds_qset_prop(qos, "dds.sec.access.permissions", "file:QOS_Permissions.p7s"); - - dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, ""MOCKLIB_PATH("dds_security_authentication_all_ok")""); - dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_authentication"); - dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_authentication"); - dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, ""MOCKLIB_PATH("dds_security_cryptography_all_ok")""); - dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_crypto"); - dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_crypto"); - dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); - dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_access_control"); - dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_access_control"); + dds_qset_prop(qos, "dds.sec.auth.library.path", ""MOCKLIB_PATH("dds_security_authentication_all_ok")""); + dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication"); + dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication"); + dds_qset_prop(qos, "dds.sec.crypto.library.path", ""MOCKLIB_PATH("dds_security_cryptography_all_ok")""); + dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_crypto"); + dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_crypto"); + dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); + dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); + dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); + dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); + dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); /* Set up the trace sinks to detect the config parsing. */ dds_set_log_mask(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_WARNING | DDS_LC_CONFIG); @@ -677,24 +605,7 @@ CU_Test(ddsc_security_config, other_prop, .init = ddsrt_init, .fini = ddsrt_fini * qos containing only non-security properties. */ const char *log_expected[] = { /* The security settings from config should have been parsed into the participant QoS. */ - "PARTICIPANT * QOS={*property_list={value={{test.dds.sec.prop1,testtext_value1_testtext,0}," - "{dds.sec.auth.library.path,"MOCKLIB_PATH("dds_security_authentication_all_ok")",0}," - "{dds.sec.auth.library.init,init_authentication,0}," - "{dds.sec.auth.library.finalize,finalize_authentication,0}," - "{dds.sec.crypto.library.path,"MOCKLIB_PATH("dds_security_cryptography_all_ok")",0}," - "{dds.sec.crypto.library.init,init_crypto,0}," - "{dds.sec.crypto.library.finalize,finalize_crypto,0}," - "{dds.sec.access.library.path,"MOCKLIB_PATH("dds_security_access_control_all_ok")",0}," - "{dds.sec.access.library.init,init_access_control,0}," - "{dds.sec.access.library.finalize,finalize_access_control,0}," - "{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0}," - "{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0}," - "{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0}," - "{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0}," - "{dds.sec.access.governance,file:Governance.p7s,0}," - "{dds.sec.access.permissions,file:Permissions.p7s,0}," - "{dds.sec.auth.password,testtext_Password_testtext,0}," - "{dds.sec.auth.trusted_ca_dir,testtext_Dir_testtext,0}}binary_value={}}*}*", + PARTICIPANT_QOS_ALL_OK ("0:\"test.dds.sec.prop1\":\"testtext_value1_testtext\",", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), NULL }; diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c index 8fe6eae..628778b 100644 --- a/src/tools/ddsperf/ddsperf.c +++ b/src/tools/ddsperf/ddsperf.c @@ -969,18 +969,24 @@ static void maybe_send_new_ping (dds_time_t tnow, dds_time_t *tnextping) } } -static uint32_t subthread_waitset (void *varg) +static dds_entity_t make_reader_waitset (dds_entity_t rd) { - struct subthread_arg * const arg = varg; dds_entity_t ws; int32_t rc; ws = dds_create_waitset (dp); if ((rc = dds_waitset_attach (ws, termcond, 0)) < 0) error2 ("dds_waitset_attach (termcond, 0): %d\n", (int) rc); - if ((rc = dds_set_status_mask (rd_data, DDS_DATA_AVAILABLE_STATUS)) < 0) - 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); + if ((rc = dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS)) < 0) + error2 ("dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS): %d\n", (int) rc); + if ((rc = dds_waitset_attach (ws, rd, 1)) < 0) + error2 ("dds_waitset_attach (ws, rd, 1): %d\n", (int) rc); + return ws; +} + +static uint32_t subthread_waitset (void *varg) +{ + struct subthread_arg * const arg = varg; + dds_entity_t ws = make_reader_waitset (rd_data); while (!ddsrt_atomic_ld32 (&termflag)) { if (!process_data (rd_data, arg)) @@ -998,15 +1004,7 @@ static uint32_t subthread_waitset (void *varg) static uint32_t subpingthread_waitset (void *varg) { struct subthread_arg * const arg = varg; - dds_entity_t ws; - int32_t rc; - ws = dds_create_waitset (dp); - if ((rc = dds_waitset_attach (ws, termcond, 0)) < 0) - error2 ("dds_waitset_attach (termcond, 0): %d\n", (int) rc); - if ((rc = dds_set_status_mask (rd_ping, DDS_DATA_AVAILABLE_STATUS)) < 0) - 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); + dds_entity_t ws = make_reader_waitset (rd_ping); while (!ddsrt_atomic_ld32 (&termflag)) { int32_t nxs; @@ -1020,15 +1018,7 @@ static uint32_t subpingthread_waitset (void *varg) static uint32_t subpongthread_waitset (void *varg) { struct subthread_arg * const arg = varg; - dds_entity_t ws; - int32_t rc; - ws = dds_create_waitset (dp); - if ((rc = dds_waitset_attach (ws, termcond, 0)) < 0) - error2 ("dds_waitset_attach (termcond, 0): %d\n", (int) rc); - if ((rc = dds_set_status_mask (rd_pong, DDS_DATA_AVAILABLE_STATUS)) < 0) - 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); + dds_entity_t ws = make_reader_waitset (rd_pong); while (!ddsrt_atomic_ld32 (&termflag)) { int32_t nxs; @@ -1101,7 +1091,7 @@ static dds_entity_t create_pong_writer (dds_instance_handle_t pphandle, const st return wr_pong; } -static void delete_pong_writer (dds_instance_handle_t pphandle) +static dds_entity_t delete_pong_writer (dds_instance_handle_t pphandle) { uint32_t i = 0; dds_entity_t wr_pong = 0; @@ -1118,8 +1108,7 @@ static void delete_pong_writer (dds_instance_handle_t pphandle) } } ddsrt_mutex_unlock (&pongwr_lock); - if (wr_pong) - dds_delete (wr_pong); + return wr_pong; } static void free_ppant (void *vpp) @@ -1143,6 +1132,7 @@ static void participant_data_listener (dds_entity_t rd, void *arg) if (info.instance_state != DDS_ALIVE_INSTANCE_STATE) { ddsrt_avl_dpath_t dpath; + dds_entity_t pong_wr_to_del = 0; ddsrt_mutex_lock (&disc_lock); if ((pp = ddsrt_avl_lookup_dpath (&ppants_td, &ppants, &info.instance_handle, &dpath)) != NULL) { @@ -1151,7 +1141,7 @@ static void participant_data_listener (dds_entity_t rd, void *arg) if (pp->handle != dp_handle || ignorelocal == DDS_IGNORELOCAL_NONE) { - delete_pong_writer (pp->handle); + pong_wr_to_del = delete_pong_writer (pp->handle); n_pong_expected_delta--; } @@ -1161,6 +1151,7 @@ static void participant_data_listener (dds_entity_t rd, void *arg) free_ppant (pp); } ddsrt_mutex_unlock (&disc_lock); + dds_delete (pong_wr_to_del); } else { @@ -1171,6 +1162,7 @@ static void participant_data_listener (dds_entity_t rd, void *arg) /* only add unknown participants with the magic user_data value: DDSPerf:X:HOSTNAME, where X is decimal */ if (dds_qget_userdata (sample->qos, &vudata, &usz) && usz > 0) { + bool make_pongwr = false; const char *udata = vudata; int has_reader, pos; long pid; @@ -1199,15 +1191,17 @@ static void participant_data_listener (dds_entity_t rd, void *arg) ddsrt_fibheap_insert (&ppants_to_match_fhd, &ppants_to_match, pp); ddsrt_avl_insert_ipath (&ppants_td, &ppants, pp, &ipath); - if (pp->handle != dp_handle || ignorelocal == DDS_IGNORELOCAL_NONE) - { - struct guidstr guidstr; - make_guidstr (&guidstr, &sample->key); - create_pong_writer (pp->handle, &guidstr); - n_pong_expected_delta++; - } + make_pongwr = (pp->handle != dp_handle || ignorelocal == DDS_IGNORELOCAL_NONE); } ddsrt_mutex_unlock (&disc_lock); + + if (make_pongwr) + { + struct guidstr guidstr; + make_guidstr (&guidstr, &sample->key); + create_pong_writer (pp->handle, &guidstr); + n_pong_expected_delta++; + } } dds_free (vudata); } @@ -1312,8 +1306,8 @@ static void subscription_matched_listener (dds_entity_t rd, const dds_subscripti static void publication_matched_listener (dds_entity_t wr, const dds_publication_matched_status_t status, void *arg) { /* this only works because the listener is called for every match; but I don't think that is something the - spec guarantees, and I don't think Cyclone should guarantee that either -- and if it isn't guaranteed - _really_ needs the get_matched_... interfaces to not have to implement the matching logic ... */ + spec guarantees, and I don't think Cyclone should guarantee that either -- and if it isn't guaranteed + _really_ needs the get_matched_... interfaces to not have to implement the matching logic ... */ (void) wr; if (status.current_count_change > 0) { @@ -1326,8 +1320,8 @@ static void publication_matched_listener (dds_entity_t wr, const dds_publication static void set_data_available_listener (dds_entity_t rd, const char *rd_name, dds_on_data_available_fn fn, void *arg) { /* This convoluted code is so that we leave all listeners unchanged, except the - data_available one. There is no real need for these complications, but it is - a nice exercise. */ + data_available one. There is no real need for these complications, but it is + a nice exercise. */ dds_listener_t *listener = dds_create_listener (arg); dds_return_t rc; dds_lset_data_available (listener, fn); diff --git a/src/tools/decode-trace b/src/tools/decode-trace index eedeee5..e534669 100755 --- a/src/tools/decode-trace +++ b/src/tools/decode-trace @@ -36,6 +36,7 @@ for (@showopts) { my $topfmt = "%${topcolwidth}.${topcolwidth}s"; my $guidre = "[0-9a-f]+(?::[0-9a-f]+){3}"; my $gidre = "[0-9a-f]+(?::[0-9a-f]+){2}"; +my $leasere = "(?:L\\((?:[a-z]+ )?[0-9a-f:]+\\s+[0-9.]+\\)\\s*)+"; my %opstr = ("00" => "R ", "01" => "W ", # index by $stinfo.$dflag "10" => " D ", "11" => "WD ", "20" => " U", "21" => "W U", @@ -258,7 +259,7 @@ while(<>) { # decent proxy for that. # # FIXME: find a way of dealing with decimal representation ... - if (/: ACKNACK\(F?#\d+:(\d+)\/(\d+):[01]* (?:L\([0-9a-f:]+\s+[0-9.]+\)\s*)?([0-9a-f]+(?::[0-9a-f]+){2}:[234]c7) -\> ([0-9a-f]+(?::[0-9a-f]+){2}:[234]c2) .*?(happy-now)?/) { + if (/: ACKNACK\(F?#\d+:(\d+)\/(\d+):[01]* (?:$leasere)?([0-9a-f]+(?::[0-9a-f]+){2}:[234]c7) -\> ([0-9a-f]+(?::[0-9a-f]+){2}:[234]c2) .*?(happy-now)?/) { if (defined $5 || ($1 > 1 && $2 == 0 && version_at_least(6,6,4))) { # happy-now should be enough, but historically DDSI2 advertised only data present in the WHC, # which caused happy-now to not show up if the historical data ended on an unregister, because @@ -266,7 +267,7 @@ while(<>) { # last one written (that is, unregistered) (fixed in 6.6.4) check_disccomplete("A", $3); } - } elsif (/: HEARTBEAT\(F?#\d+:(\d+)\.\.(\d+)\s+(?:L\([0-9a-f:]+\s+[0-9.]+\)\s*)?([0-9a-f]+(?::[0-9a-f]+){2}:[234]c2)/) { + } elsif (/: HEARTBEAT\(F?L?#\d+:(\d+)\.\.(\d+)\s+(?:$leasere)?([0-9a-f]+(?::[0-9a-f]+){2}:[234]c2)/) { check_disccomplete("H", $3); # if there is no data and final is set there might be no ACK check_disccomplete("B", $3) if $2 < $1; @@ -351,8 +352,10 @@ while(<>) { $rwguid{$tid} = $guid; # if $is_cyclone; die "$guid $rwguid{$tid}" unless $guid eq $rwguid{$tid}; my $topic; my $type; my $groupcoh; my $partitions; my $keepall; - if ($3 =~ /topic=([^,]+?),type=([^,]+?).*?,presentation=(\d:\d):\d,partition=\{([^}]*?)\}.*?,history=([01]):/) { - $topic = $1; $type = $2; $groupcoh = ($3 eq "2:1"); $partitions = $4; $keepall = $5; + if ($qos =~ /topic(?:_name)?=([^,]+?),type(?:_name)=([^,]+?).*?,partition=\{([^}]*?)\}/) { + $topic = $1; $type = $2; $partitions = $3; + die unless $qos =~ /,history=([01]):/; $keepall = $1; + die unless $qos =~ /,presentation=(\d:\d):\d/; $groupcoh = ($1 eq "2:1"); unless (defined $rwguid{$tid} && ($ftrflag{$tid} || (defined $psgid{$tid} && defined $psguid{$tid} && defined $rwgid{$tid})) || 1) { # $is_cyclone die; } @@ -622,15 +625,14 @@ while(<>) { my $h = ($kind eq "READER") ? \%prd : \%pwr; my $hk = ($kind eq "READER") ? "prd" : "pwr"; my $qos = $3; - unless ($3 =~ /topic=([^,]+?),type=([^,]+?),presentation=(\d+):\d+:\d+,partition=\{([^}]*?)\}.*?,durability=(\d+)/) { + unless ($3 =~ /topic(?:_name)?=([^,]+?),type(?:_name)?=([^,]+?),(?:.+?,)?partition=\{([^}]*?)\}/) { die unless $prwguid =~ /[4c][27]$/; } - my $topic = $1; my $type = $2; my $access_scope = $3; my $partitions = $4; my $durkind = $5; + my $topic = $1; my $type = $2; my $partitions = $3; (my $ppguid = $prwguid) =~ s/:[0-9a-f]+$/:1c1/; die unless exists $proxypp{$ppguid} && !defined $proxypp{$ppguid}->{tdel}; my @ps = split ',', $partitions; my $stopic = make_stopic($partitions, $topic); - #print "$kind $topic\n" if $durkind >= 2 && ($kind eq "READER" || $access_scope >= 2); my $prw = { guid => $prwguid, ppguid => $ppguid, topic => $topic, stopic => $stopic, type => $type, partition => \@ps, matches => {}, checklost => 0, suppressbegin => 0, tcreate => $ts, tstamps => {} }; @@ -745,7 +747,7 @@ while(<>) { if $nlost > 0 && $shows{rematch}; delete $prd->{matches}->{$wrguid}->{seqp1del}; } - } elsif (/ACKNACK\(F?#\d+:(\d+)\/\d+:([01]*) (?:L\(:1c1 [0-9.]+\) )?($guidre) -> ($guidre)(\??)/o) { + } elsif (/ACKNACK\(F?#\d+:(\d+)\/\d+:([01]*) (?:$leasere)?($guidre) -> ($guidre)(\??)/o) { my $seqp1 = $1; my $nackset = $2; my $prdguid = hexify($3); my $wrguid = hexify($4); my $wrknown = ($5 eq ""); my $wr = $wr{$wrguid}; my $cnt = ($nackset =~ y/1//); @@ -904,7 +906,7 @@ while(<>) { } } } - } elsif (/HEARTBEAT\(F?#\d+:(\d+)\.\.(\d+) ($guidre)/o) { + } elsif (/HEARTBEAT\(F?L?#\d+:(\d+)\.\.(\d+) ($guidre)/o) { my $prdguid = hexify($3); (my $ppguid = $prdguid) =~ s/:[0-9a-f]+$/:1c1/; $proxypp{$ppguid}->{non_spdp_seen} = 1 if exists $proxypp{$ppguid} && !defined $proxypp{$ppguid}->{tdel}; @@ -1475,7 +1477,7 @@ not necessarily the 4th field in, say, AWK): EOT ; exit 1; - return; + return; } sub fmtblurb {