Merge branch 'master' into security
Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
commit
ad58db0721
158 changed files with 6915 additions and 3361 deletions
31
.travis.yml
31
.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='<CycloneDDS><Domain><Internal><EnableExpensiveChecks>all</EnableExpensiveChecks></Internal><Tracing><Verbosity>config</Verbosity><OutputFile>stderr</OutputFile></Tracing></Domain></CycloneDDS>' ctest -j 4 --output-on-failure -T test -E '^CUnit_ddsrt_random_default_random$' -C ${BUILD_TYPE}
|
||||
- CYCLONEDDS_URI='<CycloneDDS><Domain><Internal><EnableExpensiveChecks>all</EnableExpensiveChecks><LivelinessMonitoring>true</LivelinessMonitoring></Internal><Tracing><Verbosity>config</Verbosity><OutputFile>stderr</OutputFile></Tracing></Domain></CycloneDDS>' 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}";
|
||||
|
|
30
README.md
30
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 <REMOTE> https://api.bintray.com/conan/bincrafters/public-conan
|
||||
|
||||
Replace ``<REMOTE>`` 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 <install-location>/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.
|
||||
|
|
|
@ -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}}) {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.</p><p>The default value is: "single".</p>""" ] ]
|
||||
element ManySocketsMode {
|
||||
"false"|"true"|"single"|"none"|"many"
|
||||
("false"|"true"|"single"|"none"|"many")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>This element sets the level of standards conformance of this instance
|
||||
|
@ -78,7 +78,7 @@ though there is no good reason not to.</li></ul>
|
|||
<p>The default setting is "lax".</p><p>The default value is:
|
||||
"lax".</p>""" ] ]
|
||||
element StandardsConformance {
|
||||
"lax"|"strict"|"pedantic"
|
||||
("lax"|"strict"|"pedantic")
|
||||
}?
|
||||
}*
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
|
@ -745,13 +745,13 @@ is available.</p><p>The default value is: "false".</p>""" ] ]
|
|||
<p>This element allows selecting the transport to be used (udp, udp6,
|
||||
tcp, tcp6, raweth)</p><p>The default value is: "default".</p>""" ] ]
|
||||
element Transport {
|
||||
"default"|"udp"|"udp6"|"tcp"|"tcp6"|"raweth"
|
||||
("default"|"udp"|"udp6"|"tcp"|"tcp6"|"raweth")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>Deprecated (use Transport instead)</p><p>The default value is:
|
||||
"default".</p>""" ] ]
|
||||
element UseIPv6 {
|
||||
"false"|"true"|"default"
|
||||
("false"|"true"|"default")
|
||||
}?
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
|
@ -810,7 +810,7 @@ most efficient, and <i>full</i> is inefficient but certain to be
|
|||
compliant. See also Internal/ConservativeBuiltinReaderStartup.</p><p>The
|
||||
default value is: "writers".</p>""" ] ]
|
||||
element BuiltinEndpointSet {
|
||||
"full"|"writers"|"minimal"
|
||||
("full"|"writers"|"minimal")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>The ControlTopic element allows configured whether Cyclone DDS
|
||||
|
@ -1036,10 +1036,13 @@ is: "-1".</p>""" ] ]
|
|||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<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: "true".</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: "default".</p>""" ] ]
|
||||
element MultipleReceiveThreads {
|
||||
[ a:documentation [ xml:lang="en" """
|
||||
<p>Receive threads dedicated to a single socket can only be triggered for
|
||||
|
@ -1051,7 +1054,7 @@ attribute before aborting.</p><p>The default value is:
|
|||
attribute maxretries {
|
||||
xsd:integer
|
||||
}?
|
||||
& xsd:boolean
|
||||
& ("false"|"true"|"default")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>This setting controls the delay between receipt of a HEARTBEAT
|
||||
|
@ -1136,7 +1139,7 @@ try to merge.</li></ul>
|
|||
Internal/RetransmitMergingPeriod.</p><p>The default value is:
|
||||
"never".</p>""" ] ]
|
||||
element RetransmitMerging {
|
||||
"never"|"adaptive"|"always"
|
||||
("never"|"adaptive"|"always")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>This setting determines the size of the time window in which a NACK of
|
||||
|
@ -1521,7 +1524,7 @@ using TCP.</p><p>The default value is: "false".</p>""" ] ]
|
|||
General/Transport instead.</p><p>The default value is:
|
||||
"default".</p>""" ] ]
|
||||
element Enable {
|
||||
"false"|"true"|"default"
|
||||
("false"|"true"|"default")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>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.</p><p>The default value is:
|
||||
"default".</p>""" ] ]
|
||||
element Class {
|
||||
"realtime"|"timeshare"|"default"
|
||||
("realtime"|"timeshare"|"default")
|
||||
}?
|
||||
& [ a:documentation [ xml:lang="en" """
|
||||
<p>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 <i>config</i>, <i>fine</i> and
|
||||
<i>finest</i>.</p><p>The default value is: "none".</p>""" ] ]
|
||||
element Verbosity {
|
||||
"finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none"
|
||||
("finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none")
|
||||
}?
|
||||
}*
|
||||
}*
|
||||
|
|
|
@ -1379,14 +1379,24 @@ is: &quot;-1&quot;.</p></xs:documentation>
|
|||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<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></xs:documentation>
|
||||
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></xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:boolean">
|
||||
<xs:restriction base="xs:anyType">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="false"/>
|
||||
<xs:enumeration value="true"/>
|
||||
<xs:enumeration value="default"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:attribute name="maxretries" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
|
@ -1398,7 +1408,7 @@ attribute before aborting.</p><p>The default value is:
|
|||
&quot;4294967295&quot;.</p></xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:extension>
|
||||
</xs:restriction>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/dd
|
|||
ddsc/dds_public_qosdefs.h
|
||||
ddsc/dds_public_status.h
|
||||
ddsc/dds_rhc.h
|
||||
ddsc/dds_internal_api.h
|
||||
)
|
||||
|
||||
PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
|
||||
|
@ -69,7 +69,6 @@ PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
|
|||
dds__guardcond.h
|
||||
dds__reader.h
|
||||
dds__rhc_default.h
|
||||
dds__stream.h
|
||||
dds__subscriber.h
|
||||
dds__topic.h
|
||||
dds__types.h
|
||||
|
|
|
@ -50,6 +50,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct dds_rhc;
|
||||
struct ddsi_plist;
|
||||
struct ddsi_sertopic;
|
||||
struct ddsi_serdata;
|
||||
|
||||
#define DDS_MIN_PSEUDO_HANDLE ((dds_entity_t) 0x7fff0000)
|
||||
|
@ -555,7 +557,9 @@ dds_set_enabled_status(dds_entity_t entity, uint32_t mask);
|
|||
* @param[in] entity Entity on which to get qos.
|
||||
* @param[out] qos Pointer to the qos structure that returns the set policies.
|
||||
*
|
||||
* @returns A dds_return_t indicating success or failure.
|
||||
* @returns A dds_return_t indicating success or failure. The QoS object will have
|
||||
* at least all QoS relevant for the entity present and the corresponding dds_qget_...
|
||||
* will return true.
|
||||
*
|
||||
* @retval DDS_RETCODE_OK
|
||||
* The existing set of QoS policy values applied to the entity
|
||||
|
@ -962,7 +966,9 @@ dds_lookup_participant(
|
|||
* @brief Creates a new topic with default type handling.
|
||||
*
|
||||
* The type name for the topic is taken from the generated descriptor. 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.
|
||||
*
|
||||
* @param[in] participant Participant on which to create the topic.
|
||||
* @param[in] descriptor An IDL generated topic descriptor.
|
||||
|
@ -970,14 +976,20 @@ dds_lookup_participant(
|
|||
* @param[in] qos QoS to set on the new topic (can be NULL).
|
||||
* @param[in] listener Any listener functions associated with the new topic (can be NULL).
|
||||
*
|
||||
* @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 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
|
||||
|
|
44
src/core/ddsc/include/dds/ddsc/dds_internal_api.h
Normal file
44
src/core/ddsc/include/dds/ddsc/dds_internal_api.h
Normal file
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dds_sample_free_contents (char * data, const uint32_t * ops);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 -> <type_name, QoS> 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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,21 +13,9 @@
|
|||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,14 +10,15 @@
|
|||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
484
src/core/ddsc/tests/deadline.c
Normal file
484
src/core/ddsc/tests/deadline.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
|
||||
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);
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
608
src/core/ddsc/tests/multi_sertopic.c
Normal file
608
src/core/ddsc/tests/multi_sertopic.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_multi_sertopic_tests.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
|
||||
/* 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
279
src/core/ddsc/tests/whc.c
Normal file
279
src/core/ddsc/tests/whc.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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:+,}<Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
#define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}<Tracing><OutputFile>cyclonedds_whc_test.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.log</OutputFile><Verbosity>finest</Verbosity></Tracing><Discovery><ExternalDomainId>0</ExternalDomainId></Discovery>"
|
||||
|
||||
#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
|
|
@ -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})
|
||||
|
|
|
@ -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);
|
84
src/core/ddsi/include/dds/ddsi/ddsi_deadline.h
Normal file
84
src/core/ddsi/include/dds/ddsi/ddsi_deadline.h
Normal file
|
@ -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 */
|
||||
|
62
src/core/ddsi/include/dds/ddsi/ddsi_deliver_locally.h
Normal file
62
src/core/ddsi/include/dds/ddsi/ddsi_deliver_locally.h
Normal file
|
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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 */
|
|
@ -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 <stdio.h>
|
||||
|
||||
|
@ -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 */
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
{
|
112
src/core/ddsi/src/ddsi_deadline.c
Normal file
112
src/core/ddsi/src/ddsi_deadline.c
Normal file
|
@ -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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
269
src/core/ddsi/src/ddsi_deliver_locally.c
Normal file
269
src/core/ddsi/src/ddsi_deliver_locally.c
Normal file
|
@ -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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue