$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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; 
 }