1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-02 21:51:50 +02:00

Merge pull request #12687 from Mic92/handle-eagain

libutil/file-descriptor: handle EAGAIN in read/write operations
This commit is contained in:
Jörg Thalheim 2025-03-19 22:46:05 +01:00 committed by GitHub
commit 12ad06c104
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -5,9 +5,27 @@
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
namespace nix {
namespace {
// This function is needed to handle non-blocking reads/writes. This is needed in the buildhook, because
// somehow the json logger file descriptor ends up beeing non-blocking and breaks remote-building.
// TODO: get rid of buildhook and remove this function again (https://github.com/NixOS/nix/issues/12688)
void pollFD(int fd, int events)
{
struct pollfd pfd;
pfd.fd = fd;
pfd.events = events;
int ret = poll(&pfd, 1, -1);
if (ret == -1) {
throw SysError("poll on file descriptor failed");
}
}
}
std::string readFile(int fd)
{
struct stat st;
@ -17,14 +35,18 @@ std::string readFile(int fd)
return drainFD(fd, true, st.st_size);
}
void readFull(int fd, char * buf, size_t count)
{
while (count) {
checkInterrupt();
ssize_t res = read(fd, buf, count);
if (res == -1) {
if (errno == EINTR) continue;
switch (errno) {
case EINTR: continue;
case EAGAIN:
pollFD(fd, POLLIN);
continue;
}
throw SysError("reading from file");
}
if (res == 0) throw EndOfFile("unexpected end-of-file");
@ -39,8 +61,15 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts)
while (!s.empty()) {
if (allowInterrupts) checkInterrupt();
ssize_t res = write(fd, s.data(), s.size());
if (res == -1 && errno != EINTR)
if (res == -1) {
switch (errno) {
case EINTR: continue;
case EAGAIN:
pollFD(fd, POLLOUT);
continue;
}
throw SysError("writing to file");
}
if (res > 0)
s.remove_prefix(res);
}
@ -56,8 +85,15 @@ std::string readLine(int fd, bool eofOk)
// FIXME: inefficient
ssize_t rd = read(fd, &ch, 1);
if (rd == -1) {
if (errno != EINTR)
switch (errno) {
case EINTR: continue;
case EAGAIN: {
pollFD(fd, POLLIN);
continue;
}
default:
throw SysError("reading a line");
}
} else if (rd == 0) {
if (eofOk)
return s;