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 _try_acknowledge_jobs()
{ {
bool overall_progress = false; bool progress = false;
for (;;) { Node_queue requeued_nodes { };
if (!_stream.ready_to_ack())
break;
if (_active_nodes.empty()) _active_nodes.dequeue_all([&] (Node &node) {
break;
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 * If there is still another acknowledgement pending,
* re-check the 'ready_to_ack' condition for each * keep the node enqueud to process it in the next call of
* acknowledgement. * '_try_acknowledge_jobs'. This can happen if there is a
*/ * READ_READY acknowledgement in addition to the
if (node.acknowledgement_pending()) { * acknowledgement of an operation.
_stream.acknowledge_packet(node.dequeue_acknowledgement()); */
progress_in_iteration = true; if (node.active())
} requeued_nodes.enqueue(node);
});
/* _active_nodes = requeued_nodes;
* 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);
});
overall_progress |= progress_in_iteration; return progress;
if (!progress_in_iteration)
break;
}
return overall_progress;
} }
public: public: