Merge branch 'master' into security

Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
Erik Boasson 2020-02-12 16:00:57 +01:00
commit ad58db0721
158 changed files with 6915 additions and 3361 deletions

View file

@ -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}";

View file

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

View file

@ -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}}) {

View file

@ -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]

View file

@ -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: &quot;single&quot;.</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:
&quot;lax&quot;.</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: &quot;false&quot;.</p>""" ] ]
<p>This element allows selecting the transport to be used (udp, udp6,
tcp, tcp6, raweth)</p><p>The default value is: &quot;default&quot;.</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:
&quot;default&quot;.</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: &quot;writers&quot;.</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: &quot;-1&quot;.</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: &quot;true&quot;.</p>""" ] ]
receive thread (false) or whether multiple receive threads may be used to
improve latency (true). By default it is disabled on Windows because it
appears that one cannot count on being able to send packets to oneself,
which is necessary to stop the thread during shutdown. Currently multiple
receive threads are only used for connectionless transport (e.g., UDP)
and ManySocketsMode not set to single (the default).</p><p>The default
value is: &quot;default&quot;.</p>""" ] ]
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:
&quot;never&quot;.</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: &quot;false&quot;.</p>""" ] ]
General/Transport instead.</p><p>The default value is:
&quot;default&quot;.</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:
&quot;default&quot;.</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: &quot;none&quot;.</p>""" ] ]
element Verbosity {
"finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none"
("finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none")
}?
}*
}*

View file

@ -1379,14 +1379,24 @@ is: &amp;quot;-1&amp;quot;.&lt;/p&gt;</xs:documentation>
<xs:annotation>
<xs:documentation>
&lt;p&gt;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).&lt;/p&gt;&lt;p&gt;The default value is: &amp;quot;true&amp;quot;.&lt;/p&gt;</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).&lt;/p&gt;&lt;p&gt;The default
value is: &amp;quot;default&amp;quot;.&lt;/p&gt;</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.&lt;/p&gt;&lt;p&gt;The default value is:
&amp;quot;4294967295&amp;quot;.&lt;/p&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
</xs:element>

View file

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

View file

@ -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

View file

@ -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

View 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

View file

@ -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;

View file

@ -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 (

View file

@ -18,8 +18,6 @@
extern "C" {
#endif
void dds_sample_free_contents (char * data, const uint32_t * ops);
#if defined (__cplusplus)
}
#endif

View file

@ -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);

View file

@ -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

View file

@ -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" {

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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;

View file

@ -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)
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

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

View file

@ -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;

View file

@ -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);

View file

@ -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)
{

View file

@ -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;

View file

@ -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);

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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;

View file

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

View file

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

View file

@ -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

View file

@ -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;

View file

@ -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

View 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);
}

View file

@ -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");
}
}
}
}
}

View 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);
}

View file

@ -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);

View file

@ -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
View 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

View file

@ -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})

View file

@ -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);

View 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 */

View 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 */

View file

@ -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 */

View file

@ -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;

View file

@ -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 */

View file

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

View file

@ -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);

View file

@ -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)
}

View file

@ -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 */

View file

@ -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);

View file

@ -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)
}

View file

@ -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"

View file

@ -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),

View file

@ -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);
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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)
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)
}

View file

@ -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 */

View file

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

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)
}

View file

@ -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)
}

View file

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

View file

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

View file

@ -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];

View file

@ -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);

View file

@ -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);

View file

@ -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)
}

View file

@ -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 */

View file

@ -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)
}

View file

@ -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) {

View file

@ -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)
}

View file

@ -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))
{

View 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);
}

View 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;
}

View file

@ -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));

View file

@ -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