guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

341/376: Use vfork


From: Ludovic Courtès
Subject: 341/376: Use vfork
Date: Wed, 28 Jan 2015 22:06:03 +0000

civodul pushed a commit to tag 1.8
in repository guix.

commit 0e8fc118b3d2d3bb6f9b0a918bf8ceb3927774cd
Author: Eelco Dolstra <address@hidden>
Date:   Wed Dec 10 16:35:42 2014 +0100

    Use vfork
---
 src/libutil/util.cc          |   31 +++++++++++++++++++++++--------
 src/libutil/util.hh          |   12 ++++++++++--
 src/nix-daemon/nix-daemon.cc |    7 ++++++-
 3 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 305e470..bdd114c 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -863,31 +863,46 @@ void killUser(uid_t uid)
 //////////////////////////////////////////////////////////////////////
 
 
-pid_t startProcess(std::function<void()> fun,
-    bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
+/* Wrapper around vfork to prevent the child process from clobbering
+   the caller's stack frame in the parent. */
+static pid_t doFork(bool allowVfork, std::function<void()> fun) 
__attribute__((noinline));
+static pid_t doFork(bool allowVfork, std::function<void()> fun)
 {
+#ifdef __linux__
+    pid_t pid = allowVfork ? vfork() : fork();
+#else
     pid_t pid = fork();
-    if (pid == -1) throw SysError("unable to fork");
+#endif
+    if (pid != 0) return pid;
+    fun();
+    abort();
+}
 
-    if (pid == 0) {
+
+pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
+{
+    auto wrapper = [&]() {
         _writeToStderr = 0;
         try {
 #if __linux__
-            if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
+            if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == 
-1)
                 throw SysError("setting death signal");
 #endif
             restoreAffinity();
             fun();
         } catch (std::exception & e) {
             try {
-                std::cerr << errorPrefix << e.what() << "\n";
+                std::cerr << options.errorPrefix << e.what() << "\n";
             } catch (...) { }
         } catch (...) { }
-        if (runExitHandlers)
+        if (options.runExitHandlers)
             exit(1);
         else
             _exit(1);
-    }
+    };
+
+    pid_t pid = doFork(options.allowVfork, wrapper);
+    if (pid == -1) throw SysError("unable to fork");
 
     return pid;
 }
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 628b8a0..09eb4d6 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -269,8 +269,16 @@ void killUser(uid_t uid);
 
 /* Fork a process that runs the given function, and return the child
    pid to the caller. */
-pid_t startProcess(std::function<void()> fun, bool dieWithParent = true,
-    const string & errorPrefix = "error: ", bool runExitHandlers = false);
+struct ProcessOptions
+{
+    string errorPrefix;
+    bool dieWithParent;
+    bool runExitHandlers;
+    bool allowVfork;
+    ProcessOptions() : errorPrefix("error: "), dieWithParent(true), 
runExitHandlers(false), allowVfork(true) { };
+};
+
+pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = 
ProcessOptions());
 
 
 /* Run a program and return its stdout in a string (i.e., like the
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 3864ab9..9a8f469 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -799,6 +799,11 @@ static void daemonLoop(char * * argv)
                 % (peer.uidKnown ? user : "<unknown>"));
 
             /* Fork a child to handle the connection. */
+            ProcessOptions options;
+            options.errorPrefix = "unexpected Nix daemon error: ";
+            options.dieWithParent = false;
+            options.runExitHandlers = true;
+            options.allowVfork = false;
             startProcess([&]() {
                 fdSocket.close();
 
@@ -821,7 +826,7 @@ static void daemonLoop(char * * argv)
                 processConnection(trusted);
 
                 exit(0);
-            }, false, "unexpected Nix daemon error: ", true);
+            }, options);
 
         } catch (Interrupted & e) {
             throw;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]