forked from lix-project/lix
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
|
@ -15,6 +15,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
@ -305,14 +306,35 @@ RunPager::RunPager()
|
|||
Pipe toPager;
|
||||
toPager.create();
|
||||
|
||||
pid = startProcess([&]() {
|
||||
if (dup2(toPager.readSide, STDIN_FILENO) == -1)
|
||||
throw SysError("dupping stdin");
|
||||
// FIXME: should do this in the child environment.
|
||||
if (!getenv("LESS"))
|
||||
setenv("LESS", "FRSXMK", 1);
|
||||
execl("/bin/sh", "sh", "-c", pager.c_str(), NULL);
|
||||
throw SysError(format("executing ‘%1%’") % pager);
|
||||
});
|
||||
|
||||
/* Start the pager using posix_spawn. */
|
||||
pid_t pid_;
|
||||
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)
|
||||
throw SysError("dupping stdout");
|
||||
|
|
|
@ -73,6 +73,7 @@ class SysError : public Error
|
|||
public:
|
||||
int errNo;
|
||||
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)
|
||||
: Error(format("%1%: %2%") % fs.s % strerror(errno))
|
||||
, errNo(errno)
|
||||
: SysError(errno, fs)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SysError::SysError(int errNo, const FormatOrString & fs)
|
||||
: Error(format("%1%: %2%") % fs.s % strerror(errNo))
|
||||
, errNo(errNo)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue