Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extensions to support shm #125

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,14 @@ install(
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld"
COMPONENT dev)

install(
FILES helloworld_shm/publisher_shm.cpp
helloworld_shm/subscriber_shm.cpp
helloworld_shm/HelloWorldDataShm.idl
helloworld_shm/CMakeLists.txt
helloworld_shm/readme.rst
DESTINATION "${CMAKE_INSTALL_EXAMPLESDIR}/helloworld_shm"
COMPONENT dev)

add_subdirectory(helloworld)
add_subdirectory(helloworld_shm)
38 changes: 38 additions & 0 deletions examples/helloworld_shm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# 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
#
project(helloworld_shm LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.5)

if(NOT TARGET CycloneDDS-CXX::ddscxx)
find_package(CycloneDDS-CXX REQUIRED)
endif()

idlcxx_generate(TARGET helloworlddatashm FILES HelloWorldDataShm.idl)

add_executable(ddscxxHelloworldPublisherShm publisher_shm.cpp)
add_executable(ddscxxHelloworldSubscriberShm subscriber_shm.cpp)

# Link both executables to idl data type library and ddscxx.
target_link_libraries(ddscxxHelloworldPublisherShm CycloneDDS-CXX::ddscxx helloworlddatashm)
target_link_libraries(ddscxxHelloworldSubscriberShm CycloneDDS-CXX::ddscxx helloworlddatashm)

# Disable the static analyzer in GCC to avoid crashing the GNU C++ compiler
# on Azure Pipelines
if(DEFINED ENV{SYSTEM_TEAMFOUNDATIONSERVERURI})
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND ANALYZER STREQUAL "on")
target_compile_options(ddscxxHelloworldPublisherShm PRIVATE -fno-analyzer)
target_compile_options(ddscxxHelloworldSubscriberShm PRIVATE -fno-analyzer)
endif()
endif()

set_property(TARGET ddscxxHelloworldPublisherShm PROPERTY CXX_STANDARD 17)
set_property(TARGET ddscxxHelloworldSubscriberShm PROPERTY CXX_STANDARD 17)
19 changes: 19 additions & 0 deletions examples/helloworld_shm/HelloWorldDataShm.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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
*/
module HelloWorldDataShm
{
struct Msg
{
long data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is enough to just have this small of a message?

Maybe it is better to have a message with a huge payload to better illustrate the performance increase iceoryx can cause?

};
#pragma keylist Msg data
};
99 changes: 99 additions & 0 deletions examples/helloworld_shm/publisher_shm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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
*/
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <thread>

/* Include the C++ DDS API. */
#include "dds/dds.hpp"

/* Include data type and specific traits to be used with the C++ DDS API. */
#include "HelloWorldDataShm.hpp"

using namespace org::eclipse::cyclonedds;

