Use posix_spawn to run the pager
In low memory environments, "nix-env -qa" failed because the fork to run the pager hit the kernel's overcommit limits. Using posix_spawn gets around this. (Actually, you have to use posix_spawn with the undocumented POSIX_SPAWN_USEVFORK flag, otherwise it just uses fork/exec...)
This commit is contained in:
parent
d51eed833a
commit
d34d2b2bbf
3 changed files with 39 additions and 10 deletions
|
@ -15,6 +15,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -305,14 +306,35 @@ RunPager::RunPager()
|
||||||
Pipe toPager;
|
Pipe toPager;
|
||||||
toPager.create();
|
toPager.create();
|
||||||
|
|
||||||
pid = startProcess([&]() {
|
// FIXME: should do this in the child environment.
|
||||||
if (dup2(toPager.readSide, STDIN_FILENO) == -1)
|
if (!getenv("LESS"))
|
||||||
throw SysError("dupping stdin");
|
setenv("LESS", "FRSXMK", 1);
|
||||||
if (!getenv("LESS"))
|
|
||||||
setenv("LESS", "FRSXMK", 1);
|
/* Start the pager using posix_spawn. */
|
||||||
execl("/bin/sh", "sh", "-c", pager.c_str(), NULL);
|
pid_t pid_;
|
||||||
throw SysError(format("executing ‘%1%’") % pager);
|
const char * argv[] = { "sh", "-c", pager.c_str(), 0 };
|
||||||
});
|
|
||||||
|
posix_spawn_file_actions_t fileActions;
|
||||||
|
int err = posix_spawn_file_actions_init(&fileActions);
|
||||||
|
if (err) throw SysError(err, "creating POSIX file actions");
|
||||||
|
err = posix_spawn_file_actions_adddup2(&fileActions, toPager.readSide, STDIN_FILENO);
|
||||||
|
if (err) throw SysError(err, "adding to POSIX file actions");
|
||||||
|
|
||||||
|
posix_spawnattr_t spawnAttrs;
|
||||||
|
err = posix_spawnattr_init(&spawnAttrs);
|
||||||
|
if (err) throw SysError(err, "creating POSIX spawn attrs");
|
||||||
|
#ifdef POSIX_SPAWN_USEVFORK
|
||||||
|
err = posix_spawnattr_setflags(&spawnAttrs, POSIX_SPAWN_USEVFORK);
|
||||||
|
if (err) throw SysError(err, "setting POSIX spawn attr flag");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = posix_spawn(&pid_, "/bin/sh", &fileActions, &spawnAttrs, (char * const *) argv, environ);
|
||||||
|
|
||||||
|
posix_spawn_file_actions_destroy(&fileActions);
|
||||||
|
posix_spawnattr_destroy(&spawnAttrs);
|
||||||
|
|
||||||
|
if (err) throw SysError(err, format("running ‘%1%’") % pager);
|
||||||
|
pid = pid_;
|
||||||
|
|
||||||
if (dup2(toPager.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(toPager.writeSide, STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
|
|
|
@ -73,6 +73,7 @@ class SysError : public Error
|
||||||
public:
|
public:
|
||||||
int errNo;
|
int errNo;
|
||||||
SysError(const FormatOrString & fs);
|
SysError(const FormatOrString & fs);
|
||||||
|
SysError(int errNo, const FormatOrString & fs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,14 @@ BaseError & BaseError::addPrefix(const FormatOrString & fs)
|
||||||
|
|
||||||
|
|
||||||
SysError::SysError(const FormatOrString & fs)
|
SysError::SysError(const FormatOrString & fs)
|
||||||
: Error(format("%1%: %2%") % fs.s % strerror(errno))
|
: SysError(errno, fs)
|
||||||
, errNo(errno)
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SysError::SysError(int errNo, const FormatOrString & fs)
|
||||||
|
: Error(format("%1%: %2%") % fs.s % strerror(errNo))
|
||||||
|
, errNo(errNo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue