diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 7a414da6b..e35199b3d 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -126,7 +126,17 @@ void LocalStore::addTempRoot(const StorePath & path) auto socketPath = stateDir.get() + gcSocketPath; debug("connecting to '%s'", socketPath); state->fdRootsSocket = createUnixDomainSocket(); - nix::connect(state->fdRootsSocket.get(), socketPath); + try { + nix::connect(state->fdRootsSocket.get(), socketPath); + } catch (SysError & e) { + /* The garbage collector may have exited, so we need to + restart. */ + if (e.errNo == ECONNREFUSED) { + debug("GC socket connection refused"); + state->fdRootsSocket.close(); + goto restart; + } + } } try { @@ -523,6 +533,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) AutoCloseFD fdClient = accept(fdServer.get(), nullptr, nullptr); if (!fdClient) continue; + debug("GC roots server accepted new client"); + /* Process the connection in a separate thread. */ auto fdClient_ = fdClient.get(); std::thread clientThread([&, fdClient = std::move(fdClient)]() { @@ -535,6 +547,12 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) } }); + /* On macOS, accepted sockets inherit the + non-blocking flag from the server socket, so + explicitly make it blocking. */ + if (fcntl(fdServer.get(), F_SETFL, fcntl(fdServer.get(), F_GETFL) & ~O_NONBLOCK) == -1) + abort(); + while (true) { try { auto path = readLine(fdClient.get()); @@ -559,7 +577,10 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) } else printError("received garbage instead of a root from client"); writeFull(fdClient.get(), "1", false); - } catch (Error &) { break; } + } catch (Error & e) { + debug("reading GC root from client: %s", e.msg()); + break; + } } }); diff --git a/tests/gc-non-blocking.sh b/tests/gc-non-blocking.sh index 8b21c6f1c..0d781485d 100644 --- a/tests/gc-non-blocking.sh +++ b/tests/gc-non-blocking.sh @@ -19,7 +19,7 @@ pid=$! sleep 2 -outPath=$(nix-build -o "$TEST_ROOT/result" -E " +outPath=$(nix-build --max-silent-time 60 -o "$TEST_ROOT/result" -E " with import ./config.nix; mkDerivation { name = \"non-blocking\";