Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r63766 - in sandbox/SOC/2010/process: boost/process boost/process/detail libs/process/example
From: boris_at_[hidden]
Date: 2010-07-08 17:12:29


Author: bschaeling
Date: 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
New Revision: 63766
URL: http://svn.boost.org/trac/boost/changeset/63766

Log:
Added Boost.Asio I/O service object status to support asynchronous wait operations
Added:
   sandbox/SOC/2010/process/boost/process/detail/basic_status.hpp (contents, props changed)
   sandbox/SOC/2010/process/boost/process/detail/basic_status_service.hpp (contents, props changed)
   sandbox/SOC/2010/process/boost/process/detail/status_impl.hpp (contents, props changed)
   sandbox/SOC/2010/process/boost/process/pid_type.hpp (contents, props changed)
   sandbox/SOC/2010/process/boost/process/status.hpp (contents, props changed)
Text files modified:
   sandbox/SOC/2010/process/boost/process/process.hpp | 46 ++++++++++++++++-----------------------
   sandbox/SOC/2010/process/boost/process/stream_behavior.hpp | 46 +++------------------------------------
   sandbox/SOC/2010/process/libs/process/example/wait_async_child.cpp | 13 +++++------
   3 files changed, 29 insertions(+), 76 deletions(-)

Added: sandbox/SOC/2010/process/boost/process/detail/basic_status.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2010/process/boost/process/detail/basic_status.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -0,0 +1,56 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008, 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/basic_status.hpp
+ *
+ * Includes the declaration of the basic status class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_BASIC_STATUS_HPP
+#define BOOST_PROCESS_DETAIL_BASIC_STATUS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/pid_type.hpp>
+#include <boost/asio.hpp>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+template <typename Service>
+class basic_status
+ : public boost::asio::basic_io_object<Service>
+{
+public:
+ explicit basic_status(boost::asio::io_service &io_service)
+ : boost::asio::basic_io_object<Service>(io_service)
+ {
+ }
+
+ int wait(pid_type pid)
+ {
+ return this->service.wait(this->implementation, pid);
+ }
+
+ template <typename Handler>
+ void async_wait(pid_type pid, Handler handler)
+ {
+ this->service.async_wait(this->implementation, pid, handler);
+ }
+};
+
+}
+}
+}
+
+#endif

Added: sandbox/SOC/2010/process/boost/process/detail/basic_status_service.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2010/process/boost/process/detail/basic_status_service.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -0,0 +1,188 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008, 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/basic_status_service.hpp
+ *
+ * Includes the declaration of the basic status service class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_BASIC_STATUS_SERVICE_HPP
+#define BOOST_PROCESS_DETAIL_BASIC_STATUS_SERVICE_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/pid_type.hpp>
+#include <boost/process/detail/status_impl.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/system/error_code.hpp>
+#include <vector>
+#include <algorithm>
+
+#if defined(BOOST_POSIX_API)
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+namespace boost {
+namespace process {
+namespace detail {
+
+template <typename StatusImplementation = status_impl>
+class basic_status_service
+ : public boost::asio::detail::service_base<StatusImplementation>
+{
+public:
+ explicit basic_status_service(boost::asio::io_service &io_service)
+ : boost::asio::detail::service_base<StatusImplementation>(io_service),
+ run_(true),
+ work_thread_(&basic_status_service<StatusImplementation>::work_thread, this)
+ {
+ handles_.push_back(::CreateEvent(NULL, FALSE, FALSE, NULL));
+ if (handles_[0] == NULL)
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateEvent() failed");
+ }
+
+ ~basic_status_service()
+ {
+ stop_work_thread();
+ work_thread_.join();
+ if (!::CloseHandle(handles_[0]))
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+ }
+
+ typedef boost::shared_ptr<StatusImplementation> implementation_type;
+
+ void construct(implementation_type &impl)
+ {
+ impl = boost::make_shared<StatusImplementation>(StatusImplementation());
+ boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+ impls_.push_back(impl);
+ }
+
+ void destroy(implementation_type &impl)
+ {
+ // impl->destroy();
+ impl.reset();
+ // remove impl from impls_
+ }
+
+ int wait(implementation_type &impl, pid_type pid)
+ {
+ /*
+ boost::system::error_code ec;
+ int exit_code = impl->wait(pid, ec);
+ boost::asio::detail::throw_error(ec);
+ */
+ int exit_code = 0;
+ return exit_code;
+ }
+
+ template <typename Handler>
+ void async_wait(implementation_type &impl, pid_type pid, Handler handler)
+ {
+ HANDLE handle = ::OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (handle == NULL)
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+
+ boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+ interrupt_work_thread();
+ work_thread_cond_.wait(work_thread_mutex_);
+ if (!work_)
+ work_.reset(new boost::asio::io_service::work(this->get_io_service()));
+ handles_.push_back(handle);
+ impl->async_wait(handle, this->get_io_service().wrap(handler));
+ work_thread_cond_.notify_all();
+ }
+
+private:
+ void shutdown_service()
+ {
+ }
+
+ void work_thread()
+ {
+ while (running())
+ {
+ DWORD res = ::WaitForMultipleObjects(handles_.size(), &handles_[0], FALSE, INFINITE);
+ if (res == WAIT_FAILED)
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("WaitForMultipleObjects() failed");
+ else if (res - WAIT_OBJECT_0 == 0)
+ {
+ boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+ if (!run_)
+ break;
+ work_thread_cond_.notify_all();
+ work_thread_cond_.wait(work_thread_mutex_);
+ }
+ else if (res - WAIT_OBJECT_0 > 0)
+ {
+ HANDLE handle = handles_[res - WAIT_OBJECT_0];
+ DWORD exit_code;
+ if (!::GetExitCodeProcess(handle, &exit_code))
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("GetExitCodeProcess() failed");
+ boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+ for (std::vector<implementation_type>::iterator it = impls_.begin(); it != impls_.end(); ++it)
+ (*it)->complete(handle, exit_code);
+ std::vector<HANDLE>::iterator it = handles_.begin();
+ std::advance(it, res - WAIT_OBJECT_0);
+ handles_.erase(it);
+ if (handles_.size() == 1)
+ work_.reset();
+ }
+ }
+ }
+
+ bool running()
+ {
+ // Access to run_ is sychronized with stop_work_thread().
+ boost::mutex::scoped_lock lock(work_thread_mutex_);
+ return run_;
+ }
+
+ void interrupt_work_thread()
+ {
+ // By signaling the event in the first slot WaitForMultipleObjects() will return.
+ // The work thread won't do anything except checking if it should continue to run.
+ if (!::SetEvent(handles_[0]))
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("SetEvent() failed");
+ }
+
+ void stop_work_thread()
+ {
+ // Access to run_ is sychronized with running().
+ boost::mutex::scoped_lock lock(work_thread_mutex_);
+ run_ = false;
+ interrupt_work_thread();
+ }
+
+ boost::scoped_ptr<boost::asio::io_service::work> work_;
+ std::vector<implementation_type> impls_;
+ boost::mutex work_thread_mutex_;
+ boost::condition_variable_any work_thread_cond_;
+ bool run_;
+ boost::thread work_thread_;
+ std::vector<HANDLE> handles_;
+};
+
+}
+}
+}
+
+#endif

