summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2022-05-10 22:33:52 +1000
committerMaxime Coste <mawww@kakoune.org>2022-05-10 22:36:13 +1000
commitae001a1f911181ec0ca752212e5ebaf5f57c4ad0 (patch)
treea26ccc953277ddb2e14545b1b6b7e57dc6fc1e59 /src
parent3882b0e21b7ff8d7a6ad9e8fb9961eaa104d1b18 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/file.cc18
1 files changed, 13 insertions, 5 deletions
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));
}
}