Register singleton's destruction using std::atexit
[folly.git] / folly / Subprocess.h
index d739288a1c49b73aded1a4679d54009ed534c048..597bb57324b800ec2f66c0821cd853fa027918a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 /**
  * Subprocess library, modeled after Python's subprocess module
  * (http://docs.python.org/2/library/subprocess.html)
  * to complete, returning the exit status.
  *
  * A thread-safe [1] version of popen() (type="r", to read from the child):
- *    Subprocess proc(cmd, Subprocess::pipeStdout());
+ *    Subprocess proc(cmd, Subprocess::Options().pipeStdout());
  *    // read from proc.stdoutFd()
  *    proc.wait();
  *
  * A thread-safe [1] version of popen() (type="w", to write to the child):
- *    Subprocess proc(cmd, Subprocess::pipeStdin());
+ *    Subprocess proc(cmd, Subprocess::Options().pipeStdin());
  *    // write to proc.stdinFd()
  *    proc.wait();
  *
@@ -93,8 +92,9 @@
 
 #pragma once
 
-#include <sys/types.h>
 #include <signal.h>
+#include <sys/types.h>
+
 #if __APPLE__
 #include <sys/wait.h>
 #else
 #endif
 
 #include <exception>
-#include <vector>
 #include <string>
+#include <vector>
 
 #include <boost/container/flat_map.hpp>
 
 #include <folly/Range.h>
 #include <folly/gen/String.h>
 #include <folly/io/IOBufQueue.h>
+#include <folly/portability/SysResource.h>
 
 namespace folly {
 
@@ -125,7 +126,6 @@ namespace folly {
  */
 class Subprocess;
 class ProcessReturnCode {
-  friend class Subprocess;
  public:
   enum State {
     // Subprocess starts in the constructor, so this state designates only
@@ -133,12 +133,22 @@ class ProcessReturnCode {
     NOT_STARTED,
     RUNNING,
     EXITED,
-    KILLED
+    KILLED,
   };
 
+  static ProcessReturnCode makeNotStarted() {
+    return ProcessReturnCode(RV_NOT_STARTED);
+  }
+
+  static ProcessReturnCode makeRunning() {
+    return ProcessReturnCode(RV_RUNNING);
+  }
+
+  static ProcessReturnCode make(int status);
+
   // Default-initialized for convenience. Subprocess::returnCode() will
   // never produce this value.
-  ProcessReturnCode() : ProcessReturnCode(RV_NOT_STARTED) {}
+  ProcessReturnCode() : rawStatus_(RV_NOT_STARTED) {}
 
   // Trivially copyable
   ProcessReturnCode(const ProcessReturnCode& p) = default;
@@ -208,35 +218,34 @@ class ProcessReturnCode {
 /**
  * Base exception thrown by the Subprocess methods.
  */
-class SubprocessError : public std::exception {};
+class FOLLY_EXPORT SubprocessError : public std::runtime_error {
+ public:
+  using std::runtime_error::runtime_error;
+};
 
 /**
  * Exception thrown by *Checked methods of Subprocess.
  */
-class CalledProcessError : public SubprocessError {
+class FOLLY_EXPORT CalledProcessError : public SubprocessError {
  public:
   explicit CalledProcessError(ProcessReturnCode rc);
-  ~CalledProcessError() throw() = default;
-  const char* what() const throw() override { return what_.c_str(); }
+  ~CalledProcessError() throw() override = default;
   ProcessReturnCode returnCode() const { return returnCode_; }
  private:
   ProcessReturnCode returnCode_;
-  std::string what_;
 };
 
 /**
  * Exception thrown if the subprocess cannot be started.
  */
-class SubprocessSpawnError : public SubprocessError {
+class FOLLY_EXPORT SubprocessSpawnError : public SubprocessError {
  public:
   SubprocessSpawnError(const char* executable, int errCode, int errnoValue);
-  ~SubprocessSpawnError() throw() = default;
-  const char* what() const throw() override { return what_.c_str(); }
+  ~SubprocessSpawnError() throw() override = default;
   int errnoValue() const { return errnoValue_; }
 
  private:
   int errnoValue_;
-  std::string what_;
 };
 
 /**
@@ -352,7 +361,7 @@ class Subprocess {
 
     /**
      * Child will be made a process group leader when it starts. Upside: one
-     * can reliably all its kill non-daemonizing descendants.  Downside: the
+     * can reliably kill all its non-daemonizing descendants.  Downside: the
      * child will not receive Ctrl-C etc during interactive use.
      */
     Options& processGroupLeader() {
@@ -439,10 +448,6 @@ class Subprocess {
 #endif
   };
 
-  static Options pipeStdin() { return Options().stdinFd(PIPE); }
-  static Options pipeStdout() { return Options().stdoutFd(PIPE); }
-  static Options pipeStderr() { return Options().stderrFd(PIPE); }
-
   // Non-copiable, but movable
   Subprocess(const Subprocess&) = delete;
   Subprocess& operator=(const Subprocess&) = delete;
@@ -513,7 +518,7 @@ class Subprocess {
    * e.g. if you wait for the underlying process without going through this
    * Subprocess instance.
    */
-  ProcessReturnCode poll();
+  ProcessReturnCode poll(struct rusage* ru = nullptr);
 
   /**
    * Poll the child's status.  If the process is still running, return false.
@@ -816,9 +821,6 @@ class Subprocess {
   std::vector<ChildPipe> takeOwnershipOfPipes();
 
  private:
-  static const int RV_RUNNING = ProcessReturnCode::RV_RUNNING;
-  static const int RV_NOT_STARTED = ProcessReturnCode::RV_NOT_STARTED;
-
   // spawn() sets up a pipe to read errors from the child,
   // then calls spawnInternal() to do the bulk of the work.  Once
   // spawnInternal() returns it reads the error pipe to see if the child
@@ -854,7 +856,7 @@ class Subprocess {
   size_t findByChildFd(const int childFd) const;
 
   pid_t pid_{-1};
-  ProcessReturnCode returnCode_{RV_NOT_STARTED};
+  ProcessReturnCode returnCode_;
 
   /**
    * Represents a pipe between this process, and the child process (or its
@@ -885,4 +887,4 @@ class Subprocess {
   std::vector<Pipe> pipes_;
 };
 
-}  // namespace folly
+} // namespace folly