5.6.8. Zero Copy v2 Transport¶
The Zero Copy v2 transport enables RTI Connext Micro to share data samples between publishers and subscribers without serializing, transmitting, or deserializing the samples. For an overview of this feature and its utility, see Zero Copy Transfer.
This section outlines the basic steps required to enable the Zero Copy v2 transport in an application. All the example code shown below is taken from a Zero Copy v2 application that you can generate using rtiddsgen (see Generating Examples for more details).
5.6.8.1. Generate example and type support files¶
First, identify types that require Zero Copy transfer and annotate them with
the @transfer_mode(SHMEM_REF)
annotation. See the example IDL file
below:
@transfer_mode(SHMEM_REF)
struct HelloWorld {
@key long id;
long data[100];
};
rtiddsgen generates additional TypePlugin code when a type is annotated with
@transfer_mode(SHMEM_REF)
in the IDL files. This code allows a DataWriter
and a DataReader to communicate using a reference to the sample in shared
memory.
Note
Zero Copy v2 for Connext Micro only supports contiguous data types; this means that fixed-size arrays are supported, but sequences and strings are not.
Next, generate the type support and example files with the following command:
rtiddsgen -micro -example -exampleTemplate zcv2 -language C HelloWorld.idl
The generated files will appear in the same directory as the type file.
5.6.8.2. Initialize the Zero Copy v2 transport¶
Before the Zero Copy v2 transport can be used, it must be initialized. This must be done before creating a DomainParticipant and after registering the DataReader and DataWriter history plugins. The order is important because the Zero Copy v2 transport will perform actions on the history components during initialization.
The following example code from HelloWorldApplication.c demonstrates how to initialize the Zero Copy v2 transport with NDDS_Transport_ZeroCopy_initialize():
if (!NDDS_Transport_ZeroCopy_initialize(registry, NULL, NULL))
{
printf("failed to initialize zero copy\n");
/* handle error */
}
5.6.8.3. Register the Zero Copy v2 transport¶
The Zero Copy v2 transport needs a notification mechanism to notify DataReaders when a DataWriter has published data samples. RTI provies a default notification mechanism based on POSIX. You can also implement your own custom notification mechanism, but doing so is beyond the scope of this documentation; for more information, contact support@rti.com.
The default provided by RTI is a POSIX implementation of the notification mechanism. This mechanism is based on a monitor implemented in shared memory. In this documentation, we will assume that you are using the default implementation unless otherwise noted.
Once the Zero Copy transport is initialized, configure the notif
interface factory with the ZCOPY_NotifInterfaceFactoryProperty
property. This property has three fields you need to set:
max_samples_per_notif: The number of samples processesed per notification. By default this value is 1. Note that a high value may starve other threads from progressing.
user_intf: This is the implementation of your chosen notification mechanism. It is populated automatically if you are using the default implementation.
user_property: Any properties associated with your chosen notification mechanism. Connext Micro treats this as an opaque pointer.
When using the default mechanism provided by RTI, the user_property mentioned above is resolved to ZCOPY_NotifMechanismProperty. Both of these properties are required to configure the transport.
See the following example from HelloWorldApplication.c:
struct ZCOPY_NotifInterfaceFactoryProperty notif_prop;
struct ZCOPY_NotifMechanismProperty notif_mech_prop;
notif_mech_prop.intf_addr = 0;
notif_prop.user_property = ¬if_mech_prop;
notif_prop.max_samples_per_notif = 1;
For more information on these properties, see the Configuration section.
Finally, call ZCOPY_NotifMechanism_register()
(a utility function on the
default notification mechanism) to register the Zero Copy v2 transport with
the default notification mechanism. This makes it available for use. The
following example registers a notif
with the name NETIO_DEFAULT_NOTIF_NAME
:
if (!ZCOPY_NotifMechanism_register(registry, NETIO_DEFAULT_NOTIF_NAME, ¬if_prop))
{
printf("failed to register notif\n");
goto done;
}
5.6.8.4. Enable transports¶
With the specific notification mechanism registered, you can enable the Zero Copy and UDP transports for the DomainParticipant. Consider the following example code:
if (!DDS_StringSeq_set_maximum(&dp_qos.transports.enabled_transports, 2))
{
printf("failed to set transports.enabled_transports maximum\n");
goto done;
}
if (!DDS_StringSeq_set_length(&dp_qos.transports.enabled_transports, 2))
{
printf("failed to set transports.enabled_transports length\n");
goto done;
}
/* UDP and Notif are enabled*/
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports, 0) =
DDS_String_dup(NETIO_DEFAULT_NOTIF_NAME);
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports, 1) =
DDS_String_dup(NETIO_DEFAULT_UDP_NAME);
/* Discovery takes place over UDP */
DDS_StringSeq_set_maximum(&dp_qos.discovery.enabled_transports, 1);
DDS_StringSeq_set_length(&dp_qos.discovery.enabled_transports, 1);
*DDS_StringSeq_get_reference(&dp_qos.discovery.enabled_transports, 0) =
DDS_String_dup("_udp://");
/* User data uses Notif */
DDS_StringSeq_set_maximum(&dp_qos.user_traffic.enabled_transports, 1);
DDS_StringSeq_set_length(&dp_qos.user_traffic.enabled_transports, 1);
*DDS_StringSeq_get_reference(&dp_qos.user_traffic.enabled_transports, 0) =
DDS_String_dup("notif://");
Note
The UDP Transport or Shared Memory Transport (SHMEM) must be registered while using Zero Copy v2 transfer because DDS Discovery requires one of them in order to function (see Discovery for more details).
5.6.8.5. Sample management¶
When using the Zero Copy v2 transport, each DataWriter manages a pool of samples, and the application must obtain samples from this pool using get_loan(). We can see this in the following example:
hw_datawriter = HelloWorldDataWriter_narrow(datawriter);
retcode = HelloWorldDataWriter_get_loan(hw_datawriter, &sample);
if (retcode != DDS_RETCODE_OK)
{
printf("ERROR: Failed to loan sample\n");
}
retcode = HelloWorldDataWriter_write(hw_datawriter, sample, &DDS_HANDLE_NIL);
if (retcode != DDS_RETCODE_OK)
{
printf("ERROR: Failed to write to sample\n");
}
As seen above, the DataWriter must get a loan before each write call; it cannot write a loaned sample multiple times. The DataWriter does not need to explicitly return any loan to the pool, since this is managed by the middleware. However, if a loaned sample will not be written, it can be discarded with discard_loan().
Warning
It is not possible to write a sample that has not been obtained with get_loan().
Note
A Zero Copy-enabled DataWriter can also send samples using other transports (such as UDPv4) to non-Zero Copy DataReaders. When a DataWriter uses both the Zero Copy v2 transport and a transport which uses serialized data (such as UDP), the same sample is sent over all transports.
This may adversely affect performance, since the sample must be serialized for network transmission even if it is in shared memory. For best performance, you should consider an architecture where a DataWriter matches either with Zero Copy-enabled or non Zero Copy-enabled DataReaders, but not both.
On the DataReader side, Zero Copy v2 application code is identical to subscribing applications not using Zero Copy.
When a DataReader calls read() or take() and receives samples, it is being given samples that are loaned from the DataWriter’s pool. Thus, failing to return the loan when the sample is no longer needed will deplete the available samples in the pool, eventually causing calls to get_loan() to fail.
5.6.8.6. Configuration¶
Connext Micro Zero Copy v2 includes some properties unique to its functionality. The following properties are always required:
- 1
This property is only required if you choose to implement your own notification mechanism and not use the default implementation provided by RTI.
- 2
Resolves to ZCOPY_NotifMechanismProperty when using the default notification mechanism.
The following properties are required if you are using the default implementation of the notification mechanism for Zero Copy v2. These are essentially a default set of user-defined properties; if you are using your own notification mechanism, you can set your own user-defined properties as needed.
The following additional properties are only required if you are using your own notification mechanism for Zero Copy v2, not the default implementation.
5.6.8.7. Using multiple Zero Copy v2 transport instances¶
The platform-independent Zero Copy v2 transport supports multiple instances,
provided that the user-defined, platform-specific implementation of the
notif
interface implements a way to uniquely identify each instance.
In this case, each Zero Copy v2 transport instance should be registered with
uniquely different names and properties.
When multiple instances of the Zero Copy v2 transport exist, individual DataReaders and DataWriters can be configured to use a specific instance of the Zero Copy v2 transport. This configuration is done in the entity’s enabled_transports QoS configuration. For more information, see Transport Registration.