vfs: process all acks in each iteration

This patch solves a corner case where one long-active job (e.g.,
read-ready request) stays at the beginning of the '_active_jobs' queue
without an ack. In this case, the '_try_acknowledge_jobs' method would
wrongly stop processing the subsequent acknowledgements. In practice,
this can lead to a delayed sending of acknowledgements until new I/O or
client requests occur. In particular, Vim in Sculpt's inspect window
sometimes did not immediately respond to key presses during tab
completion. Here, the read-ready request of the terminal prevented the
acknowledgement for read of directory entry from being delivered until
the next key was pressed.

Fixes #3873
This commit is contained in:
Norman Feske 2020-09-01 18:19:58 +02:00 committed by Christian Helmuth
parent 0605180a61
commit 17a6318ad6

View File

@ -261,46 +261,36 @@ class Vfs_server::Session_component : private Session_resources,
bool _try_acknowledge_jobs()
{
bool overall_progress = false;
bool progress = false;
for (;;) {
if (!_stream.ready_to_ack())
break;
Node_queue requeued_nodes { };
if (_active_nodes.empty())
break;
_active_nodes.dequeue_all([&] (Node &node) {
bool progress_in_iteration = false;
if (!_stream.ready_to_ack()) {
requeued_nodes.enqueue(node);
return;
}
_active_nodes.dequeue([&] (Node &node) {
if (node.acknowledgement_pending()) {
_stream.acknowledge_packet(node.dequeue_acknowledgement());
progress = true;
}
/*
* Deliver only one acknowledgement per iteration to
* re-check the 'ready_to_ack' condition for each
* acknowledgement.
*/
if (node.acknowledgement_pending()) {
_stream.acknowledge_packet(node.dequeue_acknowledgement());
progress_in_iteration = true;
}
/*
* If there is still another acknowledgement pending,
* keep the node enqueud to process it in the next call of
* '_try_acknowledge_jobs'. This can happen if there is a
* READ_READY acknowledgement in addition to the
* acknowledgement of an operation.
*/
if (node.active())
requeued_nodes.enqueue(node);
});
/*
* If there is still another acknowledgement pending, keep
* the node enqueud to process it in the next iteration.
* This can happen if there is a READ_READY acknowledgement
* in addition to the acknowledgement of an operation.
*/
if (node.active())
_active_nodes.enqueue(node);
});
_active_nodes = requeued_nodes;
overall_progress |= progress_in_iteration;
if (!progress_in_iteration)
break;
}
return overall_progress;
return progress;
}
public: