Skip to content

Latest commit

 

History

History
100 lines (80 loc) · 3.31 KB

File metadata and controls

100 lines (80 loc) · 3.31 KB

stdio.hpp

 The initializer for the stdio of a subprocess
The subprocess stdio initializer has three members:
  • in for stdin

  • out for stdout

  • err for stderr

If the initializer is present all three will be set for the subprocess. By default they will inherit the stdio handles from the parent process. This means that this will forward stdio to the subprocess:

asio::io_context ctx;
v2::process proc(ctx, "/bin/bash", {}, v2::process_stdio{});

No constructors are provided in order to support designated initializers in later version of C++.

asio::io_context ctx;

/// C++17
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.err=nullptr});
/// C++11 & C++14
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr});

Valid initializers for any stdio are:

  • std::nullptr_t assigning a null-device

  • FILE* any open file, including stdin, stdout and stderr

  • native_handle any native file handle (HANDLE on windows) or file descriptor (int on posix)

  • any io-object with a .native_handle() function that is compatible with the above. E.g. a asio::ip::tcp::socket, or a pipe object.

  • a filesystem::path, which will open a readable or writable depending on the direction of the stream

  • an asio::basic_writeable_pipe for stdin or asio::basic_readable_pipe for stderr/stdout.

When passing a FILE*, a native_handle or an io-object with a native_handle, the initializer will assign the handle as is to the child process. That is the file descriptor/handle gets cloned into the subprocess and used without modification.

When passing a filesystem::path, the initializer will attempt to open the file and then pass the handle to the subprocess.

When passing a readable_pipe to stdout/stderr or a writable_pipe to stdin by reference, the initializer to create the other side of the pipe (writable_pipe for stdout/stderr, readable_pipe for stdin), connect the pair and pass the native_handle to the child process.

That is, these two are equivalent:

Implicit construction of the readable pipe.
asio::io_context ctx;
asio::writable_pipe wp{ctx};
// create a readable pipe internally and connect it to wp
process proc{ctx, "/bin/bash", {}, process_stdio{.in=wp}};

// create it explicitly
{
  // the pipe the child process reads from
  asio::readable_pipe rp{ctx};
  asio::connect_pipe(rp, wp);
  // `rp.native_handle()`  will be assigned to the child processes stdin
  process proc{ctx, "/bin/bash", {}, process_stdio{.in=rp}};
  rp.close(); // close it so the pipe closes when the `proc exits.
}

The explicit version allows you to assign the same writable_pipe to stdout and stderr:

// the pipe the parent process reads from and both
// stderr & stdout of the child process write to
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
process proc{ctx, "/bin/bash", {}, process_stdio{.out=wp, .err=wp}};
wp.close(); // close it so the pipe closes when the `proc exits.
Note
If the child writes to a pipe, the parent reads from it et vice versa.
/// The initializer for the stdio of a subprocess
struct process_stdio
{
  __implementation_defined__ in;
  __implementation_defined__ out;
  __implementation_defined__ err;
};