int main() {
try {
std::cout << "=== [Publisher] Create writer." << std::endl;

/* First, a domain participant is needed.
* Create one on the default domain. */
dds::domain::DomainParticipant participant(domain::default_id());

/* To publish something, a topic is needed. */
dds::topic::Topic<HelloWorldDataShm::Msg> topic(participant, "HelloWorldData_Shm");

/* A writer also needs a publisher. */
dds::pub::Publisher publisher(participant);

/* Set DataWriter QoS
* SHM currently only supports reliable, volatile and keep last QoS on the writer side
*/
dds::pub::qos::DataWriterQos qos;
qos << dds::core::policy::Reliability::Reliable();
qos << dds::core::policy::Durability::Volatile();
qos << dds::core::policy::History::KeepLast(10U);

/* Now, the writer can be created to publish a HelloWorld message. */
dds::pub::DataWriter<HelloWorldDataShm::Msg> writer(publisher, topic, qos);

/* For this example, we'd like to have a subscriber to actually read
* our message. This is not always necessary. Also, the way it is
* done here is just to illustrate the easiest way to do so. It isn't
* really recommended to do a wait in a polling loop, however.
* Please take a look at Listeners and WaitSets for much better
* solutions, albeit somewhat more elaborate ones. */
std::cout << "=== [Publisher] Waiting for subscriber." << std::endl;
while (writer.publication_matched_status().current_count() == 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}

/* Loan the memory for the message */
HelloWorldDataShm::Msg &loaned_msg = writer->loan_sample();

/* Fill the message */
loaned_msg.data(4321);

/* Realize you do not intend to write this message and cancel the loan. */
writer->return_loan(loaned_msg);

/* Loan memory for a new message */
loaned_msg = writer->loan_sample();

/* Fill the message */
loaned_msg.data(1234);

/* Write the message. */
std::cout << "=== [Publisher] Write sample." << std::endl;
writer.write(loaned_msg);

/* With a normal configuration (see dds::pub::qos::DataWriterQos
* for various different writer configurations), deleting a writer will
* dispose all its related message.
* Wait for the subscriber to have stopped to be sure it received the
* message. Again, not normally necessary and not recommended to do
* this in a polling loop. */
std::cout << "=== [Publisher] Waiting for sample to be accepted." << std::endl;
while (writer.publication_matched_status().current_count() > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
catch (const dds::core::Exception& e) {
std::cerr << "=== [Publisher] Exception: " << e.what() << std::endl;
return EXIT_FAILURE;
}

std::cout << "=== [Publisher] Done." << std::endl;

return EXIT_SUCCESS;
}
105 changes: 105 additions & 0 deletions examples/helloworld_shm/readme.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
..
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

HelloWorld SHM
==========

Description
***********

The basic ddscxx HelloWorldShm example is used to illustrate the necessary steps to setup DCPS entities for using shared memory

Design
******

It consists of 2 units:

- ddscxxHelloworldPublisherShm: implements the publisher's main
- ddscxxHelloworldSubscriberShm: implements the subscriber's main

Scenario
********

The publisher sends a single HelloWorld sample. The sample contains the following field:

- a userID field (long type)

When it receives the sample, the subscriber displays the userID field.

Running the example
*******************

Configuration
--------------

Cyclone DDS needs to be configured to use the shared memory exchange

Below is an example of Cyclone DDS configuration file to enable shared memory exchange:

.. code-block:: xml

<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/iceoryx/etc/cyclonedds.xsd">
<Domain id="any">
<SharedMemory>
<Enable>true</Enable>
<SubQueueCapacity>256</SubQueueCapacity>
<SubHistoryRequest>16</SubHistoryRequest>
<PubHistoryCapacity>16</PubHistoryCapacity>
<LogLevel>info</LogLevel>
</SharedMemory>
</Domain>
</CycloneDDS>

The above example configuration can be saved as *cyclonedds.xml* and can be passed to Cyclone DDS through the environment variable CYCLONEDDS_URI as below

.. code-block:: bash

export CYCLONEDDS_URI=file://cyclonedds.xml

Run
--------------

It is recommended that you run the executables in separate terminals to avoid mixing the output.

- In the first terminal start the RouDi by running iox-roudi

.. code-block:: bash

~/iceoryx/build/iox-roudi

- In the second terminal start the subscriber by running ddscxxHelloWorldSubscriberShm

.. code-block:: bash

export CYCLONEDDS_URI=file://cyclonedds.xml
~/cyclonedds-cxx/build/bin/ddscxxHelloWorldSubscriberShm

- In the third terminal start the publisher by running ddscxxHelloWorldPublisherShm

.. code-block:: bash

export CYCLONEDDS_URI=file://cyclonedds.xml
~/cyclonedds-cxx/build/bin/ddscxxHelloWorldPublisherShm

After establishing a successful communication, the output looks something like below:

.. code-block:: bash

=== [Subscriber] Wait for message.
=== [Subscriber] Message received:
data : 1234
=== [Subscriber] Done.



103 changes: 103 additions & 0 deletions examples/helloworld_shm/subscriber_shm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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
*/
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <thread>

/* Include the C++ DDS API. */
#include "dds/dds.hpp"

/* Include data type and specific traits to be used with the C++ DDS API. */
#include "HelloWorldDataShm.hpp"

using namespace org::eclipse::cyclonedds;

int main() {
try {
std::cout << "=== [Subscriber] Create reader." << std::endl;

/* First, a domain participant is needed.
* Create one on the default domain. */
dds::domain::DomainParticipant participant(domain::default_id());

/* To subscribe to something, a topic is needed. */
dds::topic::Topic<HelloWorldDataShm::Msg> topic(participant, "HelloWorldData_Shm");

/* A reader also needs a subscriber. */
dds::sub::Subscriber subscriber(participant);

/* Set DataReader QoS
* SHM currently only supports reliable/best-effort, volatile and keep last QoS on the reader side
*/
dds::sub::qos::DataReaderQos qos;
qos << dds::core::policy::Reliability::BestEffort();
qos << dds::core::policy::Durability::Volatile();
qos << dds::core::policy::History::KeepLast(10U);

/* Now, the reader can be created to subscribe to a HelloWorld message. */
dds::sub::DataReader<HelloWorldDataShm::Msg> reader(subscriber, topic, qos);

/* Poll until a message has been read.
* It isn't really recommended to do this kind wait in a polling loop.
* It's done here just to illustrate the easiest way to get data.
* Please take a look at Listeners and WaitSets for much better
* solutions, albeit somewhat more elaborate ones. */
std::cout << "=== [Subscriber] Wait for message." << std::endl;
bool poll = true;
while (poll) {
/* For this example, the reader will return a set of messages (aka
* Samples). There are other ways of getting samples from reader.
* See the various read() and take() functions that are present. */
dds::sub::LoanedSamples<HelloWorldDataShm::Msg> samples;

/* Try taking samples from the reader. */
samples = reader.take();

/* Are samples read? */
if (samples.length() > 0) {
/* Use an iterator to run over the set of samples. */
dds::sub::LoanedSamples<HelloWorldDataShm::Msg>::const_iterator sample_iter;
for (sample_iter = samples.begin();
sample_iter < samples.end();
++sample_iter) {
/* Get the message and sample information. */
const HelloWorldDataShm::Msg& msg = sample_iter->data();
const dds::sub::SampleInfo& info = sample_iter->info();

/* Sometimes a sample is read, only to indicate a data
* state change (which can be found in the info). If
* that's the case, only the key value of the sample
* is set. The other data parts are not.
* Check if this sample has valid data. */
if (info.valid()) {
std::cout << "=== [Subscriber] Message received:" << std::endl;
std::cout << " data : " << msg.data() << std::endl;

/* Only 1 message is expected in this example. */
poll = false;
}
}
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
catch (const dds::core::Exception& e) {
std::cerr << "=== [Subscriber] Exception: " << e.what() << std::endl;
return EXIT_FAILURE;
}

std::cout << "=== [Subscriber] Done." << std::endl;

return EXIT_SUCCESS;
}
4 changes: 4 additions & 0 deletions src/ddscxx/include/dds/pub/detail/DataWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class dds::pub::detail::DataWriter : public ::org::eclipse::cyclonedds::pub::Any

void init(ObjectDelegate::weak_ref_type weak_ref);

T& loan_sample();

void return_loan(T& sample);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not overlap with @e-hndrks work on the loan interface?


void write_cdr(const org::eclipse::cyclonedds::topic::CDRBlob& sample);

void write_cdr(const org::eclipse::cyclonedds::topic::CDRBlob& sample, const dds::core::Time& timestamp);
Expand Down
Loading