if (!PKT_FIELD(vsk, peer_waiting_write)) returnfalse;
#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL /* When the sender blocks, we take that as a sign that the sender is * faster than the receiver. To reduce the transmit rate of the sender, * we delay the sending of the read notification by decreasing the * write_notify_window. The notification is delayed until the number of * bytes used in the queue drops below the write_notify_window.
*/
/* For now we ignore the wait information and just see if the free * space exceeds the notify limit. Note that improving this function * to be more intelligent will not require a protocol change and will * retain compatibility between endpoints with mixed versions of this * function. * * The notify_limit is used to delay notifications in the case where * flow control is enabled. Below the test is expressed in terms of * free space in the queue: if free_space > ConsumeSize - * write_notify_window then notify An alternate way of expressing this * is to rewrite the expression to use the data ready in the receive * queue: if write_notify_window > bufferReady then notify as * free_space == ConsumeSize - bufferReady.
*/
retval = vmci_qpair_consume_free_space(vmci_trans(vsk)->qpair) >
notify_limit; #ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL if (retval) { /* * Once we notify the peer, we reset the detected flag so the * next wait will again cause a decrease in the window size.
*/
staticbool vmci_transport_notify_waiting_read(struct vsock_sock *vsk)
{ #ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) if (!PKT_FIELD(vsk, peer_waiting_read)) returnfalse;
/* For now we ignore the wait information and just see if there is any * data for our peer to read. Note that improving this function to be * more intelligent will not require a protocol change and will retain * compatibility between endpoints with mixed versions of this * function.
*/ return vmci_qpair_produce_buf_ready(vmci_trans(vsk)->qpair) > 0; #else returntrue; #endif
}
if (vmci_transport_notify_waiting_write(vsk)) { /* Notify the peer that we have read, retrying the send on * failure up to our maximum value. XXX For now we just log * the failure, but later we should schedule a work item to * handle the resend until it succeeds. That would require * keeping track of work items in the vsk and cleaning them up * upon socket close.
*/ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
!sent_read &&
retries < VMCI_TRANSPORT_MAX_DGRAM_RESENDS) {
err = vmci_transport_send_read(sk); if (err >= 0)
sent_read = true;
retries++;
}
if (retries >= VMCI_TRANSPORT_MAX_DGRAM_RESENDS)
pr_err("%p unable to send read notify to peer\n", sk); else #ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
PKT_FIELD(vsk, peer_waiting_write) = false; #endif
if (vsock_stream_has_data(vsk) >= target) {
*data_ready_now = true;
} else { /* We can't read right now because there is not enough data * in the queue. Ask for notifications when there is something * to read.
*/ if (sk->sk_state == TCP_ESTABLISHED) { if (!send_waiting_read(sk, 1)) return -1;
produce_q_free_space = vsock_stream_has_space(vsk); if (produce_q_free_space > 0) {
*space_avail_now = true; return 0;
} elseif (produce_q_free_space == 0) { /* This is a connected socket but we can't currently send data. * Notify the peer that we are waiting if the queue is full. We * only send a waiting write if the queue is full because * otherwise we end up in an infinite WAITING_WRITE, READ, * WAITING_WRITE, READ, etc. loop. Treat failing to send the * notification as a socket error, passing that back through * the mask.
*/ if (!send_waiting_write(sk, 1)) return -1;
if (PKT_FIELD(vsk, write_notify_min_window) < target + 1) {
PKT_FIELD(vsk, write_notify_min_window) = target + 1; if (PKT_FIELD(vsk, write_notify_window) <
PKT_FIELD(vsk, write_notify_min_window)) { /* If the current window is smaller than the new * minimal window size, we need to reevaluate whether * we need to notify the sender. If the number of ready * bytes are smaller than the new window, we need to * send a notification to the sender before we block.
*/
/* Notify our peer that we are waiting for data to read. */ if (!send_waiting_read(sk, target)) {
err = -EHOSTUNREACH; return err;
} #ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL if (data->notify_on_block) {
err = vmci_transport_send_read_notification(sk); if (err < 0) return err;
/* Now consume up to len bytes from the queue. Note that since we have * the socket locked we should copy at least ready bytes.
*/ #ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
vmci_qpair_get_consume_indexes(vmci_trans(vsk)->qpair,
&data->produce_tail,
&data->consume_head); #endif
if (data_read) { #ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) /* Detect a wrap-around to maintain queue generation. Note * that this is safe since we hold the socket lock across the * two queue pair operations.
*/ if (copied >=
vmci_trans(vsk)->consume_size - data->consume_head)
PKT_FIELD(vsk, consume_q_generation)++; #endif
err = vmci_transport_send_read_notification(sk); if (err < 0) return err;
staticint
vmci_transport_notify_pkt_send_pre_block( struct sock *sk, struct vmci_transport_send_notify_data *data)
{ /* Notify our peer that we are waiting for room to write. */ if (!send_waiting_write(sk, 1)) return -EHOSTUNREACH;
#ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) /* Detect a wrap-around to maintain queue generation. Note that this * is safe since we hold the socket lock across the two queue pair * operations.
*/ if (written >= vmci_trans(vsk)->produce_size - data->produce_tail)
PKT_FIELD(vsk, produce_q_generation)++;
#endif
if (vmci_transport_notify_waiting_read(vsk)) { /* Notify the peer that we have written, retrying the send on * failure up to our maximum value. See the XXX comment for the * corresponding piece of code in StreamRecvmsg() for potential * improvements.
*/ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
!sent_wrote &&
retries < VMCI_TRANSPORT_MAX_DGRAM_RESENDS) {
err = vmci_transport_send_wrote(sk); if (err >= 0)
sent_wrote = true;
retries++;
}
if (retries >= VMCI_TRANSPORT_MAX_DGRAM_RESENDS) {
pr_err("%p unable to send wrote notify to peer\n", sk); return err;
} else { #ifdefined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
PKT_FIELD(vsk, peer_waiting_read) = false; #endif
}
} return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.