From ae001a1f911181ec0ca752212e5ebaf5f57c4ad0 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 10 May 2022 22:33:52 +1000 Subject: [PATCH] Run EventManager whenever writing to a file descriptor would block This approach is not very elegant as it hooks into the event manager deep inside the call graph, but solves the exiting issue and is an okay stop gap solution until a better design comes up. Fixes #4605 --- src/file.cc | 18 +++++++++++++----- test/regression/4605-fifo-hang/cmd | 1 + test/regression/4605-fifo-hang/rc | 5 +++++ 3 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 test/regression/4605-fifo-hang/cmd create mode 100644 test/regression/4605-fifo-hang/rc diff --git a/src/file.cc b/src/file.cc index e5d330be..60210e35 100644 --- a/src/file.cc +++ b/src/file.cc @@ -5,6 +5,7 @@ #include "exception.hh" #include "flags.hh" #include "option_types.hh" +#include "event_manager.hh" #include "ranked_match.hh" #include "regex.hh" #include "string.hh" @@ -256,13 +257,20 @@ void write(int fd, StringView data) const char* ptr = data.data(); ssize_t count = (int)data.length(); + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + auto restore_flags = on_scope_end([&] { fcntl(fd, F_SETFL, flags); }); + while (count) { - ssize_t written = ::write(fd, ptr, count); - ptr += written; - count -= written; - - if (written == -1) + if (ssize_t written = ::write(fd, ptr, count); written != -1) + { + ptr += written; + count -= written; + } + else if (errno == EAGAIN and EventManager::has_instance()) + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, false); + else throw file_access_error(format("fd: {}", fd), strerror(errno)); } } diff --git a/test/regression/4605-fifo-hang/cmd b/test/regression/4605-fifo-hang/cmd new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/4605-fifo-hang/cmd @@ -0,0 +1 @@ + diff --git a/test/regression/4605-fifo-hang/rc b/test/regression/4605-fifo-hang/rc new file mode 100644 index 00000000..8829ee78 --- /dev/null +++ b/test/regression/4605-fifo-hang/rc @@ -0,0 +1,5 @@ +exec 5000oabcdefghi%yppppp +nop %sh{ + echo "write $kak_response_fifo" > "$kak_command_fifo" + strace -o /tmp/strace.log cat "$kak_response_fifo" +}