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