Use vfork() instead of fork() if available

Hopefully this reduces the chance of hitting ‘unable to fork: Cannot
allocate memory’ errors.  vfork() is used for everything except
starting builders.
This commit is contained in:
Eelco Dolstra 2012-11-09 18:00:33 +01:00
parent 48c19c4633
commit ea89df2b76
6 changed files with 51 additions and 22 deletions

View file

@ -115,6 +115,10 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
]) ])
# Check for vfork.
AC_FUNC_FORK()
# Check for lutimes, optionally used for changing the mtime of # Check for lutimes, optionally used for changing the mtime of
# symlinks. # symlinks.
AC_CHECK_FUNCS([lutimes]) AC_CHECK_FUNCS([lutimes])

View file

@ -665,7 +665,7 @@ HookInstance::HookInstance()
builderOut.create(); builderOut.create();
/* Fork the hook. */ /* Fork the hook. */
pid = fork(); pid = maybeVfork();
switch (pid) { switch (pid) {
case -1: case -1:
@ -2662,8 +2662,19 @@ void SubstitutionGoal::tryToRun()
if (pathExists(destPath)) if (pathExists(destPath))
deletePathWrapped(destPath); deletePathWrapped(destPath);
worker.store.setSubstituterEnv();
/* Fill in the arguments. */
Strings args;
args.push_back(baseNameOf(sub));
args.push_back("--substitute");
args.push_back(storePath);
args.push_back(destPath);
const char * * argArr = strings2CharPtrs(args);
/* Fork the substitute program. */ /* Fork the substitute program. */
pid = fork(); pid = maybeVfork();
switch (pid) { switch (pid) {
case -1: case -1:
@ -2677,18 +2688,6 @@ void SubstitutionGoal::tryToRun()
if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1) if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1)
throw SysError("cannot dup output pipe into stdout"); throw SysError("cannot dup output pipe into stdout");
/* Pass configuration options (including those overriden
with --option) to the substituter. */
setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
/* Fill in the arguments. */
Strings args;
args.push_back(baseNameOf(sub));
args.push_back("--substitute");
args.push_back(storePath);
args.push_back(destPath);
const char * * argArr = strings2CharPtrs(args);
execv(sub.c_str(), (char * *) argArr); execv(sub.c_str(), (char * *) argArr);
throw SysError(format("executing `%1%'") % sub); throw SysError(format("executing `%1%'") % sub);

View file

@ -202,6 +202,7 @@ void checkStoreNotSymlink()
LocalStore::LocalStore(bool reserveSpace) LocalStore::LocalStore(bool reserveSpace)
: didSetSubstituterEnv(false)
{ {
schemaPath = settings.nixDBPath + "/schema"; schemaPath = settings.nixDBPath + "/schema";
@ -943,6 +944,18 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
} }
void LocalStore::setSubstituterEnv()
{
if (didSetSubstituterEnv) return;
/* Pass configuration options (including those overriden with
--option) to substituters. */
setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
didSetSubstituterEnv = true;
}
void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run) void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter & run)
{ {
if (run.pid != -1) return; if (run.pid != -1) return;
@ -955,7 +968,9 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
fromPipe.create(); fromPipe.create();
errorPipe.create(); errorPipe.create();
run.pid = fork(); setSubstituterEnv();
run.pid = maybeVfork();
switch (run.pid) { switch (run.pid) {
@ -964,10 +979,6 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
case 0: /* child */ case 0: /* child */
try { try {
/* Pass configuration options (including those overriden
with --option) to the substituter. */
setenv("_NIX_OPTIONS", settings.pack().c_str(), 1);
if (dup2(toPipe.readSide, STDIN_FILENO) == -1) if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
throw SysError("dupping stdin"); throw SysError("dupping stdin");
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1) if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)

View file

@ -208,6 +208,8 @@ public:
void markContentsGood(const Path & path); void markContentsGood(const Path & path);
void setSubstituterEnv();
private: private:
Path schemaPath; Path schemaPath;
@ -238,6 +240,8 @@ private:
/* Cache for pathContentsGood(). */ /* Cache for pathContentsGood(). */
std::map<Path, bool> pathContentsGoodCache; std::map<Path, bool> pathContentsGoodCache;
bool didSetSubstituterEnv;
int getSchema(); int getSchema();
void openDB(bool create); void openDB(bool create);

View file

@ -760,8 +760,8 @@ Pid::operator pid_t()
void Pid::kill() void Pid::kill()
{ {
if (pid == -1) return; if (pid == -1 || pid == 0) return;
printMsg(lvlError, format("killing process %1%") % pid); printMsg(lvlError, format("killing process %1%") % pid);
/* Send the requested signal to the child. If it has its own /* Send the requested signal to the child. If it has its own
@ -883,7 +883,8 @@ string runProgram(Path program, bool searchPath, const Strings & args)
/* Fork. */ /* Fork. */
Pid pid; Pid pid;
pid = fork(); pid = maybeVfork();
switch (pid) { switch (pid) {
case -1: case -1:
@ -955,6 +956,13 @@ void setuidCleanup()
} }
#if HAVE_VFORK
pid_t (*maybeVfork)() = vfork;
#else
pid_t (*maybeVfork)() = fork;
#endif
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View file

@ -266,6 +266,9 @@ void closeOnExec(int fd);
sanitize file handles 0, 1 and 2. */ sanitize file handles 0, 1 and 2. */
void setuidCleanup(); void setuidCleanup();
/* Call vfork() if available, otherwise fork(). */
extern pid_t (*maybeVfork)();
/* User interruption. */ /* User interruption. */