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 = &notif_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, &notif_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.

Table 7.2 Default User-Defined Properties for Zero Copy v2

Property Name

Description

Default

user_property.intf_addr

Sets the interface address for this instance. Should be unique for all instances in the system.

0

user_property.thread_prop.stack_size

Sets the stack size for the receive thread created for receiving notifications.

OSAPI_THREAD_PROPERTY_DEFAULT

user_property.thread_prop.priority

Sets the priority for the receive thread created for receiving notifications.

OSAPI_THREAD_PROPERTY_DEFAULT

user_property.thread_prop.options

Sets any thread options supported by the thread API implementation.

OSAPI_THREAD_PROPERTY_DEFAULT

user_property.max_receive_ports

Sets the maximum number of receive ports that can be opened. Used as part of the user_intf.bind function.

2

user_property.max_routes

Sets the maximum number of outgoing routes. Used as part of the user_intf.add_route function.

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.

Table 7.3 User Interface Properties for Zero Copy v2

Property Name

Type

Description

user_intf.create_instance

NETIO_Interface_T

Creates an instance of the notification mechanism interface with upstream as the owner.

user_intf.delete_instance

NETIO_Interface_T

Deletes an instance of the notification mechanism.

user_intf.get_route_table

RTI_BOOL

Instructs the notification mechanism interface netio_intf to return a sequence of address and netmask pairs this interface can send to.

user_intf.reserve_address

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to setup resources for listening to messages on the address src_addr and return a port_entry_out. The port_entry_out will be provided to a bind call.

user_intf.release_address

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to release resources for listening to messages on the address src_addr.

user_intf.resolve_address

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to determine if the address string address_string is a valid address and return the result in address_value.

user_intf.add_route

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to add a route from the source to the destination. The route_entry_out will be provided to you later when calling send.

user_intf.delete_route

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to remove a route from the source to the destination.

user_intf.bind

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to start listening for messages on the address specified by src_addr on the given port_entry.

user_intf.unbind

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to stop listening for messages on the address specified by src_addr.

user_intf.send

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to send a notification to the destination using the route_entry.

user_intf.notify_recv_port

RTI_BOOL

Instructs the notification mechanism interface specified by user_intf to notify the receive port specified by port_entry.

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.