Figure 1. Zero-Copy with Multiple Messages and Buffers Example
#define N_BUFFERS 2
#define N_MSGS 2
struct onload_zc_iovec iovec[N_MSGS][N_BUFFERS];
struct onload_zc_mmsg mmsg[N_MSGS];
for( i = 0; i < N_MSGS; ++i ) {
rc = onload_zc_alloc_buffers(fd, iovec[i], N_BUFFERS,
ONLOAD_ZC_BUFFER_HDR_TCP);
assert(rc == 0);
/* TODO store data in iovec[i][j].iov_base,
* set iovec[i][j]iov_len */
mmsg[i]fd = fd; /* Could be different for each message */
mmsg[i].iov = iovec[i];
mmsg[i].msg.msghdr.msg_iovlen = N_BUFFERS;
}
rc = onload_zc_send(mmsg, N_MSGS, 0);
if( rc <= 0 ) {
/* Probably application bug */
return rc;
} else {
for( i = 0; i < N_MSGS; ++i ) {
if( i < rc ) {
/* mmsg[i] is set and we can use it */
if( mmsg[i] < 0) {
/* error sending this message - release buffers */
for( j = 0; j < N_BUFFERS; ++j )
onload_zc_release_buffers(fd, &iovec[i][j].buf, 1);
} else if( mmsg(i] < sum_over_j(iovec[i][j].iov_len) ) {
/* partial success */
/* TODO use mmsg[i] to determine which buffers in
* iovec[i] array are sent and which are still
* owned by application */
} else {
/* Whole message sent, buffers now owned by Onload */
}
} else {
/* mmsg[i] is not set, this message was not sent */
for( j = 0; j < N_BUFFERS; ++j )
onload_zc_release_buffers(fd, &iovec[i][j].buf, 1);
}
}
}
The example above demonstrates error code handling and contains some examples of bad practice where buffers are allocated and populated on the critical path.