From 4b3718646a22fdaeab9088ed30dfe88e42cc215b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 23 Nov 2022 08:45:53 +0200 Subject: Add some more process constructor overloads --- libbutl/process.hxx | 73 ++++++++++++++++++++++++++++++++++--- libbutl/process.ixx | 103 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 163 insertions(+), 13 deletions(-) diff --git a/libbutl/process.hxx b/libbutl/process.hxx index 10e1587..dfade07 100644 --- a/libbutl/process.hxx +++ b/libbutl/process.hxx @@ -269,7 +269,30 @@ namespace butl // the parent. So you should do this yourself, if required. For example, // to redirect the child process stdout to stderr, you can do: // - // process p (..., 0, 2); + // process pr (..., 0, 2); + // + // Note also that the somewhat roundabout setup with -1 as a redirect + // "instruction" and out_fd/in_ofd/in_efd data members for the result + // helps to make sure the stream instances are destroyed before the + // process instance. For example: + // + // process pr (..., 0, -1, 2); + // ifdstream is (move (pr.in_ofd)); + // + // This is important in case an exception is thrown where we want to make + // sure all our pipe ends are closed before we wait for the process exit + // (which happens in the process destructor). + // + // And speaking of the destruction order, another thing to keep in mind is + // that only one stream can use the skip mode (fdstream_mode::skip; + // because skipping is performed in the blocking mode) and the stream that + // skips should come first so that all other streams are destroyed/closed + // before it (failed that, we may end up in a deadlock). For example: + // + // process pr (..., -1, -1, -1); + // ifdstream is (move (pr.in_ofd), fdstream_mode::skip); // Must be first. + // ifdstream es (move (pr.in_efd)); + // ofdstream os (move (pr.out_fd)); // // The cwd argument allows to change the current working directory of the // child process. NULL and empty arguments are ignored. @@ -345,6 +368,16 @@ namespace butl bool own_out = false; }; + process (const char**, + pipe in, pipe out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + + process (const char**, + int in, int out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + process (const process_path&, const char* const*, pipe in, pipe out, pipe err, const char* cwd = nullptr, @@ -355,6 +388,16 @@ namespace butl const char* cwd = nullptr, const char* const* envvars = nullptr); + process (std::vector&, + pipe in, pipe out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + + process (std::vector&, + int in, int out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + process (const process_path&, const std::vector&, pipe in, pipe out, pipe err, const char* cwd = nullptr, @@ -383,6 +426,26 @@ namespace butl const char* cwd = nullptr, const char* const* envvars = nullptr); + process (const char**, + process&, pipe out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + + process (const char**, + process&, int out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + + process (const process_path&, const char* const*, + process&, pipe out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + + process (const process_path&, const char* const*, + process&, int out, pipe err, + const char* cwd = nullptr, + const char* const* envvars = nullptr); + // Wait for the process to terminate. Return true if the process // terminated normally and with the zero exit code. Unless ignore_error // is true, throw process_error if anything goes wrong. This function can @@ -409,7 +472,7 @@ namespace butl // Note that the destructor will wait for the process but will ignore // any errors and the exit status. // - ~process () {if (handle != 0) wait (true);} + ~process () { if (handle != 0) wait (true); } // Process termination. // @@ -459,7 +522,7 @@ namespace butl // // ... // E.g., print args[0]. // - // process p (pp, args); + // process pr (pp, args); // // You can also specify the fallback directory which will be tried last. // This, for example, can be used to implement the Windows "search in the @@ -571,8 +634,8 @@ namespace butl // optional exit; - // Use the following file descriptors to communicate with the new process's - // standard streams. + // Use the following file descriptors to communicate with the new + // process's standard streams (if redirected to pipes; see above). // auto_fd out_fd; // Write to it to send to stdin. auto_fd in_ofd; // Read from it to receive from stdout. diff --git a/libbutl/process.ixx b/libbutl/process.ixx index a346a5d..9753d22 100644 --- a/libbutl/process.ixx +++ b/libbutl/process.ixx @@ -214,11 +214,7 @@ namespace butl inline process:: process (optional e) - : handle (0), - exit (std::move (e)), - out_fd (-1), - in_ofd (-1), - in_efd (-1) + : handle (0), exit (std::move (e)) { } @@ -268,6 +264,28 @@ namespace butl } inline process:: + process (const char** args, + pipe in, pipe out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args, + std::move (in), std::move (out), std::move (err), + cwd, envvars) + { + } + + inline process:: + process (const char** args, + int in, int out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args, + pipe (in, -1), pipe (-1, out), std::move (err), + cwd, envvars) + { + } + + inline process:: process (const process_path& pp, const char* const* args, int in, int out, pipe err, const char* cwd, @@ -280,6 +298,30 @@ namespace butl } inline process:: + process (std::vector& args, + pipe in, pipe out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args.data (), + std::move (in), std::move (out), std::move (err), + cwd, + envvars) + { + } + + inline process:: + process (std::vector& args, + int in, int out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args.data (), + pipe (in, -1), pipe (-1, out), std::move (err), + cwd, + envvars) + { + } + + inline process:: process (const process_path& pp, const std::vector& args, pipe in, pipe out, pipe err, const char* cwd, @@ -305,13 +347,27 @@ namespace butl inline process:: process (const process_path& pp, const char* const* args, + process& in, pipe out, pipe err, + const char* cwd, + const char* const* envvars) + : process (pp, args, + [&in] () + { + assert (in.in_ofd != nullfd); // Should be a pipe. + return process::pipe (std::move (in.in_ofd), -1); + } (), + std::move (out), std::move (err), + cwd, envvars) + { + } + + inline process:: + process (const process_path& pp, const char* const* args, process& in, int out, int err, const char* cwd, const char* const* envvars) - : process (pp, args, in.in_ofd.get (), out, err, cwd, envvars) + : process (pp, args, in, pipe (-1, out), pipe (-1, err), cwd, envvars) { - assert (in.in_ofd.get () != -1); // Should be a pipe. - in.in_ofd.reset (); // Close it on our side. } inline process:: @@ -324,6 +380,37 @@ namespace butl } inline process:: + process (const char** args, + process& in, pipe out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args, + in, std::move (out), std::move (err), + cwd, envvars) + { + } + + inline process:: + process (const char** args, + process& in, int out, pipe err, + const char* cwd, + const char* const* envvars) + : process (path_search (args[0]), args, + in, pipe (-1, out), std::move (err), + cwd, envvars) + { + } + + inline process:: + process (const process_path& pp, const char* const* args, + process& in, int out, pipe err, + const char* cwd, + const char* const* envvars) + : process (pp, args, in, pipe (-1, out), std::move (err), cwd, envvars) + { + } + + inline process:: process (process&& p) : handle (p.handle), exit (std::move (p.exit)), -- cgit v1.1