Added: sandbox/SOC/2010/process/boost/process/detail/status_impl.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2010/process/boost/process/detail/status_impl.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -0,0 +1,92 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008, 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>
+#include <boost/system/error_code.hpp>
+#include <boost/ptr_container/ptr_unordered_map.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+
+#if defined(BOOST_POSIX_API)
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+namespace boost {
+namespace process {
+namespace detail {
+
+struct operation
+{
+ virtual void operator()(DWORD exit_code)
+ {
+ }
+};
+
+template <typename Handler>
+class wrapped_handler : public operation
+{
+public:
+ wrapped_handler(Handler handler)
+ : handler_(handler)
+ {
+ }
+
+ void operator()(DWORD exit_code)
+ {
+ handler_(boost::system::error_code(), exit_code);
+ }
+
+private:
+ Handler handler_;
+};
+
+class status_impl
+{
+public:
+ template <typename Handler>
+ void async_wait(HANDLE handle, Handler handler)
+ {
+ ops_.insert(handle, new wrapped_handler<Handler>(handler));
+ }
+
+ void complete(HANDLE handle, DWORD exit_code)
+ {
+ boost::iterator_range<operations_type::iterator> r = ops_.equal_range(handle);
+ for (operations_type::iterator it = r.begin(); it != r.end(); ++it)
+ (*it->second)(exit_code);
+ ops_.erase(r.begin(), r.end());
+ if (!::CloseHandle(handle))
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+ }
+
+private:
+ typedef boost::ptr_unordered_multimap<HANDLE, operation> operations_type;
+ operations_type ops_;
+};
+
+}
+}
+}
+
+#endif

Added: sandbox/SOC/2010/process/boost/process/pid_type.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2010/process/boost/process/pid_type.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -0,0 +1,44 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008, 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/pid_type.hpp
+ *
+ * Includes the declaration of the pid type.
+ */
+
+#ifndef BOOST_PROCESS_PID_TYPE_HPP
+#define BOOST_PROCESS_PID_TYPE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/types.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#endif
+
+namespace boost {
+namespace process {
+
+#if defined(BOOST_PROCESS_DOXYGEN)
+typedef NativeProcessId pid_type;
+#elif defined(BOOST_POSIX_API)
+typedef pid_t pid_type;
+#elif defined(BOOST_WINDOWS_API)
+typedef DWORD pid_type;
+#endif
+
+}
+}
+
+#endif

Modified: sandbox/SOC/2010/process/boost/process/process.hpp
==============================================================================
--- sandbox/SOC/2010/process/boost/process/process.hpp (original)
+++ sandbox/SOC/2010/process/boost/process/process.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -108,7 +108,6 @@
         HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_);
         if (h == NULL)
             BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
