7.7.8. Zero Copy v2 Transport¶
The Zero Copy v2 transport enables RTI Connext Cert to transmit data samples without copying them internally. For an overview of this feature, 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 the Zero Copy HelloWorld example on GitHub.
7.7.8.1. Generate type support files¶
First, identify types that require Zero Copy transfer and annotate them with
the @transfer_mode(SHMEM_REF)
annotation. See the HelloWorld.idl
file from the Zero Copy HelloWorld
example:
@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 Cert only supports contiguous data types; this means that fixed-size arrays are supported, but sequences and strings are not.
Next, generate type support files with the following command:
rtiddsgen -micro -language C HelloWorld.idl
The generated files will appear in the same directory as the type file.
7.7.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 of these operations 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:
if (!NDDS_Transport_ZeroCopy_initialize(registry, NULL, NULL))
{
printf("failed to initialize zero copy\n");
/* handle error */
}
7.7.8.3. Register the Zero Copy v2 transport¶
The Zero Copy v2 transport needs a notification mechanism to send notifications from DataWriters to DataReaders. You can use the reference notification mechanism provided by RTI, or implement your own.
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 reference implementation.
user_property: Any properties associated with your chosen notification mechanism. Connext Cert treats this as an opaque pointer.
Note
For reference, RTI provides a posix implementation of the notification mechanism. This mechanism is based on a monitor implemented in shared memory. This documentation assumes that you are using the reference implementation.
When using the notification 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
reference 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;
}
7.7.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("ERROR: Failed to set transports.enabled_transports maximum\n");
goto done;
}
if (!DDS_StringSeq_set_length(&dp_qos.transports.enabled_transports, 2))
{
printf("ERROR: Failed to set transports.enabled_transports length\n");
goto done;
}
/* UDP and Notification are enabled*/
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports, 0) =
DDS_String_dup("notif");
*DDS_StringSeq_get_reference(&dp_qos.transports.enabled_transports, 1) =
DDS_String_dup(MY_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 Notification Transport */
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 must be registered while using Zero Copy v2 transfer because it is used during DDS Discovery (see Discovery for more details).
7.7.8.5. Manage DDS samples¶
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.
7.7.8.6. Configuration¶
Connext Cert Zero Copy v2 introduces 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 reference implementation provided by RTI.
- 2
Resolves to
ZCOPY_NotifMechanismProperty
when using the reference notification mechanism.
The following properties are required if you are using the reference 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.
Property Name |
Description |
Default |
---|---|---|
|
Sets the interface address for this instance. Should be unique for all instances in the system. |
0 |
|
Sets the stack size for the receive thread created for receiving notifications. |
|
|
Sets the priority for the receive thread created for receiving notifications. |
|
|
Sets any thread options supported by the thread API implementation. |
|
|
Sets the maximum number of receive ports that can be opened. Used
as part of the |
2 |
|
Sets the maximum number of outgoing routes. Used as part of
the |
32 |
The following additional properties are only required if you are using your own notification mechanism for Zero Copy v2, NOT the reference implementation. Refer to the Safety Integration Manual for more information on these properties.
Property Name |
Type |
Description |
---|---|---|
|
NETIO_Interface_T |
Creates an instance of the notification mechanism interface with upstream as the owner. |
|
NETIO_Interface_T |
Deletes an instance of the notification mechanism. |
|
RTI_BOOL |
Instructs the notification mechanism interface |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
|
RTI_BOOL |
Instructs the notification mechanism interface specified by |
7.7.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 track different interface addresses.
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.