190 lines
4.7 KiB
C++
190 lines
4.7 KiB
C++
//
|
|
// Boost.Process
|
|
// ~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
|
// Copyright (c) 2009 Boris Schaeling
|
|
// Copyright (c) 2010 Felipe Tanus, 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/detail/status_impl.hpp
|
|
*
|
|
* Includes the declaration of the status implementation class.
|
|
*/
|
|
|
|
#ifndef BOOST_PROCESS_DETAIL_STATUS_IMPL_HPP
|
|
#define BOOST_PROCESS_DETAIL_STATUS_IMPL_HPP
|
|
|
|
#include <boost/process/config.hpp>
|
|
|
|
#if defined(BOOST_POSIX_API)
|
|
# include <sys/types.h>
|
|
# include <signal.h>
|
|
# include <sys/wait.h>
|
|
# include <errno.h>
|
|
#elif defined(BOOST_WINDOWS_API)
|
|
# include <windows.h>
|
|
#else
|
|
# error "Unsupported platform."
|
|
#endif
|
|
|
|
#include <boost/process/pid_type.hpp>
|
|
#include <boost/system/error_code.hpp>
|
|
#include <boost/ptr_container/ptr_unordered_map.hpp>
|
|
#include <algorithm>
|
|
|
|
namespace boost {
|
|
namespace process {
|
|
namespace detail {
|
|
|
|
#if defined(BOOST_POSIX_API)
|
|
typedef pid_t phandle;
|
|
#elif defined(BOOST_WINDOWS_API)
|
|
typedef HANDLE phandle;
|
|
#endif
|
|
|
|
struct operation
|
|
{
|
|
virtual ~operation(){}
|
|
virtual void operator()(int exit_code)
|
|
{
|
|
#if defined(BOOST_MSVC)
|
|
exit_code;
|
|
#endif
|
|
}
|
|
};
|
|
|
|
template <typename Handler>
|
|
class wrapped_handler : public operation
|
|
{
|
|
public:
|
|
wrapped_handler(Handler handler)
|
|
: handler_(handler)
|
|
{
|
|
}
|
|
|
|
void operator()(int exit_code)
|
|
{
|
|
handler_(boost::system::error_code(), exit_code);
|
|
}
|
|
|
|
private:
|
|
Handler handler_;
|
|
};
|
|
|
|
/**
|
|
* The status_impl class saves internal data of every status I/O object.
|
|
*/
|
|
class status_impl
|
|
{
|
|
public:
|
|
#if defined(BOOST_WINDOWS_API)
|
|
template <typename Container>
|
|
void clear(Container &handles)
|
|
{
|
|
for (operations_type::iterator it = ops_.begin(); it != ops_.end();
|
|
++it)
|
|
{
|
|
for (typename Container::iterator it2 = handles.begin(); it2 !=
|
|
handles.end(); ++it2)
|
|
{
|
|
if (*it2 == it->first)
|
|
{
|
|
handles.erase(it2);
|
|
break;
|
|
}
|
|
}
|
|
CloseHandle(it->first);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int wait(pid_type pid, boost::system::error_code &ec)
|
|
{
|
|
#if defined(BOOST_POSIX_API)
|
|
pid_t p;
|
|
int status;
|
|
do
|
|
{
|
|
p = waitpid(pid, &status, 0);
|
|
} while (p == -1 && errno == EINTR);
|
|
if (p == -1)
|
|
{
|
|
ec = boost::system::error_code(errno,
|
|
boost::system::get_system_category());
|
|
return -1;
|
|
}
|
|
return status;
|
|
#elif defined(BOOST_WINDOWS_API)
|
|
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE,
|
|
pid);
|
|
if (h == NULL)
|
|
{
|
|
ec = boost::system::error_code(GetLastError(),
|
|
boost::system::get_system_category());
|
|
return -1;
|
|
}
|
|
|
|
if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED)
|
|
{
|
|
CloseHandle(h);
|
|
ec = boost::system::error_code(GetLastError(),
|
|
boost::system::get_system_category());
|
|
return -1;
|
|
}
|
|
|
|
DWORD exit_code;
|
|
if (!GetExitCodeProcess(h, &exit_code))
|
|
{
|
|
CloseHandle(h);
|
|
ec = boost::system::error_code(GetLastError(),
|
|
boost::system::get_system_category());
|
|
return -1;
|
|
}
|
|
if (!CloseHandle(h))
|
|
{
|
|
ec = boost::system::error_code(GetLastError(),
|
|
boost::system::get_system_category());
|
|
return -1;
|
|
}
|
|
return exit_code;
|
|
#endif
|
|
}
|
|
|
|
template <typename Handler>
|
|
void async_wait(phandle ph, Handler handler)
|
|
{
|
|
ops_.insert(ph, new wrapped_handler<Handler>(handler));
|
|
}
|
|
|
|
bool complete(phandle ph, int exit_code)
|
|
{
|
|
boost::iterator_range<operations_type::iterator> r =
|
|
ops_.equal_range(ph);
|
|
if (r.empty())
|
|
return false;
|
|
for (operations_type::iterator it = r.begin(); it != r.end(); ++it)
|
|
(*it->second)(exit_code);
|
|
ops_.erase(r.begin(), r.end());
|
|
#if defined(BOOST_WINDOWS_API)
|
|
if (!CloseHandle(ph))
|
|
BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
typedef boost::ptr_unordered_multimap<phandle, operation> operations_type;
|
|
operations_type ops_;
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|