From: Alexey Spiridonov Date: Tue, 19 May 2015 23:36:35 +0000 (-0700) Subject: Make Subprocess movable X-Git-Tag: v0.39.0~3 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=0e7cb3feec43284e953bb3c555802a076df78085;p=folly.git Make Subprocess movable Summary: Subprocess doesn't have any non-movable members, and its implementation does not take addresses of the object, so I think it's safe. Move makes a bunch of code cleaner (you no longer have to wrap it in `std::unique_ptr` with associated clumsiness). https://phabricator.fb.com/diffusion/FBCODE/browse/master/folly/Subprocess.h Test Plan: - unit test - Searched for `this` in `Subprocess.{h,cpp}`. - Inspected member variables: `pid_`, `returnCode_`, `pipes_` - contbuild Reviewed By: davejwatson@fb.com Subscribers: folly-diffs@, yfeldblum, chalfant FB internal diff: D2079167 Signature: t1:2079167:1432048688:26f96e29310298f47a9a9a7abef22dc863f68942 --- diff --git a/folly/Subprocess.cpp b/folly/Subprocess.cpp index 17e997e6..04866e1d 100644 --- a/folly/Subprocess.cpp +++ b/folly/Subprocess.cpp @@ -50,6 +50,18 @@ constexpr int kChildFailure = 126; 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; diff --git a/folly/Subprocess.h b/folly/Subprocess.h index cd6afa13..da2b5602 100644 --- a/folly/Subprocess.h +++ b/folly/Subprocess.h @@ -107,7 +107,6 @@ #include #include -#include #include #include @@ -133,6 +132,14 @@ class ProcessReturnCode { 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 @@ -227,7 +234,7 @@ class SubprocessSpawnError : public SubprocessError { /** * Subprocess. */ -class Subprocess : private boost::noncopyable { +class Subprocess { public: static const int CLOSE = -1; static const int PIPE = -2; @@ -349,6 +356,12 @@ class Subprocess : private boost::noncopyable { 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 diff --git a/folly/test/SubprocessTest.cpp b/folly/test/SubprocessTest.cpp index 0137bed2..489e8550 100644 --- a/folly/test/SubprocessTest.cpp +++ b/folly/test/SubprocessTest.cpp @@ -55,6 +55,16 @@ TEST(SimpleSubprocessTest, ExitsWithErrorChecked) { EXPECT_THROW(proc.waitChecked(), CalledProcessError); } +TEST(SimpleSubprocessTest, MoveSubprocess) { + Subprocess old_proc(std::vector{ "/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 { \