// // 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 #if defined(BOOST_POSIX_API) # include # include # include # include #elif defined(BOOST_WINDOWS_API) # include #else # error "Unsupported platform." #endif #include #include #include #include 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 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 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 void async_wait(phandle ph, Handler handler) { ops_.insert(ph, new wrapped_handler(handler)); } bool complete(phandle ph, int exit_code) { boost::iterator_range 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 operations_type; operations_type ops_; }; } } } #endif