Do not poll command sockets while shell command is running

Accepter is a wrapper around a socket watcher. It always uses
EventMode::Urgent, so it will be included in pselect(2) (via
EventManager::handle_next_events()) even while we are waiting for a
(blocking) shell command.  However we will not execute the command
received on this socket until after the shell command is done.

This is implemented with an early return:

	void handle_available_input(EventMode mode)
	{
	    while (not m_reader.ready() and fd_readable(sock))
	        m_reader.read_available(sock);

	    if (mode != EventMode::Normal or not m_reader.ready())
	        return;

so we read available data but don't close the socket.
When using this reproducer

	{
		sleep 1 && echo 'nop' | kak -p session
	} &
	kak -n -s session -e '%sh{sleep 7}'

the first "m_reader.read_available(sock);" will read "nop".  Then
"m_reader.ready()" is true but the socket is still readable. This
means that pselect(2) will return it every time, without blocking.

This means that the shell manager runs a hot loop between pselect(2)
and waitpid(2).

Fix this problem demoting command socket watchers from
EventMode::Urgent. This means that we won't pselect(2) it when handling
only urgent events. Control-C still works, I'm not sure why.

Alternative fix: we could read the commands but then disable the
socket. I tried this but it seems too complex.

Closes #5014
This commit is contained in:
Johannes Altmanninger 2023-11-04 17:23:09 +01:00
parent 6a39ac224b
commit b0ddbfc2df

View File

@ -776,7 +776,7 @@ class Server::Accepter
{ {
public: public:
Accepter(int socket) Accepter(int socket)
: m_socket_watcher(socket, FdEvents::Read, EventMode::Urgent, : m_socket_watcher(socket, FdEvents::Read, EventMode::Normal,
[this](FDWatcher&, FdEvents, EventMode mode) { [this](FDWatcher&, FdEvents, EventMode mode) {
handle_available_input(mode); handle_available_input(mode);
}) })