-
         if (!::TerminateProcess(h, EXIT_FAILURE))
         {
             ::CloseHandle(h);
@@ -122,48 +121,41 @@
     /**
      * Blocks and waits for the child process to terminate.
      *
- * Returns a status object that represents the child process'
- * finalization condition. The child process object ceases to be
+ * Returns an exit code. The child process object ceases to be
      * valid after this call.
      *
      * \remark Blocking remarks: This call blocks if the child
      * process has not finalized execution and waits until
      * it terminates.
      */
- status wait()
+ int wait()
     {
 #if defined(BOOST_POSIX_API)
         int s;
         if (::waitpid(get_id(), &s, 0) == -1)
             BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("waitpid(2) failed");
- return status(s);
+ return s;
 #elif defined(BOOST_WINDOWS_API)
- // TODO
- // Boris: Where do we get the process handle from? It should be possible to fetch it
- // as we do have the process ID saved in the member variable id_. I guess
- // there must be a Windows API function to get a process handle from a process ID?
- if (::WaitForSingleObject(process_handle_.get(), INFINITE) == WAIT_FAILED)
- {
- // TODO
- // Boris: What should happen if WaitForSingleObject() fails? Under what
- // conditions can it fail?
- // std::cout << "Last error:" << GetLastError() << std::endl;
- // std::cout << "Criado com ID " << process_handle_.get() << std::endl;
- }
- DWORD code;
- if (!::GetExitCodeProcess(process_handle_.get(), &code))
+ HANDLE h = ::OpenProcess(SYNCHRONIZE, FALSE, id_);
+ if (h == NULL)
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+ if (::WaitForSingleObject(h, INFINITE) == WAIT_FAILED)
+ {
+ ::CloseHandle(h);
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("WaitForSingleObject() failed");
+ }
+ DWORD exit_code;
+ if (!::GetExitCodeProcess(h, &exit_code))
+ {
+ ::CloseHandle(h);
             BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("GetExitCodeProcess() failed");
- return status(code);
+ }
+ if (!::CloseHandle(h))
+ BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+ return exit_code;
 #endif
     }
 
-#if defined(BOOST_WINDOWS_API)
- /**
- * Process handle owned by RAII object.
- */
- boost::shared_ptr<void> process_handle_;
-#endif
-
 private:
     /**
      * The process' identifier.

Added: sandbox/SOC/2010/process/boost/process/status.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2010/process/boost/process/status.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -0,0 +1,34 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008, 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/status.hpp
+ *
+ * Includes the declaration of the status class.
+ */
+
+#ifndef BOOST_PROCESS_STATUS_HPP
+#define BOOST_PROCESS_STATUS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/detail/basic_status.hpp>
+#include <boost/process/detail/basic_status_service.hpp>
+
+namespace boost {
+namespace process {
+
+typedef detail::basic_status<detail::basic_status_service<> > status;
+
+}
+}
+
+#endif

Modified: sandbox/SOC/2010/process/boost/process/stream_behavior.hpp
==============================================================================
--- sandbox/SOC/2010/process/boost/process/stream_behavior.hpp (original)
+++ sandbox/SOC/2010/process/boost/process/stream_behavior.hpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -97,33 +97,7 @@
  *
  * A child process will not be able to use its streams.
  */
-
-#if defined(BOOST_POSIX_API)
-#elif defined(BOOST_WINDOWS_API)
-//This class does not works. The handles must be closed directly
-//in startup_info.hStdxxxxx, for example: CloseHandle(startup_info.hStdInput)
-class close : public stream
-{
-public:
- close()
- {
- child_end_ = INVALID_HANDLE_VALUE;
- CloseHandle(child_end_);
- }
-
- native_type get_child_end()
- {
- return child_end_;
- }
- native_type get_parent_end()
- {
- return INVALID_HANDLE_VALUE;
- }
-
-private:
- native_type child_end_;
-};
-#endif
+typedef stream close;
 
 /**
  * Stream behavior to make a child process inherit streams.
@@ -345,21 +319,9 @@
         if (child_end_ == -1)
             BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
 #elif defined(BOOST_WINDOWS_API)
-
- if(stream == input_stream)
- {
- child_end_ = ::CreateFileA("NUL", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- }
-
- else if(stream == output_stream)
- {
- child_end_ = ::CreateFileA("NUL", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- }
-
- else
- BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("Unknown st3ream type.");
-
- if (child_end_ == INVALID_HANDLE_VALUE)
+ DWORD access = (stream == input_stream) ? GENERIC_READ : GENERIC_WRITE;
+ child_end_ = ::CreateFileA("NUL", access, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (child_end_ == INVALID_HANDLE_VALUE)
             BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed");
 #endif
     }

Modified: sandbox/SOC/2010/process/libs/process/example/wait_async_child.cpp
==============================================================================
--- sandbox/SOC/2010/process/libs/process/example/wait_async_child.cpp (original)
+++ sandbox/SOC/2010/process/libs/process/example/wait_async_child.cpp 2010-07-08 17:12:27 EDT (Thu, 08 Jul 2010)
@@ -10,9 +10,8 @@
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 
-#include <boost/all/process.hpp>
+#include <boost/process/all.hpp>
 #include <boost/asio.hpp>
-#include <boost/bind.hpp>
 #include <iostream>
 
 using namespace boost::process;
@@ -20,19 +19,19 @@
 
 io_service ioservice;
 
-void end_wait(const boost::system::error_code &ec);
+void end_wait(const boost::system::error_code &ec, int exit_code);
 
 int main()
 {
     std::string exe = find_executable_in_path("hostname");
     child c = create_child(exe);
- status &s = p.status(ioservice);
- s.async_wait(boost::bind(&end_wait, placeholders::error));
+ status s(ioservice);
+ s.async_wait(c.get_id(), end_wait);
     ioservice.run();
 }
 
-void end_wait(const boost::system::error_code &ec)
+void end_wait(const boost::system::error_code &ec, int exit_code)
 {
     if (!ec)
- std::cout << "process exited" << std::endl;
+ std::cout << "exit code: " << exit_code << std::endl;
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk