You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
6.2 KiB

//
// Boost.Process
// ~~~~~~~~~~~~~
//
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008, 2009 Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
/**
* \file boost/process/posix_child.hpp
*
* Includes the declaration of the posix_child class.
*/
#ifndef BOOST_PROCESS_POSIX_CHILD_HPP
#define BOOST_PROCESS_POSIX_CHILD_HPP
#include <boost/process/child.hpp>
#include <boost/process/pistream.hpp>
#include <boost/process/postream.hpp>
#include <boost/process/detail/pipe.hpp>
#include <boost/process/detail/posix_ops.hpp>
#include <boost/process/detail/stream_info.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/assert.hpp>
#include <map>
#include <unistd.h>
namespace boost {
namespace process {
/**
* POSIX implementation of the Child concept.
*
* The posix_child class implements the Child concept in a POSIX
* operating system.
*
* A POSIX child differs from a regular child (represented by a
* child object) in that it supports more than three communication
* channels with its parent. These channels are identified by regular
* file descriptors (integers).
*
* This class is built on top of the generic child so as to allow its
* trivial adoption. When a program is changed to use the POSIX-specific
* context (posix_context), it will most certainly need to migrate its
* use of the child class to posix_child. Doing so is only a matter of
* redefining the appropriate object and later using the required extra
* features: there should be no need to modify the existing code (e.g.
* method calls) in any other way.
*/
class posix_child : public child
{
public:
/**
* Gets a reference to the child's input stream \a desc.
*
* Returns a reference to a postream object that represents one of
* the multiple input communication channels with the child process.
* The channel is identified by \a desc as seen from the child's
* point of view. The parent can use the returned stream to send
* data to the child.
*
* Giving this function the STDIN_FILENO constant (defined in
* unistd.h) is a synonym for the get_stdin() call inherited from
* child.
*/
postream &get_input(int desc) const
{
if (desc == STDIN_FILENO)
return posix_child::get_stdin();
else
{
input_map_t::const_iterator it = input_map_.find(desc);
BOOST_ASSERT(it != input_map_.end());
return *it->second;
}
}
/**
* Gets a reference to the child's output stream \a desc.
*
* Returns a reference to a pistream object that represents one of
* the multiple output communication channels with the child process.
* The channel is identified by \a desc as seen from the child's
* point of view. The parent can use the returned stream to retrieve
* data from the child.
*
* Giving this function the STDOUT_FILENO or STDERR_FILENO constants
* (both defined in unistd.h) are synonyms for the get_stdout() and
* get_stderr() calls inherited from child, respectively.
*/
pistream &get_output(int desc) const
{
if (desc == STDOUT_FILENO)
return posix_child::get_stdout();
else if (desc == STDERR_FILENO)
return posix_child::get_stderr();
else
{
output_map_t::const_iterator it = output_map_.find(desc);
BOOST_ASSERT(it != output_map_.end());
return *it->second;
}
}
/**
* Constructs a new POSIX child object representing a just
* spawned child process.
*
* Creates a new child object that represents the just spawned process
* \a id.
*
* The \a infoin and \a infoout maps contain the pipes used to handle
* the redirections of the child process; at the moment, no other
* stream_info types are supported. If the launcher was asked to
* redirect any of the three standard flows, their pipes must be
* present in these maps.
*/
posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout)
: child(id,
detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false),
detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true),
detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true))
{
for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
{
detail::stream_info &si = it->second;
if (si.type_ == detail::stream_info::use_pipe)
{
BOOST_ASSERT(si.pipe_->wend().valid());
boost::shared_ptr<postream> st(new postream(si.pipe_->wend()));
input_map_.insert(input_map_t::value_type(it->first, st));
}
}
for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
{
detail::stream_info &si = it->second;
if (si.type_ == detail::stream_info::use_pipe)
{
BOOST_ASSERT(si.pipe_->rend().valid());
boost::shared_ptr<pistream> st(new pistream(si.pipe_->rend()));
output_map_.insert(output_map_t::value_type(it->first, st));
}
}
}
private:
/**
* Maps child's file descriptors to postream objects.
*/
typedef std::map<int, boost::shared_ptr<postream> > input_map_t;
/**
* Contains all relationships between child's input file
* descriptors and their corresponding postream objects.
*/
input_map_t input_map_;
/**
* Maps child's file descriptors to pistream objects.
*/
typedef std::map<int, boost::shared_ptr<pistream> > output_map_t;
/**
* Contains all relationships between child's output file
* descriptors and their corresponding pistream objects.
*/
output_map_t output_map_;
};
}
}
#endif