namespace folly {
+ProcessReturnCode::ProcessReturnCode(ProcessReturnCode&& p) noexcept
+ : rawStatus_(p.rawStatus_) {
+ p.rawStatus_ = ProcessReturnCode::RV_NOT_STARTED;
+}
+
+ProcessReturnCode& ProcessReturnCode::operator=(ProcessReturnCode&& p)
+ noexcept {
+ rawStatus_ = p.rawStatus_;
+ p.rawStatus_ = ProcessReturnCode::RV_NOT_STARTED;
+ return *this;
+}
+
ProcessReturnCode::State ProcessReturnCode::state() const {
if (rawStatus_ == RV_NOT_STARTED) return NOT_STARTED;
if (rawStatus_ == RV_RUNNING) return RUNNING;
#include <boost/container/flat_map.hpp>
#include <boost/operators.hpp>
-#include <boost/noncopyable.hpp>
#include <folly/File.h>
#include <folly/FileUtil.h>
KILLED
};
+ // Trivially copyable
+ ProcessReturnCode(const ProcessReturnCode& p) = default;
+ ProcessReturnCode& operator=(const ProcessReturnCode& p) = default;
+ // Non-default move: In order for Subprocess to be movable, the "moved
+ // out" state must not be "running", or ~Subprocess() will abort.
+ ProcessReturnCode(ProcessReturnCode&& p) noexcept;
+ ProcessReturnCode& operator=(ProcessReturnCode&& p) noexcept;
+
/**
* Process state. One of:
* NOT_STARTED: process hasn't been started successfully
/**
* Subprocess.
*/
-class Subprocess : private boost::noncopyable {
+class Subprocess {
public:
static const int CLOSE = -1;
static const int PIPE = -2;
static Options pipeStdout() { return Options().stdout(PIPE); }
static Options pipeStderr() { return Options().stderr(PIPE); }
+ // Non-copiable, but movable
+ Subprocess(const Subprocess&) = delete;
+ Subprocess& operator=(const Subprocess&) = delete;
+ Subprocess(Subprocess&&) = default;
+ Subprocess& operator=(Subprocess&&) = default;
+
/**
* Create a subprocess from the given arguments. argv[0] must be listed.
* If not-null, executable must be the actual executable
EXPECT_THROW(proc.waitChecked(), CalledProcessError);
}
+TEST(SimpleSubprocessTest, MoveSubprocess) {
+ Subprocess old_proc(std::vector<std::string>{ "/bin/true" });
+ EXPECT_TRUE(old_proc.returnCode().running());
+ auto new_proc = std::move(old_proc);
+ EXPECT_TRUE(old_proc.returnCode().notStarted());
+ EXPECT_TRUE(new_proc.returnCode().running());
+ EXPECT_EQ(0, new_proc.wait().exitStatus());
+ // Now old_proc is destroyed, but we don't crash.
+}
+
#define EXPECT_SPAWN_ERROR(err, errMsg, cmd, ...) \
do { \
try { \