Published using Google Docs
Boost Process
Updated automatically every 5 minutes

Rationale

Many applications require the ability to launch another application to carry out some tasks, and to do so portably. Different operating systems provide conceptually and structurally disparate means to do so. For example posix systems use the so-called fork/exec paradigm, while windows provides the CreateProcess api call. While windows supplies most posix api calls, fork is notably missing from the windows supplied posix subsystem.

Additionally, there are times when access to platform specific functionality is required, an example is specifying Windows security attributes...

Purpose

Boost.Process has the following aims:

The library includes stock components for the portable specification of child process’ application path, working_directory, arguments, environment and standard in, out and err streams.

Overview

At the heart of Boost.Process is a collection of concepts and a set predefined models of these concepts that collaborate to simplify the portable launching of an executable as a child process. Further, users may provide their own models of these concepts to extend the functionality in a portable and/or platform specific manner.

Each platform's files are organized into separate platform directories and namespaces, minimizing #ifdef'd code and coincidental coupling between platform specific code. This makes adding a new platform orthogonal to existing platforms.

Concepts

The fundamental building blocks of the library are the concepts of an initializer which serves to initialize the data structures specified by an executor, the executor uses these data structures to launch the executable as a child process, a concept of a monitor allows the synchronization of parent and child processes, and models of a ray allow streaming between parent processes child processes and their siblings. Models of intializer mutually visit models of executor. Models of monitor are produced by models of executor. Models of a pipe are used by models of an initializer to initialize child process standard stream input and output.

An initializer is constructable possibly with user data which collaborates with an executor at the appropriate phases of child process creation.

A windows initializer is a refinement of an initializer which has:

A posix initializer is a refinement of an initializer which has:

A portable initializer refines the initializer concept when there exists an initializer with the same name in each supported platform namespace.

An executor is default constructable with an execute method taking a sequence of initializers. Each initializer in the sequence is visited at each phase of child process creation by the executor, passing a reference of itself to the initializer.

A windows executor is a refinement of an executor which has an execute method taking a sequence of windows initializers. The pre_create method of each initializer is called before the windows process is created, and the post_create method of each initializer is called after the windows process is created.

A posix executor is a refinement of an executor which has an execute method taking a fusion sequence of posix initializers. The pre_fork method of each initializer is called before the posix process is forked, the post_fork_parent method of each initializer is called from the initiating parent process after fork is returned, and the post_fork_child method of each initializer is called from the newly forked child process only if fork succeeds.

A portable executor refines the executor concept, when there exists an initializer with the same name in each supported platform namespace.

A Ray is a connected pair of boost iostreams' Source and Sink concepts, embodying unidirectional flow of information into the sink end and out the source end. A model of a Ray would be file_descriptor_ray, which comprises a boost iostream file_descriptor_sink and a file_descriptor_source.

Motivating Example

A parent process wants to create 3 child processes. Child1’s standard output provides standard input to Child2 whose standard output provides standard input to Child3. The parent process opens an error log file and writes to it as should each of the Child processes. Let’s implement this with boost process::

namespace bp = boost::process;

namespace io = boost::iostreams;

io::file_descriptor_sink log(“my_error_log.txt);

Starting at the top. The parent process owns a log file that it’s using for other things in addition to capturing it’s child process’ stderr output.

bp::file_descriptor_ray ray_a;

bp::file_descriptor_ray ray_b;

We create a couple of rays to be used by the stdin and stdout initializers of subsequent child processes. These rays need only exist during the creation of the child processes that use them.

bp::monitor c1 = bp::make_child

( bp::paths(“c:/some/path/exe1.exe”)

, bp::arg(“-d”)(123)(a_boost_filesystem_path)

, bp::stdout_to(ray_a)

, bp::stderr_to(log)

));

Next we launch child process 1 by calling the make_child function(which creates an executor and calls it’s execute method), with up to ten of initializers.  The 1st argument is a paths object requiring an absolute path to an executable image file. This single argument constructor also sets the working directory to the directory containing the executable. The second argument is an args object, which is constructed by constructing an arg object initialized to the string “-d”, and then concatenating it with additional arg objects returning an args object. bp::arg uses boost::lexical_cast<std::string> to access the string representation of the type being concatenated. The remaining arguments specify standard stream definitions:  stdout writes to ray_a, and stderr is redirecting it’s output to the Finally a monitor object is initialized with the minimal process information needed to later interact with the child process.

bp::monitor c2 = bp::make_child

( bp::paths(“c:/some/path/exe2.exe”, boost::filesystem::current_path())

, bp::args(“--x=abcd efgh”)(a_boost_filesystem_path)(“-Z”)(123)

, bp::stdin_from(ray_a)

, bp::stdout_to(ray_b)

, bp::stderr_to(log)

));

Launching Child2 above, by specifying the working directory equal to the parent’s current working directory. Also note Child2 will receive its input from ray_a(generated from child1 output), and Child2 will write it’s output to ray_b, again redirecting stderr to the parent’s log file.

bp::monitor c3 = bp::make_child

( bp::paths(“c:/some/path/exe3.exe”, “f:/some/other/path/working_dir”)

, bp::args(“-d”)(123)(a_boost_filesystem_path)

, bp::stdin_from(ray_b)

, bp::stderr_to(log)

, my_portable_initializer(“on”, 123, ...)

));

Launching Child3 demonstrates specifying an arbitrary working directory . Note that bp::paths’ constructor arguments are boost::filesystem::path const&, here relying on implicit construction from strings. The last argument demonstrates specifying a non-stock portable initializer.

Arg and Args Initializers

Arg Initializer

Description

Header

#include <boost/process/initializers/args.hpp>

Model of

Portable Initializer

Notation

Args

A Args type.

as

An object of type  Args.

a

An object of type  arg.

a1...aN

Objects of type arg.

Expression Semantics

Semantics of an expression is defined only where it differs from, or is not defined in Portable Initializer.

Expression

Semantics

Args()

Construct an empty args.

Args(a)

Construct an args instance containing one arg instance..

as = s2

Assign as2 to as.

Args(a1)(a2)...(aN)

Add one or more arg (a1...aN) to Args.

Model of