- HandlerMinelayerData: BUILD_RTI Guards für RTI-Abhängigkeiten - svcTabCommon: Export-Header-Fix via Fallback-Target - TrainingAreaBase: Stub-Header für BUILD_RTI=OFF - ddsfts: Include-Pfad und Dependency-Fixes - BUILD_RTI=OFF Compilation vollständig unterstützt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Entire-Checkpoint: 01M0JNZA586SACX1PRZ2DJAE5S
474 lines
17 KiB
C
474 lines
17 KiB
C
/*
|
|
* (c) Copyright, Real-Time Innovations, 2010-2024.
|
|
* All rights reserved.
|
|
*
|
|
* No duplications, whole or partial, manual or electronic, may be made
|
|
* without express written permission. Any such copies, or
|
|
* revisions thereof, must display this notice unaltered.
|
|
* This code contains trade secrets of Real-Time Innovations, Inc.
|
|
*/
|
|
|
|
#ifndef metp_dds_h
|
|
#define metp_dds_h
|
|
|
|
#include "metp/metp_dll.h"
|
|
#include "ndds/ndds_c.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*e \defgroup METPModuleIDL rtiddsgen
|
|
\ingroup RTI
|
|
|
|
ZCSHMEM requires <b>rtiddsgen</b> to generate additional code to handle
|
|
multiple encapsulations. To enable the additional support, annotate types
|
|
that require zero copy over shared memory support with
|
|
\@transfer_mode(SHMEM_REF). For example:
|
|
<p>
|
|
\verbatim
|
|
@transfer_mode(SHMEM_REF)
|
|
struct Foo {
|
|
long id;
|
|
long data[10000];
|
|
};
|
|
\endverbatim
|
|
|
|
If the annotation is used on an unsupported IDL type
|
|
(such as a sequence) as a member, an error indicating unsupported type
|
|
will be observed during code generation.
|
|
\n\n
|
|
@section Supported IDL Types
|
|
<table>
|
|
<tr><th>IDL Construct</th>
|
|
<th>Support</th>
|
|
</tr>
|
|
<tr><th>Modules</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Interfaces</th>
|
|
<td valign="top">Ignored</td>
|
|
</tr>
|
|
<tr><th>Constants</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Basic Data Types</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Enums</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>String Types</th>
|
|
<td valign="top">Not Supported</td>
|
|
</tr>
|
|
<tr><th>Wide String Types</th>
|
|
<td valign="top">Not Supported</td>
|
|
</tr>
|
|
<tr><th>Struct Types</th>
|
|
<td valign="top">Supported.
|
|
Inline nested structures, such as the following example, are not supported.
|
|
\verbatim
|
|
struct Outer {
|
|
short outer_short;
|
|
|
|
struct Inner {
|
|
char inner_char;
|
|
short inner_short;
|
|
} outer_nested_inner;
|
|
};
|
|
\endverbatim
|
|
</td>
|
|
</tr>
|
|
<tr><th>Fixed Types</th>
|
|
<td valign="top">Ignored</td>
|
|
</tr>
|
|
<tr><th>Union Types</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Sequence Types</th>
|
|
<td valign="top">Not Supported.
|
|
</td>
|
|
</tr>
|
|
<tr><th>Array Types</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Typedefs</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
<tr><th>Any</th>
|
|
<td valign="top">Not Supported. rtiddsgen does not ignore them. Do not use
|
|
this construct in the IDL file.</td>
|
|
</tr>
|
|
<tr><th>Value Types</th>
|
|
<td valign="top">Ignored</td>
|
|
</tr>
|
|
<tr><th>Exception Types</th>
|
|
<td valign="top">Ignored</td>
|
|
</tr>
|
|
<tr><th>Type Code</th>
|
|
<td valign="top">Supported</td>
|
|
</tr>
|
|
</table>
|
|
*/
|
|
|
|
/*e \defgroup METPModuleAPI ZCSHMEM C and C++ APIs
|
|
\ingroup RTI
|
|
*/
|
|
|
|
/*e \defgroup METPModuleAPIC ZCSHMEM C API
|
|
\ingroup METPModuleAPI
|
|
*/
|
|
#ifdef DOXYGEN_DOCUMENTATION_ONLY
|
|
/*e \ingroup METPModuleAPIC
|
|
\brief Returns a pointer to a sample of IDL type, Foo. The space allocated to
|
|
this sample is the maximum size of the IDL type mapped to C.\n\n
|
|
The following is a description of the different possible states of a sample:
|
|
free, allocated, in use, and removed.\n\n
|
|
A sample that has never been allocated is "free". create_data() takes a
|
|
"free" or "removed" sample and makes it "allocated". write() takes an
|
|
"allocated" or "removed" sample and puts it "in use". An "in use" sample
|
|
becomes "removed" when DDS removes it from the writer queue. "Removed"
|
|
samples are made "free" when the DDS domain participant is deleted.\n\n
|
|
The recommended approach is to create_data, write, create_data, write, etc.
|
|
|
|
@param self \st_in. Pointer to self. Must not be NULL.
|
|
@param initialize \st_in. Controls initialization of the sample when it is
|
|
allocated. If \p initialize is DDS_BOOLEAN_TRUE, a
|
|
sample will be initialized to zero. If \p initialize
|
|
is DDS_BOOLEAN_FALSE, a sample with undefined
|
|
contents is returned.
|
|
|
|
@return Pointer to a sample of type Foo if space is available, NULL otherwise.
|
|
Returns NULL only if writer_sample_allocation_settings.max_count samples are
|
|
allocated or in use. writer_sample_allocation_settings is available in
|
|
shmem_ref_transfer_mode_settings of DataWriter TypeSupportQosPolicy.
|
|
The pointer returned is aligned to 8-byte boundary. It is guaranteed that the
|
|
distance between any two pointers returned by FooDataWriter_create_data(..)
|
|
is at least the maximum size of the IDL type mapped to C.\n\n
|
|
When zero copy data over shared memory transport is enabled, RTI DDS will
|
|
allocate shared memory based on the standard DDS_ResourceLimitsQosPolicy for the
|
|
DataWriter:
|
|
-# DDS_ResourceLimitsQosPolicy.initial_samples. The initial amount of bytes
|
|
in shared memory allocated by a DataWriter is at least initial_samples * the
|
|
maximum size of the IDL type mapped to C.
|
|
-# DDS_ResourceLimitsQosPolicy.max_samples. The maximum number of bytes
|
|
allocated in shared memory by a DataWriter is at least (max_samples +
|
|
max_samples_reserve) * the maximum size of the IDL type mapped to C.
|
|
-# It is recommended to set initial_samples = max_samples to minimize the
|
|
number of shared memory segments that are created.
|
|
-# When the resource-limits are exhausted, no additional samples can be
|
|
allocated.
|
|
-# If the ResourceLimitsQosPolicy specified on the DataWriter exceeds
|
|
available OS system resources, the application may run out of shared memory
|
|
space for samples.
|
|
-# If the ResourceLimitsQosPolicy specified on the DataWriter exceeds
|
|
available OS system resources, FooDataWriter_create_data(..) returns NULL.
|
|
|
|
*/
|
|
void *FooDataWriter_create_data(DDS_DataWriter *self, DDS_Boolean initialize);
|
|
|
|
/*e \ingroup METPModuleAPIC
|
|
\brief Called when a sample is no longer in use and is removed (see
|
|
definitions of "in use" and "removed" in the documentation for
|
|
FooDataWriter_create_data) and when the DDS_DATA_WRITER_SAMPLE_REMOVED_STATUS
|
|
bit is set on the FooDataWriterListener mask. Writing a sample already "in
|
|
use" will return this error: METPMemPool_getBufferState:!legal state
|
|
@param listener_data \st_in Data associated with the listener when the
|
|
listener is set
|
|
@param writer \st_out. Locally created DDS_DataWriter that triggers the
|
|
listener callback.
|
|
@param cookie \st_out. Contains the absolute address of the sample no longer
|
|
in use. You can do the following to get the address:\n
|
|
\verbatim
|
|
void *location = NULL;
|
|
location = *(void**)DDS_OctetSeq_get_contiguous_buffer(&cookie.value);
|
|
printf("on_sample_removed. location = %p\n", location);
|
|
\endverbatim
|
|
*/
|
|
void FooDataWriterListener_on_sample_removed(
|
|
void *listener_data,
|
|
DDS_DataWriter *writer,
|
|
const struct DDS_Cookie_t *cookie);
|
|
|
|
/*e \defgroup METPModuleAPICPP ZCSHMEM C++ API
|
|
\ingroup METPModuleAPI
|
|
*/
|
|
/*e \ingroup METPModuleAPICPP
|
|
\brief Returns a pointer to a sample of the calling entity's data type. The
|
|
space allocated to this sample is the maximum size of the IDL type mapped to
|
|
C++.\n\n
|
|
The following is a description of the different possible states of a sample:
|
|
free, allocated, in use, and removed.\n\n
|
|
A sample that has never been allocated is "free". create_data() takes a
|
|
"free" or "removed" sample and makes it "allocated". write() takes an
|
|
"allocated" or "removed" sample and puts it "in use". An "in use" sample
|
|
becomes "removed" when DDS removes it from the writer queue. "Removed"
|
|
samples are made "free" when the DDS domain participant is deleted.\n\n
|
|
If you have more than one writer in your application, the recommended
|
|
approach is to create_data, write, create_data, write, etc.
|
|
If writer 1 calls create_data, write, waits for on_sample_removed, and then
|
|
writer 2 calls create_data, writer 2 could get the "removed" sample of writer
|
|
1. At this point, both writers are working with the same sample, so then when
|
|
writer 1 makes an update to the sample, writer 2 will unintentionally get
|
|
that update, causing confusion. However, if writer 1 calls create_data before
|
|
making the update, it will get a fresh sample different from the one that
|
|
writer 2 has, avoiding confusion.
|
|
|
|
@param self \st_in. Pointer to self. Must not be NULL.
|
|
@param initialize \st_in. Controls initialization of the sample when it is
|
|
allocated. If \p initialize is DDS_BOOLEAN_TRUE, a
|
|
sample will be initialized to zero. If \p initialize
|
|
is DDS_BOOLEAN_FALSE, a sample with undefined
|
|
contents is returned.
|
|
|
|
@return Pointer to a sample of type Foo if space is available, NULL
|
|
otherwise. Returns NULL only if (the value of the property
|
|
dds.data_writer.type_plugin.max_samples_reserve + the value of the QoS
|
|
datawriter_qos.resource_limits.max_samples) samples are allocated or in use.
|
|
The pointer returned is guaranteed to be aligned with the largest CPU
|
|
alignment requirement for any type on a specific platform. On the Cell
|
|
platform, the pointer will be aligned on a 128 byte boundary per IBM
|
|
performance recommendations. It is guaranteed that the distance between any
|
|
two pointers returned by FooDataWriter_create_data(..) is at least the
|
|
maximum size of the IDL type mapped to C++.\n\n
|
|
When zero copy data over shared memory transport is enabled, RTI DDS will
|
|
allocate shared memory based on the standard DDS_ResourceLimitsQosPolicy for the
|
|
DataWriter:
|
|
-# DDS_ResourceLimitsQosPolicy.initial_samples. The initial amount of bytes
|
|
in shared memory allocated by a DataWriter is at least initial_samples * the
|
|
maximum size of the IDL type mapped to C++.
|
|
-# DDS_ResourceLimitsQosPolicy.max_samples. The maximum number of bytes
|
|
allocated in shared memory by a DataWriter is at least (max_samples +
|
|
max_samples_reserve) * the maximum size of the IDL type mapped to C++.
|
|
-# When the resource-limits are exhausted, no additional samples can be
|
|
allocated.
|
|
-# If the ResourceLimitsQosPolicy specified on the DataWriter exceeds
|
|
available OS system resources, the application may run out of shared memory
|
|
space for samples.
|
|
-# If the ResourceLimitsQosPolicy specified on the DataWriter exceeds
|
|
available OS system resources, FooDataWriter_create_data(..) returns NULL.
|
|
*/
|
|
void *FooDataWriter_create_data(DDSDataWriter *self, DDS_Boolean initialize);
|
|
|
|
/*e \ingroup METPModuleAPICPP
|
|
\brief Called when a sample is no longer in use and is removed (see
|
|
definitions of "in use" and "removed" in the documentation for
|
|
FooDataWriter_create_data) and when the DDS_DATA_WRITER_SAMPLE_REMOVED_STATUS
|
|
bit is set on the FooDataWriterListener mask. Writing a sample already "in
|
|
use" will return this error: METPMemPool_getBufferState:!legal state
|
|
@param writer \st_out. Locally created DDS_DataWriter that triggers the
|
|
listener callback.
|
|
@param cookie \st_out. Contains the absolute address of the sample no longer
|
|
in use. You can do the following to get the address:\n
|
|
\verbatim
|
|
void *location = NULL;
|
|
location = *(void**)DDS_OctetSeq_get_contiguous_buffer(&cookie.value);
|
|
printf("on_sample_removed. location = %p\n", location);
|
|
\endverbatim
|
|
*/
|
|
virtual void FooDataWriterListener_on_sample_removed(
|
|
DDSDataWriter *writer,
|
|
const struct DDS_Cookie_t& cookie);
|
|
#endif
|
|
|
|
|
|
/*e \defgroup METPModuleExample Examples
|
|
\ingroup RTI
|
|
|
|
ZCSHMEM comes with example applications and QoS profiles, which can be found
|
|
in the following locations:
|
|
\verbatim
|
|
$NDDSHOME/example/C/helloWorldMETP - Example HelloWorld in C
|
|
$NDDSHOME/example/CPP/helloWorldMETP - Example HelloWorld in C++
|
|
$NDDSHOME/example/CPP/performance/latencyMETP - Example latency test in
|
|
C++ $NDDSHOME/example/CPP/performance/throughputMETP - Example throughput
|
|
test in C++ \endverbatim <b> Running the Examples </b> <p> To build the
|
|
applications, use the provided makefiles. Please make sure that NDDSHOME is
|
|
set. For example, to compile HelloWorld: \verbatim declare -x NDDSHOME=<path>
|
|
make -f makefile_HelloWorld_x64Linux2.6gcc4.5.1
|
|
\endverbatim
|
|
|
|
After running make, you can find the executables in:
|
|
\verbatim
|
|
./objs/x64Linux2.6gcc4.5.1/HelloWorld_publisher
|
|
./objs/x64Linux2.6gcc4.5.1/HelloWorld_subscriber
|
|
\endverbatim
|
|
All executables have a help option (not all applications support all
|
|
options):
|
|
\verbatim
|
|
./objs/x64Linux2.6gcc4.5.1/HelloWorld_publisher -h
|
|
|
|
-sleep <ms> - Sleep between each write call in ms. Default=1000
|
|
-domain <id> - Domain to join. Default=0
|
|
-count <count> - Number of samples to send. 0 = infinite (Default)
|
|
-profile <name> - Name of QoS profile to use
|
|
-hello - Publish HelloWorld sample
|
|
-10mb - Publish 10MB sample
|
|
-50mb - Publish 50MB sample
|
|
-100mb - Publish 100MB sample
|
|
-v - Print non-error messages
|
|
\endverbatim
|
|
<p>
|
|
All the examples follow the general design described below. It is assumed that
|
|
you are familiar with the different \ndds read and take APIs, as well as loan
|
|
and return semantics. <p> All the QoS are written using the XML profile syntax.
|
|
The following example forms the basis for all examples. This example uses the
|
|
Multi-Encapsulation Type Support (METP) to publish and subscribe to an IDL type
|
|
called MyType.
|
|
|
|
<b> IDL </b>
|
|
<p>
|
|
ZCSHMEM requires additonal code to be generated. Use rtiddsgen's -metp option
|
|
to enable ZCSHMEM functionality.
|
|
|
|
\verbatim
|
|
|
|
MyType.idl
|
|
|
|
struct MyType {
|
|
long x;
|
|
long y;
|
|
octet data[120];
|
|
};
|
|
|
|
rtiddsgen -language C -metp MyType.idl
|
|
|
|
\endverbatim
|
|
|
|
<b> DataWriterQos </b>
|
|
|
|
Enable ZCSHMEM only for DataWriters that communicate using the \ndds zero-copy
|
|
over shared memory transport.
|
|
|
|
\verbatim
|
|
<property>
|
|
<value>
|
|
<element>
|
|
<name>dds.data_writer.type_plugin.disable_zcshmem</name>
|
|
<value>true</value>
|
|
</element>
|
|
</value>
|
|
</property>
|
|
\endverbatim
|
|
|
|
<b> DataReaderQos </b>
|
|
|
|
Enable ZCSHMEM only for DataReaders that communicate using the \ndds zero-copy
|
|
over shared memory transport.
|
|
|
|
\verbatim
|
|
<property>
|
|
<value>
|
|
<element>
|
|
<name>dds.data_reader.type_plugin.disable_zcshmem</name>
|
|
<value>true</value>
|
|
</element>
|
|
</value>
|
|
</property>
|
|
\endverbatim
|
|
|
|
<b> Publishing Data </b>
|
|
|
|
\verbatim
|
|
|
|
MyType *sample;
|
|
MyTypeDataWriter *writer;
|
|
|
|
Create a DDS DomainParticipant, Publisher, and DataWriter and register MyType
|
|
as normal.
|
|
|
|
while (data_to_send) {
|
|
sample = MyTypeDataWriter_create_data(writer, DDS_BOOLEAN_TRUE);
|
|
if (sample == NULL) [
|
|
continue;
|
|
}
|
|
sample-> = ....;
|
|
MyTypeDataWriter_write(sample,....);
|
|
}
|
|
\endverbatim
|
|
|
|
<b> Subscribing to Data, Zero-Copy </b>
|
|
|
|
\verbatim
|
|
MyTypeDataReader *reader;
|
|
MyTypeSeq data_seq = = DDS_SEQUENCE_INITIALIZER;
|
|
DDS_SampleInfoSeq info_seg = DDS_SEQUENCE_INITIALIZER;
|
|
DDS_ReturnCode_t retcode;
|
|
|
|
Create a DDS DomainParticipant, Subscriber, and DataReader and register MyType
|
|
as normal.
|
|
|
|
while (data_to_receive) {
|
|
retcode = MyTypeDataReader_read/take(reader,&data_seq,&info_seq,.....);
|
|
if (retcode == DDS_RETCODE_OK) {
|
|
... process data ...
|
|
MyTypeDataReader_return_loan(reader,&data_seq,....);
|
|
}
|
|
}
|
|
\endverbatim
|
|
|
|
<b> Subscribing to Data, Copy </b>
|
|
|
|
\verbatim
|
|
MyType *sample;
|
|
MyTypeDataReader *reader;
|
|
MyTypeSeq data_seq = = DDS_SEQUENCE_INITIALIZER;
|
|
DDS_SampleInfoSeq info_seg = DDS_SEQUENCE_INITIALIZER;
|
|
DDS_ReturnCode_t retcode;
|
|
|
|
Create a DDS DomainParticipant, Subscriber, and DataReader and register MyType
|
|
as normal.
|
|
|
|
sample = MyTypeDataReader_create_data(reader, DDS_BOOLEAN_TRUE);
|
|
if (sample == NULL) {
|
|
... error ...
|
|
}
|
|
|
|
while (data_to_receive) {
|
|
retcode = MyTypeDataReader_read/take_next(reader,sample);
|
|
if (retcode == DDS_RETCODE_OK) {
|
|
... process ...
|
|
}
|
|
}
|
|
\endverbatim
|
|
*/
|
|
|
|
/*i \ingroup METPModuleAPI
|
|
*/
|
|
extern METPDllExport DDS_ReturnCode_t DDS_DataWriter_create_metp_data(
|
|
DDS_DataWriter *self,
|
|
void **sample,
|
|
DDS_Boolean *initialize_data);
|
|
|
|
/*i \ingroup METPModuleAPI
|
|
*/
|
|
extern METPDllExport DDS_ReturnCode_t
|
|
DDS_DataWriter_delete_metp_data(DDS_DataWriter *self, void *sample);
|
|
|
|
/*i \ingroup METPModuleAPI
|
|
*/
|
|
extern METPDllExport DDS_Boolean
|
|
DDS_DataWriter_is_metp_writer(DDS_DataWriter *self);
|
|
|
|
/*i \ingroup METPModuleAPI
|
|
*/
|
|
extern METPDllExport DDS_ReturnCode_t DDS_DataWriter_write_metp_data(
|
|
DDS_DataWriter *self,
|
|
const void *instance_data,
|
|
const DDS_InstanceHandle_t *handle,
|
|
struct DDS_WriteParams_t *w_params);
|
|
|
|
/*i \ingroup METPModuleAPI
|
|
*/
|
|
extern METPDllExport DDS_ReturnCode_t DDS_DataReader_is_metp_data_consistent(
|
|
DDS_DataReader *self,
|
|
DDS_Boolean *is_consistent,
|
|
const void *sample,
|
|
const struct DDS_SampleInfo *sample_info);
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* metp_dds_h */
|