Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r69467 - in trunk: boost/asio boost/asio/detail boost/asio/detail/impl boost/asio/impl boost/asio/ip boost/asio/local boost/asio/posix boost/asio/ssl boost/asio/windows libs/asio/doc libs/asio/example/chat libs/asio/example/echo libs/asio/example/fork libs/asio/example/http/server2 libs/asio/example/http/server3 libs/asio/example/local libs/asio/example/services libs/asio/example/timeouts libs/asio/example/tutorial/timer5 libs/asio/test libs/asio/test/archetypes libs/asio/test/ip
From: chris_at_[hidden]
Date: 2011-03-02 03:28:00


Author: chris_kohlhoff
Date: 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
New Revision: 69467
URL: http://svn.boost.org/trac/boost/changeset/69467

Log:
* Add support for the fork() system call. Programs that use fork must call
  io_service.notify_fork() at the appropriate times. Two new examples have been
  added showing how to use this feature. Refs #3238, #4162.

* Clean up the handling of errors reported by the close() system call. In
  particular, assume that most operating systems won't have close() fail with
  EWOULDBLOCK, but if it does then set blocking mode and restart the call. If
  any other error occurs we assume the descriptor is closed. Refs #3307.

* EV_ONESHOT seems to cause problems on some versions of Mac OS X, with the
  io_service destructor getting stuck inside the close() system call. Use
  EV_CLEAR instead. Refs #5021.

* Include function name in exception what() messages.

* Fix insufficient initialisers warning with MinGW.

* Make the shutdown_service() member functions private.

* Add archetypes for testing socket option functions.

* Add missing lock in signal_set_service::cancel().

* Fix copy/paste error in SignalHandler example.

* The signal header needs to be included in signal_set_service.hpp so that we
  can use constants like NSIG and SIGRTMAX.

* Don't use Boost.Thread's convenience header. Use the header file that is
  specifically for the boost::thread class instead.

Added:
   trunk/libs/asio/example/fork/
   trunk/libs/asio/example/fork/Jamfile (contents, props changed)
   trunk/libs/asio/example/fork/Jamfile.v2 (contents, props changed)
   trunk/libs/asio/example/fork/daemon.cpp (contents, props changed)
   trunk/libs/asio/example/fork/process_per_connection.cpp (contents, props changed)
   trunk/libs/asio/test/archetypes/gettable_socket_option.hpp (contents, props changed)
   trunk/libs/asio/test/archetypes/settable_socket_option.hpp (contents, props changed)
Text files modified:
   trunk/boost/asio/basic_datagram_socket.hpp | 16 +-
   trunk/boost/asio/basic_deadline_timer.hpp | 14 +-
   trunk/boost/asio/basic_raw_socket.hpp | 16 +-
   trunk/boost/asio/basic_seq_packet_socket.hpp | 6
   trunk/boost/asio/basic_serial_port.hpp | 24 ++--
   trunk/boost/asio/basic_signal_set.hpp | 20 ++--
   trunk/boost/asio/basic_socket.hpp | 48 +++++----
   trunk/boost/asio/basic_socket_acceptor.hpp | 40 ++++----
   trunk/boost/asio/basic_socket_streambuf.hpp | 4
   trunk/boost/asio/basic_stream_socket.hpp | 12 +-
   trunk/boost/asio/datagram_socket_service.hpp | 12 +-
   trunk/boost/asio/deadline_timer_service.hpp | 12 +-
   trunk/boost/asio/detail/dev_poll_reactor.hpp | 13 ++
   trunk/boost/asio/detail/epoll_reactor.hpp | 9 +
   trunk/boost/asio/detail/eventfd_select_interrupter.hpp | 9 +
   trunk/boost/asio/detail/impl/descriptor_ops.ipp | 21 +++-
   trunk/boost/asio/detail/impl/dev_poll_reactor.ipp | 89 +++++++++++++++++-
   trunk/boost/asio/detail/impl/epoll_reactor.ipp | 96 ++++++++++++++++++-
   trunk/boost/asio/detail/impl/eventfd_select_interrupter.ipp | 20 ++++
   trunk/boost/asio/detail/impl/kqueue_reactor.ipp | 106 ++++++++++++++++++---
   trunk/boost/asio/detail/impl/pipe_select_interrupter.ipp | 20 ++++
   trunk/boost/asio/detail/impl/reactive_descriptor_service.ipp | 11 +
   trunk/boost/asio/detail/impl/reactive_socket_service_base.ipp | 13 ++
   trunk/boost/asio/detail/impl/resolver_service_base.ipp | 19 +++
   trunk/boost/asio/detail/impl/select_reactor.ipp | 15 +++
   trunk/boost/asio/detail/impl/service_registry.ipp | 30 ++++++
   trunk/boost/asio/detail/impl/signal_set_service.ipp | 192 ++++++++++++++++++++++++++-------------
   trunk/boost/asio/detail/impl/socket_ops.ipp | 51 ++++++----
   trunk/boost/asio/detail/impl/socket_select_interrupter.ipp | 20 ++++
   trunk/boost/asio/detail/kqueue_reactor.hpp | 9 +
   trunk/boost/asio/detail/pipe_select_interrupter.hpp | 9 +
   trunk/boost/asio/detail/resolver_service_base.hpp | 3
   trunk/boost/asio/detail/select_reactor.hpp | 8 +
   trunk/boost/asio/detail/service_registry.hpp | 3
   trunk/boost/asio/detail/signal_set_service.hpp | 10 ++
   trunk/boost/asio/detail/socket_select_interrupter.hpp | 9 +
   trunk/boost/asio/detail/win_static_mutex.hpp | 2
   trunk/boost/asio/impl/connect.hpp | 8
   trunk/boost/asio/impl/io_service.ipp | 9 +
   trunk/boost/asio/impl/read.hpp | 8
   trunk/boost/asio/impl/read_at.hpp | 8
   trunk/boost/asio/impl/read_until.hpp | 8
   trunk/boost/asio/impl/write.hpp | 8
   trunk/boost/asio/impl/write_at.hpp | 8
   trunk/boost/asio/io_service.hpp | 73 ++++++++++++++
   trunk/boost/asio/ip/basic_resolver.hpp | 4
   trunk/boost/asio/ip/resolver_service.hpp | 18 ++-
   trunk/boost/asio/local/connect_pair.hpp | 2
   trunk/boost/asio/posix/basic_descriptor.hpp | 20 ++-
   trunk/boost/asio/posix/basic_stream_descriptor.hpp | 4
   trunk/boost/asio/posix/stream_descriptor_service.hpp | 12 +-
   trunk/boost/asio/raw_socket_service.hpp | 12 +-
   trunk/boost/asio/seq_packet_socket_service.hpp | 12 +-
   trunk/boost/asio/serial_port_service.hpp | 12 +-
   trunk/boost/asio/signal_set_service.hpp | 18 ++-
   trunk/boost/asio/socket_acceptor_service.hpp | 12 +-
   trunk/boost/asio/ssl/context_service.hpp | 10 +-
   trunk/boost/asio/ssl/stream_service.hpp | 10 +-
   trunk/boost/asio/stream_socket_service.hpp | 12 +-
   trunk/boost/asio/windows/basic_handle.hpp | 8
   trunk/boost/asio/windows/basic_random_access_handle.hpp | 4
   trunk/boost/asio/windows/basic_stream_handle.hpp | 4
   trunk/boost/asio/windows/random_access_handle_service.hpp | 12 +-
   trunk/boost/asio/windows/stream_handle_service.hpp | 12 +-
   trunk/libs/asio/doc/Jamfile.v2 | 2
   trunk/libs/asio/doc/examples.qbk | 14 ++
   trunk/libs/asio/example/chat/chat_client.cpp | 2
   trunk/libs/asio/example/echo/blocking_tcp_echo_server.cpp | 2
   trunk/libs/asio/example/http/server2/io_service_pool.cpp | 2
   trunk/libs/asio/example/http/server3/server.cpp | 2
   trunk/libs/asio/example/local/connect_pair.cpp | 2
   trunk/libs/asio/example/services/logger_service.hpp | 2
   trunk/libs/asio/example/timeouts/async_tcp_client.cpp | 3
   trunk/libs/asio/example/timeouts/blocking_tcp_client.cpp | 3
   trunk/libs/asio/example/timeouts/server.cpp | 3
   trunk/libs/asio/example/tutorial/timer5/timer.cpp | 2
   trunk/libs/asio/test/deadline_timer.cpp | 2
   trunk/libs/asio/test/io_service.cpp | 2
   trunk/libs/asio/test/ip/tcp.cpp | 26 ++++-
   trunk/libs/asio/test/ip/udp.cpp | 27 ++++-
   trunk/libs/asio/test/strand.cpp | 2
   81 files changed, 1056 insertions(+), 381 deletions(-)

Modified: trunk/boost/asio/basic_datagram_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_datagram_socket.hpp (original)
+++ trunk/boost/asio/basic_datagram_socket.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -159,7 +159,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -187,7 +187,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -335,7 +335,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send_to(
         this->implementation, buffers, destination, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send_to");
     return s;
   }
 
@@ -362,7 +362,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send_to(
         this->implementation, buffers, destination, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send_to");
     return s;
   }
 
@@ -510,7 +510,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -539,7 +539,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -688,7 +688,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive_from(
         this->implementation, buffers, sender_endpoint, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
     return s;
   }
   
@@ -715,7 +715,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive_from(
         this->implementation, buffers, sender_endpoint, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
     return s;
   }
   

Modified: trunk/boost/asio/basic_deadline_timer.hpp
==============================================================================
--- trunk/boost/asio/basic_deadline_timer.hpp (original)
+++ trunk/boost/asio/basic_deadline_timer.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -162,7 +162,7 @@
   {
     boost::system::error_code ec;
     this->service.expires_at(this->implementation, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_at");
   }
 
   /// Constructor to set a particular expiry time relative to now.
@@ -181,7 +181,7 @@
   {
     boost::system::error_code ec;
     this->service.expires_from_now(this->implementation, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_from_now");
   }
 
   /// Cancel any asynchronous operations that are waiting on the timer.
@@ -210,7 +210,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
     return s;
   }
 
@@ -269,7 +269,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.cancel_one(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel_one");
     return s;
   }
 
@@ -339,7 +339,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.expires_at(
         this->implementation, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_at");
     return s;
   }
 
@@ -408,7 +408,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.expires_from_now(
         this->implementation, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_from_now");
     return s;
   }
 
@@ -452,7 +452,7 @@
   {
     boost::system::error_code ec;
     this->service.wait(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "wait");
   }
 
   /// Perform a blocking wait on the timer.

Modified: trunk/boost/asio/basic_raw_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_raw_socket.hpp (original)
+++ trunk/boost/asio/basic_raw_socket.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -158,7 +158,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -185,7 +185,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -330,7 +330,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send_to(
         this->implementation, buffers, destination, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send_to");
     return s;
   }
 
@@ -357,7 +357,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send_to(
         this->implementation, buffers, destination, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send_to");
     return s;
   }
 
@@ -505,7 +505,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -534,7 +534,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -683,7 +683,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive_from(
         this->implementation, buffers, sender_endpoint, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
     return s;
   }
   
@@ -710,7 +710,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive_from(
         this->implementation, buffers, sender_endpoint, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
     return s;
   }
   

Modified: trunk/boost/asio/basic_seq_packet_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_seq_packet_socket.hpp (original)
+++ trunk/boost/asio/basic_seq_packet_socket.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -166,7 +166,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -276,7 +276,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, 0, out_flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -323,7 +323,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, in_flags, out_flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 

Modified: trunk/boost/asio/basic_serial_port.hpp
==============================================================================
--- trunk/boost/asio/basic_serial_port.hpp (original)
+++ trunk/boost/asio/basic_serial_port.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -88,7 +88,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, device, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Construct and open a basic_serial_port.
@@ -108,7 +108,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, device, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Construct a basic_serial_port on an existing native serial port.
@@ -129,7 +129,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, native_serial_port, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Get a reference to the lowest layer.
@@ -172,7 +172,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, device, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Open the serial port using the specified device name.
@@ -202,7 +202,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, native_serial_port, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Assign an existing native serial port to the serial port.
@@ -237,7 +237,7 @@
   {
     boost::system::error_code ec;
     this->service.close(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "close");
   }
 
   /// Close the serial port.
@@ -288,7 +288,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all asynchronous operations associated with the serial port.
@@ -315,7 +315,7 @@
   {
     boost::system::error_code ec;
     this->service.send_break(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send_break");
   }
 
   /// Send a break sequence to the serial port.
@@ -350,7 +350,7 @@
   {
     boost::system::error_code ec;
     this->service.set_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "set_option");
   }
 
   /// Set an option on the serial port.
@@ -396,7 +396,7 @@
   {
     boost::system::error_code ec;
     this->service.get_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "get_option");
   }
 
   /// Get an option from the serial port.
@@ -454,7 +454,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.write_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_some");
     return s;
   }
 
@@ -561,7 +561,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.read_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_some");
     return s;
   }
 

Modified: trunk/boost/asio/basic_signal_set.hpp
==============================================================================
--- trunk/boost/asio/basic_signal_set.hpp (original)
+++ trunk/boost/asio/basic_signal_set.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -125,7 +125,7 @@
   {
     boost::system::error_code ec;
     this->service.add(this->implementation, signal_number_1, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
   }
 
   /// Construct a signal set and add two signals.
@@ -150,9 +150,9 @@
   {
     boost::system::error_code ec;
     this->service.add(this->implementation, signal_number_1, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
     this->service.add(this->implementation, signal_number_2, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
   }
 
   /// Construct a signal set and add three signals.
@@ -180,11 +180,11 @@
   {
     boost::system::error_code ec;
     this->service.add(this->implementation, signal_number_1, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
     this->service.add(this->implementation, signal_number_2, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
     this->service.add(this->implementation, signal_number_3, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
   }
 
   /// Add a signal to a signal_set.
@@ -200,7 +200,7 @@
   {
     boost::system::error_code ec;
     this->service.add(this->implementation, signal_number, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "add");
   }
 
   /// Add a signal to a signal_set.
@@ -234,7 +234,7 @@
   {
     boost::system::error_code ec;
     this->service.remove(this->implementation, signal_number, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "remove");
   }
 
   /// Remove a signal from a signal_set.
@@ -268,7 +268,7 @@
   {
     boost::system::error_code ec;
     this->service.clear(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "clear");
   }
 
   /// Remove all signals from a signal_set.
@@ -310,7 +310,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all operations associated with the signal set.

Modified: trunk/boost/asio/basic_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_socket.hpp (original)
+++ trunk/boost/asio/basic_socket.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -87,7 +87,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, protocol, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Construct a basic_socket, opening it and binding it to the given local
@@ -111,9 +111,9 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, endpoint.protocol(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
     this->service.bind(this->implementation, endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "bind");
   }
 
   /// Construct a basic_socket on an existing native socket.
@@ -135,7 +135,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, protocol, native_socket, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Get a reference to the lowest layer.
@@ -184,7 +184,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, protocol, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Open the socket using the specified protocol.
@@ -227,7 +227,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, protocol, native_socket, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Assign an existing native socket to the socket.
@@ -259,7 +259,8 @@
    * or connect operations will be cancelled immediately, and will complete
    * with the boost::asio::error::operation_aborted error.
    *
- * @throws boost::system::system_error Thrown on failure.
+ * @throws boost::system::system_error Thrown on failure. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
    *
    * @note For portable behaviour with respect to graceful closure of a
    * connected socket, call shutdown() before closing the socket.
@@ -268,7 +269,7 @@
   {
     boost::system::error_code ec;
     this->service.close(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "close");
   }
 
   /// Close the socket.
@@ -277,7 +278,8 @@
    * or connect operations will be cancelled immediately, and will complete
    * with the boost::asio::error::operation_aborted error.
    *
- * @param ec Set to indicate what error occurred, if any.
+ * @param ec Set to indicate what error occurred, if any. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
    *
    * @par Example
    * @code
@@ -366,7 +368,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all asynchronous operations associated with the socket.
@@ -429,7 +431,7 @@
   {
     boost::system::error_code ec;
     bool b = this->service.at_mark(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "at_mark");
     return b;
   }
 
@@ -462,7 +464,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.available(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "available");
     return s;
   }
 
@@ -503,7 +505,7 @@
   {
     boost::system::error_code ec;
     this->service.bind(this->implementation, endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "bind");
   }
 
   /// Bind the socket to the given local endpoint.
@@ -564,10 +566,10 @@
     if (!is_open())
     {
       this->service.open(this->implementation, peer_endpoint.protocol(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
     }
     this->service.connect(this->implementation, peer_endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
   }
 
   /// Connect the socket to the specified endpoint.
@@ -716,7 +718,7 @@
   {
     boost::system::error_code ec;
     this->service.set_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "set_option");
   }
 
   /// Set an option on the socket.
@@ -805,7 +807,7 @@
   {
     boost::system::error_code ec;
     this->service.get_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "get_option");
   }
 
   /// Get an option from the socket.
@@ -882,7 +884,7 @@
   {
     boost::system::error_code ec;
     this->service.io_control(this->implementation, command, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "io_control");
   }
 
   /// Perform an IO control command on the socket.
@@ -952,7 +954,7 @@
   {
     boost::system::error_code ec;
     this->service.non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
   }
 
   /// Sets the non-blocking mode of the socket.
@@ -1152,7 +1154,7 @@
   {
     boost::system::error_code ec;
     this->service.native_non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
   }
 
   /// Sets the non-blocking mode of the native socket implementation.
@@ -1265,7 +1267,7 @@
   {
     boost::system::error_code ec;
     endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "local_endpoint");
     return ep;
   }
 
@@ -1314,7 +1316,7 @@
   {
     boost::system::error_code ec;
     endpoint_type ep = this->service.remote_endpoint(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "remote_endpoint");
     return ep;
   }
 
@@ -1365,7 +1367,7 @@
   {
     boost::system::error_code ec;
     this->service.shutdown(this->implementation, what, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "shutdown");
   }
 
   /// Disable sends or receives on the socket.

Modified: trunk/boost/asio/basic_socket_acceptor.hpp
==============================================================================
--- trunk/boost/asio/basic_socket_acceptor.hpp (original)
+++ trunk/boost/asio/basic_socket_acceptor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -102,7 +102,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, protocol, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Construct an acceptor opened on the given endpoint.
@@ -138,18 +138,18 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, endpoint.protocol(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
     if (reuse_addr)
     {
       this->service.set_option(this->implementation,
           socket_base::reuse_address(true), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "set_option");
     }
     this->service.bind(this->implementation, endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "bind");
     this->service.listen(this->implementation,
         socket_base::max_connections, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "listen");
   }
 
   /// Construct a basic_socket_acceptor on an existing native acceptor.
@@ -173,7 +173,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, protocol, native_acceptor, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Open the acceptor using the specified protocol.
@@ -195,7 +195,7 @@
   {
     boost::system::error_code ec;
     this->service.open(this->implementation, protocol, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "open");
   }
 
   /// Open the acceptor using the specified protocol.
@@ -239,7 +239,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, protocol, native_acceptor, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Assigns an existing native acceptor to the acceptor.
@@ -286,7 +286,7 @@
   {
     boost::system::error_code ec;
     this->service.bind(this->implementation, endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "bind");
   }
 
   /// Bind the acceptor to the given local endpoint.
@@ -331,7 +331,7 @@
   {
     boost::system::error_code ec;
     this->service.listen(this->implementation, backlog, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "listen");
   }
 
   /// Place the acceptor into the state where it will listen for new
@@ -375,7 +375,7 @@
   {
     boost::system::error_code ec;
     this->service.close(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "close");
   }
 
   /// Close the acceptor.
@@ -439,7 +439,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all asynchronous operations associated with the acceptor.
@@ -481,7 +481,7 @@
   {
     boost::system::error_code ec;
     this->service.set_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "set_option");
   }
 
   /// Set an option on the acceptor.
@@ -544,7 +544,7 @@
   {
     boost::system::error_code ec;
     this->service.get_option(this->implementation, option, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "get_option");
   }
 
   /// Get an option from the acceptor.
@@ -606,7 +606,7 @@
   {
     boost::system::error_code ec;
     this->service.io_control(this->implementation, command, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "io_control");
   }
 
   /// Perform an IO control command on the acceptor.
@@ -674,7 +674,7 @@
   {
     boost::system::error_code ec;
     this->service.non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
   }
 
   /// Sets the non-blocking mode of the acceptor.
@@ -734,7 +734,7 @@
   {
     boost::system::error_code ec;
     this->service.native_non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
   }
 
   /// Sets the non-blocking mode of the native acceptor implementation.
@@ -777,7 +777,7 @@
   {
     boost::system::error_code ec;
     endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "local_endpoint");
     return ep;
   }
 
@@ -831,7 +831,7 @@
   {
     boost::system::error_code ec;
     this->service.accept(this->implementation, peer, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "accept");
   }
 
   /// Accept a new connection.
@@ -944,7 +944,7 @@
   {
     boost::system::error_code ec;
     this->service.accept(this->implementation, peer, &peer_endpoint, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "accept");
   }
 
   /// Accept a new connection and obtain the endpoint of the peer

Modified: trunk/boost/asio/basic_socket_streambuf.hpp
==============================================================================
--- trunk/boost/asio/basic_socket_streambuf.hpp (original)
+++ trunk/boost/asio/basic_socket_streambuf.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -223,7 +223,7 @@
 
     boost::system::error_code ec;
     timer_service_->expires_at(timer_implementation_, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_at");
 
     start_timer();
   }
@@ -252,7 +252,7 @@
 
     boost::system::error_code ec;
     timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "expires_from_now");
 
     start_timer();
   }

Modified: trunk/boost/asio/basic_stream_socket.hpp
==============================================================================
--- trunk/boost/asio/basic_stream_socket.hpp (original)
+++ trunk/boost/asio/basic_stream_socket.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -164,7 +164,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send(
         this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -202,7 +202,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.send(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "send");
     return s;
   }
 
@@ -359,7 +359,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -400,7 +400,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.receive(
         this->implementation, buffers, flags, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "receive");
     return s;
   }
 
@@ -560,7 +560,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_some");
     return s;
   }
 
@@ -667,7 +667,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_some");
     return s;
   }
 

Modified: trunk/boost/asio/datagram_socket_service.hpp
==============================================================================
--- trunk/boost/asio/datagram_socket_service.hpp (original)
+++ trunk/boost/asio/datagram_socket_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -90,12 +90,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new datagram socket implementation.
   void construct(implementation_type& impl)
   {
@@ -340,6 +334,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/deadline_timer_service.hpp
==============================================================================
--- trunk/boost/asio/deadline_timer_service.hpp (original)
+++ trunk/boost/asio/deadline_timer_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -72,12 +72,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new timer implementation.
   void construct(implementation_type& impl)
   {
@@ -143,6 +137,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/detail/dev_poll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/dev_poll_reactor.hpp (original)
+++ trunk/boost/asio/detail/dev_poll_reactor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -64,6 +64,10 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Recreate internal descriptors following a fork.
+ BOOST_ASIO_DECL void fork_service(
+ boost::asio::io_service::fork_event event);
+
   // Initialise the task.
   BOOST_ASIO_DECL void init_task();
 
@@ -98,6 +102,11 @@
   BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor,
       per_descriptor_data&, bool closing);
 
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ BOOST_ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data&);
+
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
   void add_timer_queue(timer_queue<Time_Traits>& queue);
@@ -148,6 +157,10 @@
   BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
       const boost::system::error_code& ec);
 
+ // Helper class used to reregister descriptors after a fork.
+ class fork_helper;
+ friend class fork_helper;
+
   // Add a pending event entry for the given descriptor.
   BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
 

Modified: trunk/boost/asio/detail/epoll_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/epoll_reactor.hpp (original)
+++ trunk/boost/asio/detail/epoll_reactor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -52,6 +52,7 @@
     friend class epoll_reactor;
     friend class object_pool_access;
     mutex mutex_;
+ int descriptor_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
     descriptor_state* next_;
@@ -70,6 +71,10 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Recreate internal descriptors following a fork.
+ BOOST_ASIO_DECL void fork_service(
+ boost::asio::io_service::fork_event event);
+
   // Initialise the task.
   BOOST_ASIO_DECL void init_task();
 
@@ -107,6 +112,10 @@
   BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor,
       per_descriptor_data& descriptor_data, bool closing);
 
+ // Remote the descriptor's registration from the reactor.
+ BOOST_ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data& descriptor_data);
+
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
   void add_timer_queue(timer_queue<Time_Traits>& timer_queue);

Modified: trunk/boost/asio/detail/eventfd_select_interrupter.hpp
==============================================================================
--- trunk/boost/asio/detail/eventfd_select_interrupter.hpp (original)
+++ trunk/boost/asio/detail/eventfd_select_interrupter.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -35,6 +35,9 @@
   // Destructor.
   BOOST_ASIO_DECL ~eventfd_select_interrupter();
 
+ // Recreate the interrupter's descriptors. Used after a fork.
+ BOOST_ASIO_DECL void recreate();
+
   // Interrupt the select call.
   BOOST_ASIO_DECL void interrupt();
 
@@ -48,6 +51,12 @@
   }
 
 private:
+ // Open the descriptors. Throws on error.
+ BOOST_ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ BOOST_ASIO_DECL void close_descriptors();
+
   // The read end of a connection used to interrupt the select call. This file
   // descriptor is passed to select such that when it is time to stop, a single
   // 64bit value will be written on the other end of the connection and this

Modified: trunk/boost/asio/detail/impl/descriptor_ops.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/descriptor_ops.ipp (original)
+++ trunk/boost/asio/detail/impl/descriptor_ops.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -43,8 +43,19 @@
   int result = 0;
   if (d != -1)
   {
- if (state & internal_non_blocking)
+ errno = 0;
+ result = error_wrapper(::close(d), ec);
+
+ if (result != 0
+ && (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again))
     {
+ // According to UNIX Network Programming Vol. 1, it is possible for
+ // close() to fail with EWOULDBLOCK under certain circumstances. What
+ // isn't clear is the state of the descriptor after this error. The one
+ // current OS where this behaviour is seen, Windows, says that the socket
+ // remains open. Therefore we'll put the descriptor back into blocking
+ // mode and have another attempt at closing it.
 #if defined(__SYMBIAN32__)
       int flags = ::fcntl(d, F_GETFL, 0);
       if (flags >= 0)
@@ -53,11 +64,11 @@
       ioctl_arg_type arg = 0;
       ::ioctl(d, FIONBIO, &arg);
 #endif // defined(__SYMBIAN32__)
- state &= ~internal_non_blocking;
- }
+ state &= ~non_blocking;
 
- errno = 0;
- result = error_wrapper(::close(d), ec);
+ errno = 0;
+ result = error_wrapper(::close(d), ec);
+ }
   }
 
   if (result == 0)

Modified: trunk/boost/asio/detail/impl/dev_poll_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/dev_poll_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/dev_poll_reactor.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -19,6 +19,7 @@
 
 #if defined(BOOST_ASIO_HAS_DEV_POLL)
 
+#include <boost/assert.hpp>
 #include <boost/asio/detail/dev_poll_reactor.hpp>
 #include <boost/asio/detail/throw_error.hpp>
 #include <boost/asio/error.hpp>
@@ -38,7 +39,7 @@
     shutdown_(false)
 {
   // Add the interrupter's descriptor to /dev/poll.
- ::pollfd ev = { 0 };
+ ::pollfd ev = { 0, 0, 0 };
   ev.fd = interrupter_.read_descriptor();
   ev.events = POLLIN | POLLERR;
   ev.revents = 0;
@@ -65,6 +66,64 @@
   timer_queues_.get_all_timers(ops);
 }
 
+// Helper class to re-register all descriptors with /dev/poll.
+class dev_poll_reactor::fork_helper
+{
+public:
+ fork_helper(dev_poll_reactor* reactor, short events)
+ : reactor_(reactor), events_(events)
+ {
+ }
+
+ bool set(int descriptor)
+ {
+ ::pollfd& ev = reactor_->add_pending_event_change(descriptor);
+ ev.events = events_;
+ return true;
+ }
+
+private:
+ dev_poll_reactor* reactor_;
+ short events_;
+};
+
+void dev_poll_reactor::fork_service(boost::asio::io_service::fork_event event)
+{
+ if (event == boost::asio::io_service::fork_child)
+ {
+ detail::mutex::scoped_lock lock(mutex_);
+
+ if (dev_poll_fd_ != -1)
+ ::close(dev_poll_fd_);
+ dev_poll_fd_ = -1;
+ dev_poll_fd_ = do_dev_poll_create();
+
+ interrupter_.recreate();
+
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+ // Re-register all descriptors with /dev/poll. The changes will be written
+ // to the /dev/poll descriptor the next time the reactor is run.
+ op_queue<operation> ops;
+ fork_helper read_op_helper(this, POLLERR | POLLHUP | POLLIN);
+ op_queue_[read_op].get_descriptors(read_op_helper, ops);
+ fork_helper write_op_helper(this, POLLERR | POLLHUP | POLLOUT);
+ op_queue_[write_op].get_descriptors(write_op_helper, ops);
+ fork_helper except_op_helper(this, POLLERR | POLLHUP | POLLPRI);
+ op_queue_[except_op].get_descriptors(except_op_helper, ops);
+ interrupter_.interrupt();
+
+ // The ops op_queue will always be empty because the fork_helper's set()
+ // member function never returns false.
+ BOOST_ASSERT(ops.empty());
+ }
+}
+
 void dev_poll_reactor::init_task()
 {
   io_service_.init_task();
@@ -163,6 +222,26 @@
   cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
 }
 
+void dev_poll_reactor::deregister_internal_descriptor(
+ socket_type descriptor, dev_poll_reactor::per_descriptor_data&)
+{
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from /dev/poll. Since this function is only called
+ // during a fork, we can apply the change immediately.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+ // Destroy all operations associated with the descriptor.
+ op_queue<operation> ops;
+ boost::system::error_code ec;
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].cancel_operations(descriptor, ops, ec);
+}
+
 void dev_poll_reactor::run(bool block, op_queue<operation>& ops)
 {
   boost::asio::detail::mutex::scoped_lock lock(mutex_);
@@ -199,8 +278,8 @@
   lock.unlock();
 
   // Block on the /dev/poll descriptor.
- ::pollfd events[128] = { { 0 } };
- ::dvpoll dp = { 0 };
+ ::pollfd events[128] = { { 0, 0, 0 } };
+ ::dvpoll dp = { 0, 0, 0 };
   dp.dp_fds = events;
   dp.dp_nfds = 128;
   dp.dp_timeout = timeout;
@@ -248,7 +327,7 @@
         // The poll operation can produce POLLHUP or POLLERR events when there
         // is no operation pending, so if we do not remove the descriptor we
         // can end up in a tight polling loop.
- ::pollfd ev = { 0 };
+ ::pollfd ev = { 0, 0, 0 };
         ev.fd = descriptor;
         ev.events = POLLREMOVE;
         ev.revents = 0;
@@ -256,7 +335,7 @@
       }
       else
       {
- ::pollfd ev = { 0 };
+ ::pollfd ev = { 0, 0, 0 };
         ev.fd = descriptor;
         ev.events = POLLERR | POLLHUP;
         if (more_reads)

Modified: trunk/boost/asio/detail/impl/epoll_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/epoll_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/epoll_reactor.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -62,7 +62,8 @@
 
 epoll_reactor::~epoll_reactor()
 {
- close(epoll_fd_);
+ if (epoll_fd_ != -1)
+ close(epoll_fd_);
   if (timer_fd_ != -1)
     close(timer_fd_);
 }
@@ -86,6 +87,57 @@
   timer_queues_.get_all_timers(ops);
 }
 
+void epoll_reactor::fork_service(boost::asio::io_service::fork_event event)
+{
+ if (event == boost::asio::io_service::fork_child)
+ {
+ if (epoll_fd_ != -1)
+ ::close(epoll_fd_);
+ epoll_fd_ = -1;
+ epoll_fd_ = do_epoll_create();
+
+ if (timer_fd_ != -1)
+ ::close(timer_fd_);
+ timer_fd_ = -1;
+ timer_fd_ = do_timerfd_create();
+
+ interrupter_.recreate();
+
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ interrupter_.interrupt();
+
+ // Add the timer descriptor to epoll.
+ if (timer_fd_ != -1)
+ {
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.ptr = &timer_fd_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+ }
+
+ update_timeout();
+
+ // Re-register all descriptors with epoll.
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ for (descriptor_state* state = registered_descriptors_.first();
+ state != 0; state = state->next_)
+ {
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
+ ev.data.ptr = state;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev);
+ if (result != 0)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ boost::asio::detail::throw_error(ec, "epoll re-registration");
+ }
+ }
+ }
+}
+
 void epoll_reactor::init_task()
 {
   io_service_.init_task();
@@ -97,6 +149,7 @@
   mutex::scoped_lock lock(registered_descriptors_mutex_);
 
   descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
 
   lock.unlock();
@@ -118,20 +171,14 @@
   mutex::scoped_lock lock(registered_descriptors_mutex_);
 
   descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
   descriptor_data->op_queue_[op_type].push(op);
 
   lock.unlock();
 
   epoll_event ev = { 0, { 0 } };
- ev.events = EPOLLERR | EPOLLHUP | EPOLLET;
- switch (op_type)
- {
- case read_op: ev.events |= EPOLLIN; break;
- case write_op: ev.events |= EPOLLOUT; break;
- case except_op: ev.events |= EPOLLPRI; break;
- default: break;
- };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET;
   ev.data.ptr = descriptor_data;
   int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
   if (result != 0)
@@ -243,6 +290,7 @@
       }
     }
 
+ descriptor_data->descriptor_ = -1;
     descriptor_data->shutdown_ = true;
 
     descriptor_lock.unlock();
@@ -256,6 +304,36 @@
   }
 }
 
+void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(descriptor_data->op_queue_[i]);
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ registered_descriptors_.free(descriptor_data);
+ descriptor_data = 0;
+
+ descriptors_lock.unlock();
+ }
+}
+
 void epoll_reactor::run(bool block, op_queue<operation>& ops)
 {
   // Calculate a timeout only if timerfd is not used.

Modified: trunk/boost/asio/detail/impl/eventfd_select_interrupter.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/eventfd_select_interrupter.ipp (original)
+++ trunk/boost/asio/detail/impl/eventfd_select_interrupter.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -40,6 +40,11 @@
 
 eventfd_select_interrupter::eventfd_select_interrupter()
 {
+ open_descriptors();
+}
+
+void eventfd_select_interrupter::open_descriptors()
+{
 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
   write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
   if (read_descriptor_ != -1)
@@ -89,12 +94,27 @@
 
 eventfd_select_interrupter::~eventfd_select_interrupter()
 {
+ close_descriptors();
+}
+
+void eventfd_select_interrupter::close_descriptors()
+{
   if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
     ::close(write_descriptor_);
   if (read_descriptor_ != -1)
     ::close(read_descriptor_);
 }
 
+void eventfd_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = -1;
+ read_descriptor_ = -1;
+
+ open_descriptors();
+}
+
 void eventfd_select_interrupter::interrupt()
 {
   uint64_t counter(1UL);

Modified: trunk/boost/asio/detail/impl/kqueue_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/kqueue_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/kqueue_reactor.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -47,9 +47,9 @@
     interrupter_(),
     shutdown_(false)
 {
- // The interrupter is put into a permanently readable state. Whenever we
- // want to interrupt the blocked kevent call we register a one-shot read
- // operation against the descriptor.
+ // The interrupter is put into a permanently readable state. Whenever we want
+ // to interrupt the blocked kevent call we register a read operation against
+ // the descriptor.
   interrupter_.interrupt();
 }
 
@@ -77,17 +77,57 @@
   timer_queues_.get_all_timers(ops);
 }
 
+void kqueue_reactor::fork_service(boost::asio::io_service::fork_event event)
+{
+ if (event == boost::asio::io_service::fork_child)
+ {
+ // The kqueue descriptor is automatically closed in the child.
+ kqueue_fd_ = -1;
+ kqueue_fd_ = do_kqueue_create();
+
+ interrupter_.recreate();
+
+ // Re-register all descriptors with kqueue.
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ for (descriptor_state* state = registered_descriptors_.first();
+ state != 0; state = state->next_)
+ {
+ struct kevent events[2];
+ int num_events = 0;
+
+ if (!state->op_queue_[read_op].empty())
+ BOOST_ASIO_KQUEUE_EV_SET(&events[num_events++], state->descriptor_,
+ EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state);
+ else if (!state->op_queue_[except_op].empty())
+ BOOST_ASIO_KQUEUE_EV_SET(&events[num_events++], state->descriptor_,
+ EVFILT_READ, EV_ADD | EV_CLEAR, EV_OOBAND, 0, state);
+
+ if (!state->op_queue_[write_op].empty())
+ BOOST_ASIO_KQUEUE_EV_SET(&events[num_events++], state->descriptor_,
+ EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state);
+
+ if (num_events && ::kevent(kqueue_fd_, events, num_events, 0, 0, 0) == -1)
+ {
+ boost::system::error_code error(errno,
+ boost::asio::error::get_system_category());
+ boost::asio::detail::throw_error(error);
+ }
+ }
+ }
+}
+
 void kqueue_reactor::init_task()
 {
   io_service_.init_task();
 }
 
-int kqueue_reactor::register_descriptor(socket_type,
+int kqueue_reactor::register_descriptor(socket_type descriptor,
     kqueue_reactor::per_descriptor_data& descriptor_data)
 {
   mutex::scoped_lock lock(registered_descriptors_mutex_);
 
   descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
 
   return 0;
@@ -100,6 +140,7 @@
   mutex::scoped_lock lock(registered_descriptors_mutex_);
 
   descriptor_data = registered_descriptors_.alloc();
+ descriptor_data->descriptor_ = descriptor;
   descriptor_data->shutdown_ = false;
   descriptor_data->op_queue_[op_type].push(op);
 
@@ -108,15 +149,15 @@
   {
   case read_op:
     BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
     break;
   case write_op:
     BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
     break;
   case except_op:
     BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, EV_OOBAND, 0, descriptor_data);
     break;
   }
   ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
@@ -170,17 +211,17 @@
     {
     case read_op:
       BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
       break;
     case write_op:
       BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
       break;
     case except_op:
       if (!descriptor_data->op_queue_[read_op].empty())
         return; // Already registered for read events.
       BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, EV_OOBAND, 0, descriptor_data);
       break;
     }
 
@@ -255,6 +296,7 @@
       }
     }
 
+ descriptor_data->descriptor_ = -1;
     descriptor_data->shutdown_ = true;
 
     descriptor_lock.unlock();
@@ -268,6 +310,40 @@
   }
 }
 
+void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ struct kevent events[2];
+ BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor,
+ EVFILT_READ, EV_DELETE, 0, 0, 0);
+ BOOST_ASIO_KQUEUE_EV_SET(&events[1], descriptor,
+ EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, events, 2, 0, 0, 0);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(descriptor_data->op_queue_[i]);
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ registered_descriptors_.free(descriptor_data);
+ descriptor_data = 0;
+
+ descriptors_lock.unlock();
+ }
+}
+
 void kqueue_reactor::run(bool block, op_queue<operation>& ops)
 {
   mutex::scoped_lock lock(mutex_);
@@ -290,7 +366,7 @@
     if (ptr == &interrupter_)
     {
       // No need to reset the interrupter since we're leaving the descriptor
- // in a ready-to-read state and relying on one-shot notifications.
+ // in a ready-to-read state and relying on edge-triggered notifications.
     }
     else
     {
@@ -339,17 +415,17 @@
       case EVFILT_READ:
         if (!descriptor_data->op_queue_[read_op].empty())
           BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
         else if (!descriptor_data->op_queue_[except_op].empty())
           BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ,
- EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, EV_OOBAND, 0, descriptor_data);
         else
           continue;
         break;
       case EVFILT_WRITE:
         if (!descriptor_data->op_queue_[write_op].empty())
           BOOST_ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
- EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
         else
           continue;
         break;
@@ -381,7 +457,7 @@
 {
   struct kevent event;
   BOOST_ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(),
- EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_);
+ EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &interrupter_);
   ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
 }
 

Modified: trunk/boost/asio/detail/impl/pipe_select_interrupter.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/pipe_select_interrupter.ipp (original)
+++ trunk/boost/asio/detail/impl/pipe_select_interrupter.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -38,6 +38,11 @@
 
 pipe_select_interrupter::pipe_select_interrupter()
 {
+ open_descriptors();
+}
+
+void pipe_select_interrupter::open_descriptors()
+{
   int pipe_fds[2];
   if (pipe(pipe_fds) == 0)
   {
@@ -61,12 +66,27 @@
 
 pipe_select_interrupter::~pipe_select_interrupter()
 {
+ close_descriptors();
+}
+
+void pipe_select_interrupter::close_descriptors()
+{
   if (read_descriptor_ != -1)
     ::close(read_descriptor_);
   if (write_descriptor_ != -1)
     ::close(write_descriptor_);
 }
 
+void pipe_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = -1;
+ read_descriptor_ = -1;
+
+ open_descriptors();
+}
+
 void pipe_select_interrupter::interrupt()
 {
   char byte = 0;

Modified: trunk/boost/asio/detail/impl/reactive_descriptor_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/reactive_descriptor_service.ipp (original)
+++ trunk/boost/asio/detail/impl/reactive_descriptor_service.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -97,8 +97,15 @@
         (impl.state_ & descriptor_ops::possible_dup) == 0);
   }
 
- if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0)
- construct(impl);
+ descriptor_ops::close(impl.descriptor_, impl.state_, ec);
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour.)
+ construct(impl);
 
   return ec;
 }

Modified: trunk/boost/asio/detail/impl/reactive_socket_service_base.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/reactive_socket_service_base.ipp (original)
+++ trunk/boost/asio/detail/impl/reactive_socket_service_base.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -72,8 +72,17 @@
         (impl.state_ & socket_ops::possible_dup) == 0);
   }
 
- if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0)
- construct(impl);
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour. The
+ // known exception is when Windows's closesocket() function fails with
+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+ construct(impl);
 
   return ec;
 }

Modified: trunk/boost/asio/detail/impl/resolver_service_base.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/resolver_service_base.ipp (original)
+++ trunk/boost/asio/detail/impl/resolver_service_base.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -65,6 +65,25 @@
   }
 }
 
+void resolver_service_base::fork_service(
+ boost::asio::io_service::fork_event event)
+{
+ if (work_thread_)
+ {
+ if (event == boost::asio::io_service::fork_prepare)
+ {
+ work_io_service_->stop();
+ work_thread_->join();
+ }
+ else
+ {
+ work_io_service_->reset();
+ work_thread_.reset(new boost::asio::detail::thread(
+ work_io_service_runner(*work_io_service_)));
+ }
+ }
+}
+
 void resolver_service_base::construct(
     resolver_service_base::implementation_type& impl)
 {

Modified: trunk/boost/asio/detail/impl/select_reactor.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/select_reactor.ipp (original)
+++ trunk/boost/asio/detail/impl/select_reactor.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -84,6 +84,12 @@
   timer_queues_.get_all_timers(ops);
 }
 
+void select_reactor::fork_service(boost::asio::io_service::fork_event event)
+{
+ if (event == boost::asio::io_service::fork_child)
+ interrupter_.recreate();
+}
+
 void select_reactor::init_task()
 {
   io_service_.init_task();
@@ -138,6 +144,15 @@
   cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted);
 }
 
+void select_reactor::deregister_internal_descriptor(
+ socket_type descriptor, select_reactor::per_descriptor_data&)
+{
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].cancel_operations(descriptor, ops);
+}
+
 void select_reactor::run(bool block, op_queue<operation>& ops)
 {
   boost::asio::detail::mutex::scoped_lock lock(mutex_);

Modified: trunk/boost/asio/detail/impl/service_registry.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/service_registry.ipp (original)
+++ trunk/boost/asio/detail/impl/service_registry.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -17,6 +17,7 @@
 
 #include <boost/asio/detail/config.hpp>
 #include <boost/throw_exception.hpp>
+#include <vector>
 #include <boost/asio/detail/service_registry.hpp>
 
 #include <boost/asio/detail/push_options.hpp>
@@ -52,6 +53,35 @@
   }
 }
 
+void service_registry::notify_fork(boost::asio::io_service::fork_event event)
+{
+ // Make a copy of all of the services while holding the lock. We don't want
+ // to hold the lock while calling into each service, as it may try to call
+ // back into this class.
+ std::vector<boost::asio::io_service::service*> services;
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ boost::asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ services.push_back(service);
+ service = service->next_;
+ }
+ }
+
+ // If processing the fork_prepare event, we want to go in reverse order of
+ // service registration, which happens to be the existing order of the
+ // services in the vector. For the other events we want to go in the other
+ // direction.
+ std::size_t num_services = services.size();
+ if (event == boost::asio::io_service::fork_prepare)
+ for (std::size_t i = 0; i < num_services; ++i)
+ services[i]->fork_service(event);
+ else
+ for (std::size_t i = num_services; i > 0; --i)
+ services[i - 1]->fork_service(event);
+}
+
 void service_registry::init_key(boost::asio::io_service::service::key& key,
     const boost::asio::io_service::id& id)
 {

Modified: trunk/boost/asio/detail/impl/signal_set_service.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/signal_set_service.ipp (original)
+++ trunk/boost/asio/detail/impl/signal_set_service.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -17,9 +17,9 @@
 
 #include <boost/asio/detail/config.hpp>
 
-#include <signal.h>
 #include <cstring>
 #include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/signal_blocker.hpp>
 #include <boost/asio/detail/signal_set_service.hpp>
 #include <boost/asio/detail/static_mutex.hpp>
 
@@ -40,6 +40,9 @@
   // The write end of the pipe used for signal notifications.
   int write_descriptor_;
 
+ // Whether the signal state has been prepared for a fork.
+ bool fork_prepared_;
+
   // The head of a linked list of all signal_set_service instances.
   class signal_set_service* service_list_;
 
@@ -50,7 +53,7 @@
 signal_state* get_signal_state()
 {
   static signal_state state = {
- BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, 0, { 0 } };
+ BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
   return &state;
 }
 
@@ -69,6 +72,37 @@
 #endif // !defined(BOOST_ASIO_HAS_SIGACTION)
 }
 
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+class signal_set_service::pipe_read_op : public reactor_op
+{
+public:
+ pipe_read_op()
+ : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
+ {
+ }
+
+ static bool do_perform(reactor_op*)
+ {
+ signal_state* state = get_signal_state();
+
+ int fd = state->read_descriptor_;
+ int signal_number = 0;
+ while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
+ if (signal_number >= 0 && signal_number < max_signal_number)
+ signal_set_service::deliver_signal(signal_number);
+
+ return false;
+ }
+
+ static void do_complete(io_service_impl* /*owner*/, operation* base,
+ boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
+ {
+ pipe_read_op* o(static_cast<pipe_read_op*>(base));
+ delete o;
+ }
+};
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
 signal_set_service::signal_set_service(
     boost::asio::io_service& io_service)
   : io_service_(boost::asio::use_service<io_service_impl>(io_service)),
@@ -112,6 +146,43 @@
   }
 }
 
+void signal_set_service::fork_service(boost::asio::io_service::fork_event event)
+{
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ switch (event)
+ {
+ case boost::asio::io_service::fork_prepare:
+ reactor_.deregister_internal_descriptor(
+ state->read_descriptor_, reactor_data_);
+ state->fork_prepared_ = true;
+ break;
+ case boost::asio::io_service::fork_parent:
+ state->fork_prepared_ = false;
+ reactor_.register_internal_descriptor(reactor::read_op,
+ state->read_descriptor_, reactor_data_, new pipe_read_op);
+ break;
+ case boost::asio::io_service::fork_child:
+ if (state->fork_prepared_)
+ {
+ boost::asio::detail::signal_blocker blocker;
+ close_descriptors();
+ open_descriptors();
+ state->fork_prepared_ = false;
+ }
+ reactor_.register_internal_descriptor(reactor::read_op,
+ state->read_descriptor_, reactor_data_, new pipe_read_op);
+ break;
+ default:
+ break;
+ }
+#else // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ (void)event;
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+}
+
 void signal_set_service::construct(
     signal_set_service::implementation_type& impl)
 {
@@ -323,11 +394,16 @@
   BOOST_ASIO_HANDLER_OPERATION(("signal_set", &impl, "cancel"));
 
   op_queue<operation> ops;
- while (signal_op* op = impl.queue_.front())
   {
- op->ec_ = boost::asio::error::operation_aborted;
- impl.queue_.pop();
- ops.push(op);
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ while (signal_op* op = impl.queue_.front())
+ {
+ op->ec_ = boost::asio::error::operation_aborted;
+ impl.queue_.pop();
+ ops.push(op);
+ }
   }
 
   io_service_.post_deferred_completions(ops);
@@ -372,37 +448,6 @@
   }
 }
 
-#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-class signal_set_service::pipe_read_op : public reactor_op
-{
-public:
- pipe_read_op()
- : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
- {
- }
-
- static bool do_perform(reactor_op*)
- {
- signal_state* state = get_signal_state();
-
- int fd = state->read_descriptor_;
- int signal_number = 0;
- while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
- if (signal_number >= 0 && signal_number < max_signal_number)
- signal_set_service::deliver_signal(signal_number);
-
- return false;
- }
-
- static void do_complete(io_service_impl* /*owner*/, operation* base,
- boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/)
- {
- pipe_read_op* o(static_cast<pipe_read_op*>(base));
- delete o;
- }
-};
-#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
-
 void signal_set_service::add_service(signal_set_service* service)
 {
   signal_state* state = get_signal_state();
@@ -411,28 +456,7 @@
 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
   // If this is the first service to be created, open a new pipe.
   if (state->service_list_ == 0)
- {
- int pipe_fds[2];
- if (::pipe(pipe_fds) == 0)
- {
- state->read_descriptor_ = pipe_fds[0];
- ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
-
- state->write_descriptor_ = pipe_fds[1];
- ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
-
-#if defined(FD_CLOEXEC)
- ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
- ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
-#endif // defined(FD_CLOEXEC)
- }
- else
- {
- boost::system::error_code ec(errno,
- boost::asio::error::get_system_category());
- boost::asio::detail::throw_error(ec, "signal_set_service pipe");
- }
- }
+ open_descriptors();
 #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
 
   // Insert service into linked list of all services.
@@ -475,16 +499,54 @@
 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
     // If this is the last service to be removed, close the pipe.
     if (state->service_list_ == 0)
- {
- ::close(state->read_descriptor_);
- state->read_descriptor_ = -1;
- ::close(state->write_descriptor_);
- state->write_descriptor_ = -1;
- }
+ close_descriptors();
 #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
   }
 }
 
+void signal_set_service::open_descriptors()
+{
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+
+ int pipe_fds[2];
+ if (::pipe(pipe_fds) == 0)
+ {
+ state->read_descriptor_ = pipe_fds[0];
+ ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
+
+ state->write_descriptor_ = pipe_fds[1];
+ ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
+
+#if defined(FD_CLOEXEC)
+ ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
+ ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
+#endif // defined(FD_CLOEXEC)
+ }
+ else
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ boost::asio::detail::throw_error(ec, "signal_set_service pipe");
+ }
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+}
+
+void signal_set_service::close_descriptors()
+{
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+
+ if (state->read_descriptor_ != -1)
+ ::close(state->read_descriptor_);
+ state->read_descriptor_ = -1;
+
+ if (state->write_descriptor_ != -1)
+ ::close(state->write_descriptor_);
+ state->write_descriptor_ = -1;
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+}
+
 void signal_set_service::start_wait_op(
     signal_set_service::implementation_type& impl, signal_op* op)
 {

Modified: trunk/boost/asio/detail/impl/socket_ops.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/socket_ops.ipp (original)
+++ trunk/boost/asio/detail/impl/socket_ops.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -278,28 +278,9 @@
   int result = 0;
   if (s != invalid_socket)
   {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if ((state & non_blocking) && (state & user_set_linger))
- {
- ioctl_arg_type arg = 0;
- ::ioctlsocket(s, FIONBIO, &arg);
- state &= ~non_blocking;
- }
-#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- if (state & non_blocking)
- {
-#if defined(__SYMBIAN32__)
- int flags = ::fcntl(s, F_GETFL, 0);
- if (flags >= 0)
- ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
-#else // defined(__SYMBIAN32__)
- ioctl_arg_type arg = 0;
- ::ioctl(s, FIONBIO, &arg);
-#endif // defined(__SYMBIAN32__)
- state &= ~non_blocking;
- }
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
+ // We don't want the destructor to block, so set the socket to linger in
+ // the background. If the user doesn't like this behaviour then they need
+ // to explicitly close the socket.
     if (destruction && (state & user_set_linger))
     {
       ::linger opt;
@@ -316,6 +297,32 @@
 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
     result = error_wrapper(::close(s), ec);
 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+ if (result != 0
+ && (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again))
+ {
+ // According to UNIX Network Programming Vol. 1, it is possible for
+ // close() to fail with EWOULDBLOCK under certain circumstances. What
+ // isn't clear is the state of the descriptor after this error. The one
+ // current OS where this behaviour is seen, Windows, says that the socket
+ // remains open. Therefore we'll put the descriptor back into blocking
+ // mode and have another attempt at closing it.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ ioctl_arg_type arg = 0;
+ ::ioctlsocket(s, FIONBIO, &arg);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(__SYMBIAN32__)
+ int flags = ::fcntl(s, F_GETFL, 0);
+ if (flags >= 0)
+ ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
+# else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 0;
+ ::ioctl(s, FIONBIO, &arg);
+# endif // defined(__SYMBIAN32__)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ state &= ~non_blocking;
+ }
   }
 
   if (result == 0)

Modified: trunk/boost/asio/detail/impl/socket_select_interrupter.ipp
==============================================================================
--- trunk/boost/asio/detail/impl/socket_select_interrupter.ipp (original)
+++ trunk/boost/asio/detail/impl/socket_select_interrupter.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -36,6 +36,11 @@
 
 socket_select_interrupter::socket_select_interrupter()
 {
+ open_descriptors();
+}
+
+void socket_select_interrupter::open_descriptors()
+{
   boost::system::error_code ec;
   socket_holder acceptor(socket_ops::socket(
         AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
@@ -110,6 +115,11 @@
 
 socket_select_interrupter::~socket_select_interrupter()
 {
+ close_descriptors();
+}
+
+void socket_select_interrupter::close_descriptors()
+{
   boost::system::error_code ec;
   socket_ops::state_type state = socket_ops::internal_non_blocking;
   if (read_descriptor_ != invalid_socket)
@@ -118,6 +128,16 @@
     socket_ops::close(write_descriptor_, state, true, ec);
 }
 
+void socket_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = invalid_socket;
+ read_descriptor_ = invalid_socket;
+
+ open_descriptors();
+}
+
 void socket_select_interrupter::interrupt()
 {
   char byte = 0;

Modified: trunk/boost/asio/detail/kqueue_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/kqueue_reactor.hpp (original)
+++ trunk/boost/asio/detail/kqueue_reactor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -63,6 +63,7 @@
     friend class kqueue_reactor;
     friend class object_pool_access;
     mutex mutex_;
+ int descriptor_;
     op_queue<reactor_op> op_queue_[max_ops];
     bool shutdown_;
     descriptor_state* next_;
@@ -81,6 +82,10 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Recreate internal descriptors following a fork.
+ BOOST_ASIO_DECL void fork_service(
+ boost::asio::io_service::fork_event event);
+
   // Initialise the task.
   BOOST_ASIO_DECL void init_task();
 
@@ -118,6 +123,10 @@
   BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor,
       per_descriptor_data& descriptor_data, bool closing);
 
+ // Remote the descriptor's registration from the reactor.
+ BOOST_ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data& descriptor_data);
+
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
   void add_timer_queue(timer_queue<Time_Traits>& queue);

Modified: trunk/boost/asio/detail/pipe_select_interrupter.hpp
==============================================================================
--- trunk/boost/asio/detail/pipe_select_interrupter.hpp (original)
+++ trunk/boost/asio/detail/pipe_select_interrupter.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -37,6 +37,9 @@
   // Destructor.
   BOOST_ASIO_DECL ~pipe_select_interrupter();
 
+ // Recreate the interrupter's descriptors. Used after a fork.
+ BOOST_ASIO_DECL void recreate();
+
   // Interrupt the select call.
   BOOST_ASIO_DECL void interrupt();
 
@@ -50,6 +53,12 @@
   }
 
 private:
+ // Open the descriptors. Throws on error.
+ BOOST_ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ BOOST_ASIO_DECL void close_descriptors();
+
   // The read end of a connection used to interrupt the select call. This file
   // descriptor is passed to select such that when it is time to stop, a single
   // byte will be written on the other end of the connection and this

Modified: trunk/boost/asio/detail/resolver_service_base.hpp
==============================================================================
--- trunk/boost/asio/detail/resolver_service_base.hpp (original)
+++ trunk/boost/asio/detail/resolver_service_base.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -48,6 +48,9 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Perform any fork-related housekeeping.
+ BOOST_ASIO_DECL void fork_service(boost::asio::io_service::fork_event event);
+
   // Construct a new resolver implementation.
   BOOST_ASIO_DECL void construct(implementation_type& impl);
 

Modified: trunk/boost/asio/detail/select_reactor.hpp
==============================================================================
--- trunk/boost/asio/detail/select_reactor.hpp (original)
+++ trunk/boost/asio/detail/select_reactor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -73,6 +73,10 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Recreate internal descriptors following a fork.
+ BOOST_ASIO_DECL void fork_service(
+ boost::asio::io_service::fork_event event);
+
   // Initialise the task, but only if the reactor is not in its own thread.
   BOOST_ASIO_DECL void init_task();
 
@@ -107,6 +111,10 @@
   BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor,
       per_descriptor_data&, bool closing);
 
+ // Remote the descriptor's registration from the reactor.
+ BOOST_ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data& descriptor_data);
+
   // Add a new timer queue to the reactor.
   template <typename Time_Traits>
   void add_timer_queue(timer_queue<Time_Traits>& queue);

Modified: trunk/boost/asio/detail/service_registry.hpp
==============================================================================
--- trunk/boost/asio/detail/service_registry.hpp (original)
+++ trunk/boost/asio/detail/service_registry.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -58,6 +58,9 @@
   // Destructor.
   BOOST_ASIO_DECL ~service_registry();
 
+ // Notify all services of a fork event.
+ BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event event);
+
   // Get the service object corresponding to the specified service type. Will
   // create a new service object automatically if no such object already
   // exists. Ownership of the service object is not transferred to the caller.

Modified: trunk/boost/asio/detail/signal_set_service.hpp
==============================================================================
--- trunk/boost/asio/detail/signal_set_service.hpp (original)
+++ trunk/boost/asio/detail/signal_set_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -17,6 +17,7 @@
 
 #include <boost/asio/detail/config.hpp>
 
+#include <csignal>
 #include <cstddef>
 #include <boost/asio/error.hpp>
 #include <boost/asio/io_service.hpp>
@@ -117,6 +118,9 @@
   // Destroy all user-defined handler objects owned by the service.
   BOOST_ASIO_DECL void shutdown_service();
 
+ // Perform fork-related housekeeping.
+ BOOST_ASIO_DECL void fork_service(boost::asio::io_service::fork_event event);
+
   // Construct a new signal_set implementation.
   BOOST_ASIO_DECL void construct(implementation_type& impl);
 
@@ -166,6 +170,12 @@
   // Helper function to remove a service from the global signal state.
   BOOST_ASIO_DECL static void remove_service(signal_set_service* service);
 
+ // Helper function to create the pipe descriptors.
+ BOOST_ASIO_DECL static void open_descriptors();
+
+ // Helper function to close the pipe descriptors.
+ BOOST_ASIO_DECL static void close_descriptors();
+
   // Helper function to start a wait operation.
   BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
 

Modified: trunk/boost/asio/detail/socket_select_interrupter.hpp
==============================================================================
--- trunk/boost/asio/detail/socket_select_interrupter.hpp (original)
+++ trunk/boost/asio/detail/socket_select_interrupter.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -38,6 +38,9 @@
   // Destructor.
   BOOST_ASIO_DECL ~socket_select_interrupter();
 
+ // Recreate the interrupter's descriptors. Used after a fork.
+ BOOST_ASIO_DECL void recreate();
+
   // Interrupt the select call.
   BOOST_ASIO_DECL void interrupt();
 
@@ -51,6 +54,12 @@
   }
 
 private:
+ // Open the descriptors. Throws on error.
+ BOOST_ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ BOOST_ASIO_DECL void close_descriptors();
+
   // The read end of a connection used to interrupt the select call. This file
   // descriptor is passed to select such that when it is time to stop, a single
   // byte will be written on the other end of the connection and this

Modified: trunk/boost/asio/detail/win_static_mutex.hpp
==============================================================================
--- trunk/boost/asio/detail/win_static_mutex.hpp (original)
+++ trunk/boost/asio/detail/win_static_mutex.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -55,7 +55,7 @@
   ::CRITICAL_SECTION crit_section_;
 };
 
-#define BOOST_ASIO_WIN_STATIC_MUTEX_INIT { false, { 0 } }
+#define BOOST_ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } }
 
 } // namespace detail
 } // namespace asio

Modified: trunk/boost/asio/impl/connect.hpp
==============================================================================
--- trunk/boost/asio/impl/connect.hpp (original)
+++ trunk/boost/asio/impl/connect.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -45,7 +45,7 @@
 {
   boost::system::error_code ec;
   Iterator result = connect(s, begin, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
   return result;
 }
 
@@ -62,7 +62,7 @@
 {
   boost::system::error_code ec;
   Iterator result = connect(s, begin, end, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
   return result;
 }
 
@@ -80,7 +80,7 @@
 {
   boost::system::error_code ec;
   Iterator result = connect(s, begin, connect_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
   return result;
 }
 
@@ -100,7 +100,7 @@
 {
   boost::system::error_code ec;
   Iterator result = connect(s, begin, end, connect_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect");
   return result;
 }
 

Modified: trunk/boost/asio/impl/io_service.ipp
==============================================================================
--- trunk/boost/asio/impl/io_service.ipp (original)
+++ trunk/boost/asio/impl/io_service.ipp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -118,6 +118,11 @@
   impl_.reset();
 }
 
+void io_service::notify_fork(boost::asio::io_service::fork_event event)
+{
+ service_registry_->notify_fork(event);
+}
+
 io_service::service::service(boost::asio::io_service& owner)
   : owner_(owner),
     next_(0)
@@ -128,6 +133,10 @@
 {
 }
 
+void io_service::service::fork_service(boost::asio::io_service::fork_event)
+{
+}
+
 service_already_exists::service_already_exists()
   : std::logic_error("Service already exists.")
 {

Modified: trunk/boost/asio/impl/read.hpp
==============================================================================
--- trunk/boost/asio/impl/read.hpp (original)
+++ trunk/boost/asio/impl/read.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -59,7 +59,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read");
   return bytes_transferred;
 }
 
@@ -77,7 +77,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read(s, buffers, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read");
   return bytes_transferred;
 }
 
@@ -112,7 +112,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read(s, b, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read");
   return bytes_transferred;
 }
 
@@ -132,7 +132,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read(s, b, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read");
   return bytes_transferred;
 }
 

Modified: trunk/boost/asio/impl/read_at.hpp
==============================================================================
--- trunk/boost/asio/impl/read_at.hpp (original)
+++ trunk/boost/asio/impl/read_at.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -63,7 +63,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_at(
       d, offset, buffers, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_at");
   return bytes_transferred;
 }
 
@@ -84,7 +84,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_at(
       d, offset, buffers, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_at");
   return bytes_transferred;
 }
 
@@ -121,7 +121,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_at(
       d, offset, b, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_at");
   return bytes_transferred;
 }
 
@@ -142,7 +142,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_at(
       d, offset, b, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_at");
   return bytes_transferred;
 }
 

Modified: trunk/boost/asio/impl/read_until.hpp
==============================================================================
--- trunk/boost/asio/impl/read_until.hpp (original)
+++ trunk/boost/asio/impl/read_until.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -39,7 +39,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_until(s, b, delim, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_until");
   return bytes_transferred;
 }
 
@@ -95,7 +95,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_until(s, b, delim, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_until");
   return bytes_transferred;
 }
 
@@ -195,7 +195,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_until(s, b, expr, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_until");
   return bytes_transferred;
 }
 
@@ -315,7 +315,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = read_until(s, b, match_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_until");
   return bytes_transferred;
 }
 

Modified: trunk/boost/asio/impl/write.hpp
==============================================================================
--- trunk/boost/asio/impl/write.hpp (original)
+++ trunk/boost/asio/impl/write.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -57,7 +57,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write");
   return bytes_transferred;
 }
 
@@ -75,7 +75,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = write(s, buffers, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write");
   return bytes_transferred;
 }
 
@@ -98,7 +98,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = write(s, b, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write");
   return bytes_transferred;
 }
 
@@ -118,7 +118,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = write(s, b, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write");
   return bytes_transferred;
 }
 

Modified: trunk/boost/asio/impl/write_at.hpp
==============================================================================
--- trunk/boost/asio/impl/write_at.hpp (original)
+++ trunk/boost/asio/impl/write_at.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -61,7 +61,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = write_at(
       d, offset, buffers, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_at");
   return bytes_transferred;
 }
 
@@ -82,7 +82,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = write_at(
       d, offset, buffers, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_at");
   return bytes_transferred;
 }
 
@@ -106,7 +106,7 @@
 {
   boost::system::error_code ec;
   std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_at");
   return bytes_transferred;
 }
 
@@ -127,7 +127,7 @@
   boost::system::error_code ec;
   std::size_t bytes_transferred = write_at(
       d, offset, b, completion_condition, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_at");
   return bytes_transferred;
 }
 

Modified: trunk/boost/asio/io_service.hpp
==============================================================================
--- trunk/boost/asio/io_service.hpp (original)
+++ trunk/boost/asio/io_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -68,9 +68,12 @@
  *
  * @par Thread Safety
  * @e Distinct @e objects: Safe._at_n
- * @e Shared @e objects: Safe, with the exception that calling reset() while
- * there are unfinished run(), run_one(), poll() or poll_one() calls results in
- * undefined behaviour.
+ * @e Shared @e objects: Safe, with the specific exceptions of the reset() and
+ * notify_fork() functions. Calling reset() while there are unfinished run(),
+ * run_one(), poll() or poll_one() calls results in undefined behaviour. The
+ * notify_fork() function should not be called while any io_service function,
+ * or any function on an I/O object that is associated with the io_service, is
+ * being called in another thread.
  *
  * @par Concepts:
  * Dispatcher.
@@ -495,6 +498,61 @@
 #endif
   wrap(Handler handler);
 
+ /// Fork-related event notifications.
+ enum fork_event
+ {
+ /// Notify the io_service that the process is about to fork.
+ fork_prepare,
+
+ /// Notify the io_service that the process has forked and is the parent.
+ fork_parent,
+
+ /// Notify the io_service that the process has forked and is the child.
+ fork_child
+ };
+
+ /// Notify the io_service of a fork-related event.
+ /**
+ * This function is used to inform the io_service that the process is about
+ * to fork, or has just forked. This allows the io_service, and the services
+ * it contains, to perform any necessary housekeeping to ensure correct
+ * operation following a fork.
+ *
+ * This function must not be called while any other io_service function, or
+ * any function on an I/O object associated with the io_service, is being
+ * called in another thread. It is, however, safe to call this function from
+ * within a completion handler, provided no other thread is accessing the
+ * io_service.
+ *
+ * @param event A fork-related event.
+ *
+ * @throws boost::system::system_error Thrown on failure. If the notification
+ * fails the io_service object should no longer be used and should be
+ * destroyed.
+ *
+ * @par Example
+ * The following code illustrates how to incorporate the notify_fork()
+ * function:
+ * @code my_io_service.notify_fork(boost::asio::io_service::fork_prepare);
+ * if (fork() == 0)
+ * {
+ * // This is the child process.
+ * my_io_service.notify_fork(boost::asio::io_service::fork_child);
+ * }
+ * else
+ * {
+ * // This is the parent process.
+ * my_io_service.notify_fork(boost::asio::io_service::fork_parent);
+ * } @endcode
+ *
+ * @note For each service object @c svc in the io_service set, performs
+ * <tt>svc->fork_service();</tt>. When processing the fork_prepare event,
+ * services are visited in reverse order of the beginning of service object
+ * lifetime. Otherwise, services are visited in order of the beginning of
+ * service object lifetime.
+ */
+ BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event event);
+
   /// Obtain the service object corresponding to the given type.
   /**
    * This function is used to locate a service object that corresponds to
@@ -635,6 +693,15 @@
   /// Destroy all user-defined handler objects owned by the service.
   virtual void shutdown_service() = 0;
 
+ /// Handle notification of a fork-related event to perform any necessary
+ /// housekeeping.
+ /**
+ * This function is not a pure virtual so that services only have to
+ * implement it if necessary. The default implementation does nothing.
+ */
+ BOOST_ASIO_DECL virtual void fork_service(
+ boost::asio::io_service::fork_event event);
+
   friend class boost::asio::detail::service_registry;
   struct key
   {

Modified: trunk/boost/asio/ip/basic_resolver.hpp
==============================================================================
--- trunk/boost/asio/ip/basic_resolver.hpp (original)
+++ trunk/boost/asio/ip/basic_resolver.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -100,7 +100,7 @@
   {
     boost::system::error_code ec;
     iterator i = this->service.resolve(this->implementation, q, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "resolve");
     return i;
   }
 
@@ -186,7 +186,7 @@
   {
     boost::system::error_code ec;
     iterator i = this->service.resolve(this->implementation, e, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "resolve");
     return i;
   }
 

Modified: trunk/boost/asio/ip/resolver_service.hpp
==============================================================================
--- trunk/boost/asio/ip/resolver_service.hpp (original)
+++ trunk/boost/asio/ip/resolver_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -77,12 +77,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new resolver implementation.
   void construct(implementation_type& impl)
   {
@@ -132,6 +126,18 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
+ // Perform any fork-related housekeeping.
+ void fork_service(boost::asio::io_service::fork_event event)
+ {
+ service_impl_.fork_service(event);
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/local/connect_pair.hpp
==============================================================================
--- trunk/boost/asio/local/connect_pair.hpp (original)
+++ trunk/boost/asio/local/connect_pair.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -52,7 +52,7 @@
 {
   boost::system::error_code ec;
   connect_pair(socket1, socket2, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "connect_pair");
 }
 
 template <typename Protocol, typename SocketService1, typename SocketService2>

Modified: trunk/boost/asio/posix/basic_descriptor.hpp
==============================================================================
--- trunk/boost/asio/posix/basic_descriptor.hpp (original)
+++ trunk/boost/asio/posix/basic_descriptor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -88,7 +88,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, native_descriptor, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Get a reference to the lowest layer.
@@ -131,7 +131,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, native_descriptor, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Assign an existing native descriptor to the descriptor.
@@ -160,13 +160,14 @@
    * write operations will be cancelled immediately, and will complete with the
    * boost::asio::error::operation_aborted error.
    *
- * @throws boost::system::system_error Thrown on failure.
+ * @throws boost::system::system_error Thrown on failure. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
    */
   void close()
   {
     boost::system::error_code ec;
     this->service.close(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "close");
   }
 
   /// Close the descriptor.
@@ -175,7 +176,8 @@
    * write operations will be cancelled immediately, and will complete with the
    * boost::asio::error::operation_aborted error.
    *
- * @param ec Set to indicate what error occurred, if any.
+ * @param ec Set to indicate what error occurred, if any. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
    */
   boost::system::error_code close(boost::system::error_code& ec)
   {
@@ -232,7 +234,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all asynchronous operations associated with the descriptor.
@@ -275,7 +277,7 @@
   {
     boost::system::error_code ec;
     this->service.io_control(this->implementation, command, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "io_control");
   }
 
   /// Perform an IO control command on the descriptor.
@@ -345,7 +347,7 @@
   {
     boost::system::error_code ec;
     this->service.non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
   }
 
   /// Sets the non-blocking mode of the descriptor.
@@ -405,7 +407,7 @@
   {
     boost::system::error_code ec;
     this->service.native_non_blocking(this->implementation, mode, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
   }
 
   /// Sets the non-blocking mode of the native descriptor implementation.

Modified: trunk/boost/asio/posix/basic_stream_descriptor.hpp
==============================================================================
--- trunk/boost/asio/posix/basic_stream_descriptor.hpp (original)
+++ trunk/boost/asio/posix/basic_stream_descriptor.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -124,7 +124,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.write_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_some");
     return s;
   }
 
@@ -231,7 +231,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.read_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_some");
     return s;
   }
 

Modified: trunk/boost/asio/posix/stream_descriptor_service.hpp
==============================================================================
--- trunk/boost/asio/posix/stream_descriptor_service.hpp (original)
+++ trunk/boost/asio/posix/stream_descriptor_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -78,12 +78,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new stream descriptor implementation.
   void construct(implementation_type& impl)
   {
@@ -210,6 +204,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/raw_socket_service.hpp
==============================================================================
--- trunk/boost/asio/raw_socket_service.hpp (original)
+++ trunk/boost/asio/raw_socket_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -90,12 +90,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new raw socket implementation.
   void construct(implementation_type& impl)
   {
@@ -340,6 +334,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/seq_packet_socket_service.hpp
==============================================================================
--- trunk/boost/asio/seq_packet_socket_service.hpp (original)
+++ trunk/boost/asio/seq_packet_socket_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -92,12 +92,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new sequenced packet socket implementation.
   void construct(implementation_type& impl)
   {
@@ -307,6 +301,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/serial_port_service.hpp
==============================================================================
--- trunk/boost/asio/serial_port_service.hpp (original)
+++ trunk/boost/asio/serial_port_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -84,12 +84,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new serial port implementation.
   void construct(implementation_type& impl)
   {
@@ -204,6 +198,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/signal_set_service.hpp
==============================================================================
--- trunk/boost/asio/signal_set_service.hpp (original)
+++ trunk/boost/asio/signal_set_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -54,12 +54,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new signal set implementation.
   void construct(implementation_type& impl)
   {
@@ -108,6 +102,18 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
+ // Perform any fork-related housekeeping.
+ void fork_service(boost::asio::io_service::fork_event event)
+ {
+ service_impl_.fork_service(event);
+ }
+
   // The platform-specific implementation.
   detail::signal_set_service service_impl_;
 };

Modified: trunk/boost/asio/socket_acceptor_service.hpp
==============================================================================
--- trunk/boost/asio/socket_acceptor_service.hpp (original)
+++ trunk/boost/asio/socket_acceptor_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -90,12 +90,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new socket acceptor implementation.
   void construct(implementation_type& impl)
   {
@@ -246,6 +240,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/ssl/context_service.hpp
==============================================================================
--- trunk/boost/asio/ssl/context_service.hpp (original)
+++ trunk/boost/asio/ssl/context_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -62,11 +62,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- }
-
   /// Return a null context implementation.
   impl_type null() const
   {
@@ -161,6 +156,11 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
   // The service that provides the platform-specific implementation.
   service_impl_type& service_impl_;
 };

Modified: trunk/boost/asio/ssl/stream_service.hpp
==============================================================================
--- trunk/boost/asio/ssl/stream_service.hpp (original)
+++ trunk/boost/asio/ssl/stream_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -62,11 +62,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- }
-
   /// Return a null stream implementation.
   impl_type null() const
   {
@@ -171,6 +166,11 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
   // The service that provides the platform-specific implementation.
   service_impl_type& service_impl_;
 };

Modified: trunk/boost/asio/stream_socket_service.hpp
==============================================================================
--- trunk/boost/asio/stream_socket_service.hpp (original)
+++ trunk/boost/asio/stream_socket_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -90,12 +90,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new stream socket implementation.
   void construct(implementation_type& impl)
   {
@@ -303,6 +297,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/windows/basic_handle.hpp
==============================================================================
--- trunk/boost/asio/windows/basic_handle.hpp (original)
+++ trunk/boost/asio/windows/basic_handle.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -84,7 +84,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, handle, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Get a reference to the lowest layer.
@@ -127,7 +127,7 @@
   {
     boost::system::error_code ec;
     this->service.assign(this->implementation, handle, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "assign");
   }
 
   /// Assign an existing native handle to the handle.
@@ -162,7 +162,7 @@
   {
     boost::system::error_code ec;
     this->service.close(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "close");
   }
 
   /// Close the handle.
@@ -212,7 +212,7 @@
   {
     boost::system::error_code ec;
     this->service.cancel(this->implementation, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "cancel");
   }
 
   /// Cancel all asynchronous operations associated with the handle.

Modified: trunk/boost/asio/windows/basic_random_access_handle.hpp
==============================================================================
--- trunk/boost/asio/windows/basic_random_access_handle.hpp (original)
+++ trunk/boost/asio/windows/basic_random_access_handle.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -124,7 +124,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.write_some_at(
         this->implementation, offset, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_some_at");
     return s;
   }
 
@@ -240,7 +240,7 @@
     boost::system::error_code ec;
     std::size_t s = this->service.read_some_at(
         this->implementation, offset, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_some_at");
     return s;
   }
 

Modified: trunk/boost/asio/windows/basic_stream_handle.hpp
==============================================================================
--- trunk/boost/asio/windows/basic_stream_handle.hpp (original)
+++ trunk/boost/asio/windows/basic_stream_handle.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -121,7 +121,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.write_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "write_some");
     return s;
   }
 
@@ -228,7 +228,7 @@
   {
     boost::system::error_code ec;
     std::size_t s = this->service.read_some(this->implementation, buffers, ec);
- boost::asio::detail::throw_error(ec);
+ boost::asio::detail::throw_error(ec, "read_some");
     return s;
   }
 

Modified: trunk/boost/asio/windows/random_access_handle_service.hpp
==============================================================================
--- trunk/boost/asio/windows/random_access_handle_service.hpp (original)
+++ trunk/boost/asio/windows/random_access_handle_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -81,12 +81,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new random-access handle implementation.
   void construct(implementation_type& impl)
   {
@@ -171,6 +165,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/boost/asio/windows/stream_handle_service.hpp
==============================================================================
--- trunk/boost/asio/windows/stream_handle_service.hpp (original)
+++ trunk/boost/asio/windows/stream_handle_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -78,12 +78,6 @@
   {
   }
 
- /// Destroy all user-defined handler objects owned by the service.
- void shutdown_service()
- {
- service_impl_.shutdown_service();
- }
-
   /// Construct a new stream handle implementation.
   void construct(implementation_type& impl)
   {
@@ -168,6 +162,12 @@
   }
 
 private:
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ service_impl_.shutdown_service();
+ }
+
   // The platform-specific implementation.
   service_impl_type service_impl_;
 };

Modified: trunk/libs/asio/doc/Jamfile.v2
==============================================================================
--- trunk/libs/asio/doc/Jamfile.v2 (original)
+++ trunk/libs/asio/doc/Jamfile.v2 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -25,7 +25,7 @@
     <location>html/boost_asio
   ;
 
-local example-names = allocation buffers chat echo http/client http/server
+local example-names = allocation buffers chat echo fork http/client http/server
   http/server2 http/server3 http/server4 icmp invocation iostreams local
   multicast nonblocking porthopper serialization services socks4 ssl timeouts
   timers windows ;

Modified: trunk/libs/asio/doc/examples.qbk
==============================================================================
--- trunk/libs/asio/doc/examples.qbk (original)
+++ trunk/libs/asio/doc/examples.qbk 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -53,6 +53,20 @@
 * [@boost_asio/example/echo/blocking_udp_echo_server.cpp]
 
 
+[heading Fork]
+
+These POSIX-specific examples show how to use Boost.Asio in conjunction with the
+`fork()` system call. The first example illustrates the steps required to start
+a daemon process:
+
+* [@boost_asio/example/fork/daemon.cpp]
+
+The second example demonstrates how it is possible to fork a process from
+within a completion handler.
+
+* [@boost_asio/example/fork/process_per_connection.cpp]
+
+
 [heading HTTP Client]
 
 Example programs implementing simple HTTP 1.0 clients. These examples show how

Modified: trunk/libs/asio/example/chat/chat_client.cpp
==============================================================================
--- trunk/libs/asio/example/chat/chat_client.cpp (original)
+++ trunk/libs/asio/example/chat/chat_client.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -13,7 +13,7 @@
 #include <iostream>
 #include <boost/bind.hpp>
 #include <boost/asio.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include "chat_message.hpp"
 
 using boost::asio::ip::tcp;

Modified: trunk/libs/asio/example/echo/blocking_tcp_echo_server.cpp
==============================================================================
--- trunk/libs/asio/example/echo/blocking_tcp_echo_server.cpp (original)
+++ trunk/libs/asio/example/echo/blocking_tcp_echo_server.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -13,7 +13,7 @@
 #include <boost/bind.hpp>
 #include <boost/smart_ptr.hpp>
 #include <boost/asio.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 
 using boost::asio::ip::tcp;
 

Added: trunk/libs/asio/example/fork/Jamfile
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/fork/Jamfile 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# 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)
+#
+
+subproject libs/asio/example/fork ;
+
+project boost : $(BOOST_ROOT) ;
+
+if $(UNIX)
+{
+ switch $(JAMUNAME)
+ {
+ case SunOS* :
+ {
+ SOCKET_LIBS = <find-library>socket <find-library>nsl ;
+ }
+ }
+}
+
+exe daemon
+ : <lib>@boost/libs/system/build/boost_system
+ daemon.cpp
+ : <include>$(BOOST_ROOT)
+ <include>../../../..
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <mingw><*><find-library>ws2_32
+ <mingw><*><find-library>mswsock
+ $(SOCKET_LIBS)
+ ;
+
+exe process_per_connection
+ : <lib>@boost/libs/system/build/boost_system
+ process_per_connection.cpp
+ : <include>$(BOOST_ROOT)
+ <include>../../../..
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <mingw><*><find-library>ws2_32
+ <mingw><*><find-library>mswsock
+ $(SOCKET_LIBS)
+ ;

Added: trunk/libs/asio/example/fork/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/fork/Jamfile.v2 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# 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)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+else if [ os.name ] = HPUX
+{
+ lib ipv6 ;
+}
+
+exe daemon
+ : daemon.cpp
+ /boost/system//boost_system
+ : <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT:<define>_WIN32_WINNT=0x0501
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ <os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
+ <os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
+ <os>HPUX:<library>ipv6
+ ;
+
+exe process_per_connection
+ : process_per_connection.cpp
+ /boost/system//boost_system
+ : <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT:<define>_WIN32_WINNT=0x0501
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ <os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
+ <os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
+ <os>HPUX:<library>ipv6
+ ;

Added: trunk/libs/asio/example/fork/daemon.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/fork/daemon.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,189 @@
+//
+// daemon.cpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/signal_set.hpp>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <ctime>
+#include <iostream>
+#include <syslog.h>
+#include <unistd.h>
+
+using boost::asio::ip::udp;
+
+class udp_daytime_server
+{
+public:
+ udp_daytime_server(boost::asio::io_service& io_service)
+ : socket_(io_service, udp::endpoint(udp::v4(), 13))
+ {
+ start_receive();
+ }
+
+private:
+ void start_receive()
+ {
+ socket_.async_receive_from(
+ boost::asio::buffer(recv_buffer_), remote_endpoint_,
+ boost::bind(&udp_daytime_server::handle_receive, this, _1));
+ }
+
+ void handle_receive(const boost::system::error_code& ec)
+ {
+ if (!ec || ec == boost::asio::error::message_size)
+ {
+ using namespace std; // For time_t, time and ctime;
+ time_t now = time(0);
+ std::string message = ctime(&now);
+
+ boost::system::error_code ignored_ec;
+ socket_.send_to(boost::asio::buffer(message),
+ remote_endpoint_, 0, ignored_ec);
+ }
+
+ start_receive();
+ }
+
+ udp::socket socket_;
+ udp::endpoint remote_endpoint_;
+ boost::array<char, 1> recv_buffer_;
+};
+
+int main()
+{
+ try
+ {
+ boost::asio::io_service io_service;
+
+ // Initialise the server before becoming a daemon. If the process is
+ // started from a shell, this means any errors will be reported back to the
+ // user.
+ udp_daytime_server server(io_service);
+
+ // Register signal handlers so that the daemon may be shut down. You may
+ // also want to register for other signals, such as SIGHUP to trigger a
+ // re-read of a configuration file.
+ boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
+ signals.async_wait(
+ boost::bind(&boost::asio::io_service::stop, &io_service));
+
+ // Inform the io_service that we are about to become a daemon. The
+ // io_service cleans up any internal resources, such as threads, that may
+ // interfere with forking.
+ io_service.notify_fork(boost::asio::io_service::fork_prepare);
+
+ // Fork the process and have the parent exit. If the process was started
+ // from a shell, this returns control to the user. Forking a new process is
+ // also a prerequisite for the subsequent call to setsid().
+ if (pid_t pid = fork())
+ {
+ if (pid > 0)
+ {
+ // We're in the parent process and need to exit.
+ //
+ // When the exit() function is used, the program terminates without
+ // invoking local variables' destructors. Only global variables are
+ // destroyed. As the io_service object is a local variable, this means
+ // we do not have to call:
+ //
+ // io_service.notify_fork(boost::asio::io_service::fork_parent);
+ //
+ // However, this line should be added before each call to exit() if
+ // using a global io_service object. An additional call:
+ //
+ // io_service.notify_fork(boost::asio::io_service::fork_prepare);
+ //
+ // should also precede the second fork().
+ exit(0);
+ }
+ else
+ {
+ syslog(LOG_ERR | LOG_USER, "First fork failed: %m");
+ return 1;
+ }
+ }
+
+ // Make the process a new session leader. This detaches it from the
+ // terminal.
+ setsid();
+
+ // A process inherits its working directory from its parent. This could be
+ // on a mounted filesystem, which means that the running daemon would
+ // prevent this filesystem from being unmounted. Changing to the root
+ // directory avoids this problem.
+ chdir("/");
+
+ // The file mode creation mask is also inherited from the parent process.
+ // We don't want to restrict the permissions on files created by the
+ // daemon, so the mask is cleared.
+ umask(0);
+
+ // A second fork ensures the process cannot acquire a controlling terminal.
+ if (pid_t pid = fork())
+ {
+ if (pid > 0)
+ {
+ exit(0);
+ }
+ else
+ {
+ syslog(LOG_ERR | LOG_USER, "Second fork failed: %m");
+ return 1;
+ }
+ }
+
+ // Close the standard streams. This decouples the daemon from the terminal
+ // that started it.
+ close(0);
+ close(1);
+ close(2);
+
+ // We don't want the daemon to have any standard input.
+ if (open("/dev/null", O_RDONLY) < 0)
+ {
+ syslog(LOG_ERR | LOG_USER, "Unable to open /dev/null: %m");
+ return 1;
+ }
+
+ // Send standard output to a log file.
+ const char* output = "/tmp/asio.daemon.out";
+ const int flags = O_WRONLY | O_CREAT | O_APPEND;
+ const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ if (open(output, flags, mode) < 0)
+ {
+ syslog(LOG_ERR | LOG_USER, "Unable to open output file %s: %m", output);
+ return 1;
+ }
+
+ // Also send standard error to the same log file.
+ if (dup(1) < 0)
+ {
+ syslog(LOG_ERR | LOG_USER, "Unable to dup output descriptor: %m");
+ return 1;
+ }
+
+ // Inform the io_service that we have finished becoming a daemon. The
+ // io_service uses this opportunity to create any internal file descriptors
+ // that need to be private to the new process.
+ io_service.notify_fork(boost::asio::io_service::fork_child);
+
+ // The io_service can now be used normally.
+ syslog(LOG_INFO | LOG_USER, "Daemon started");
+ io_service.run();
+ syslog(LOG_INFO | LOG_USER, "Daemon stopped");
+ }
+ catch (std::exception& e)
+ {
+ syslog(LOG_ERR | LOG_USER, "Exception: %s", e.what());
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+}

Added: trunk/libs/asio/example/fork/process_per_connection.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/example/fork/process_per_connection.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,151 @@
+//
+// process_per_connection.cpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/signal_set.hpp>
+#include <boost/asio/write.hpp>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <cstdlib>
+#include <iostream>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using boost::asio::ip::tcp;
+
+class server
+{
+public:
+ server(boost::asio::io_service& io_service, unsigned short port)
+ : io_service_(io_service),
+ signal_(io_service, SIGCHLD),
+ acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
+ socket_(io_service)
+ {
+ start_signal_wait();
+ start_accept();
+ }
+
+private:
+ void start_signal_wait()
+ {
+ signal_.async_wait(boost::bind(&server::handle_signal_wait, this));
+ }
+
+ void handle_signal_wait()
+ {
+ // Reap completed child processes so that we don't end up with zombies.
+ int status = 0;
+ while (waitpid(-1, &status, WNOHANG) > 0) {}
+
+ start_signal_wait();
+ }
+
+ void start_accept()
+ {
+ acceptor_.async_accept(socket_,
+ boost::bind(&server::handle_accept, this, _1));
+ }
+
+ void handle_accept(const boost::system::error_code& ec)
+ {
+ if (!ec)
+ {
+ // Inform the io_service that we are about to fork. The io_service cleans
+ // up any internal resources, such as threads, that may interfere with
+ // forking.
+ io_service_.notify_fork(boost::asio::io_service::fork_prepare);
+
+ if (fork() == 0)
+ {
+ // Inform the io_service that the fork is finished and that this is the
+ // child process. The io_service uses this opportunity to create any
+ // internal file descriptors that must be private to the new process.
+ io_service_.notify_fork(boost::asio::io_service::fork_child);
+
+ // The child won't be accepting new connections, so we can close the
+ // acceptor. It remains open in the parent.
+ acceptor_.close();
+
+ start_read();
+ }
+ else
+ {
+ // Inform the io_service that the fork is finished (or failed) and that
+ // this is the parent process. The io_service uses this opportunity to
+ // recreate any internal resources that were cleaned up during
+ // preparation for the fork.
+ io_service_.notify_fork(boost::asio::io_service::fork_parent);
+
+ socket_.close();
+ start_accept();
+ }
+ }
+ else
+ {
+ std::cerr << "Accept error: " << ec.message() << std::endl;
+ }
+ }
+
+ void start_read()
+ {
+ socket_.async_read_some(boost::asio::buffer(data_),
+ boost::bind(&server::handle_read, this, _1, _2));
+ }
+
+ void handle_read(const boost::system::error_code& ec, std::size_t length)
+ {
+ if (!ec)
+ start_write(length);
+ }
+
+ void start_write(std::size_t length)
+ {
+ boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
+ boost::bind(&server::handle_write, this, _1));
+ }
+
+ void handle_write(const boost::system::error_code& ec)
+ {
+ if (!ec)
+ start_read();
+ }
+
+ boost::asio::io_service& io_service_;
+ boost::asio::signal_set signal_;
+ tcp::acceptor acceptor_;
+ tcp::socket socket_;
+ boost::array<char, 1024> data_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: process_per_connection <port>\n";
+ return 1;
+ }
+
+ boost::asio::io_service io_service;
+
+ using namespace std; // For atoi.
+ server s(io_service, atoi(argv[1]));
+
+ io_service.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+}

Modified: trunk/libs/asio/example/http/server2/io_service_pool.cpp
==============================================================================
--- trunk/libs/asio/example/http/server2/io_service_pool.cpp (original)
+++ trunk/libs/asio/example/http/server2/io_service_pool.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -10,7 +10,7 @@
 
 #include "server.hpp"
 #include <stdexcept>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 

Modified: trunk/libs/asio/example/http/server3/server.cpp
==============================================================================
--- trunk/libs/asio/example/http/server3/server.cpp (original)
+++ trunk/libs/asio/example/http/server3/server.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -9,7 +9,7 @@
 //
 
 #include "server.hpp"
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 #include <vector>

Modified: trunk/libs/asio/example/local/connect_pair.cpp
==============================================================================
--- trunk/libs/asio/example/local/connect_pair.cpp (original)
+++ trunk/libs/asio/example/local/connect_pair.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -12,7 +12,7 @@
 #include <string>
 #include <cctype>
 #include <boost/asio.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/array.hpp>
 #include <boost/bind.hpp>
 

Modified: trunk/libs/asio/example/services/logger_service.hpp
==============================================================================
--- trunk/libs/asio/example/services/logger_service.hpp (original)
+++ trunk/libs/asio/example/services/logger_service.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -12,7 +12,7 @@
 #define SERVICES_LOGGER_SERVICE_HPP
 
 #include <boost/asio.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/noncopyable.hpp>

Modified: trunk/libs/asio/example/timeouts/async_tcp_client.cpp
==============================================================================
--- trunk/libs/asio/example/timeouts/async_tcp_client.cpp (original)
+++ trunk/libs/asio/example/timeouts/async_tcp_client.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -110,7 +110,8 @@
   void stop()
   {
     stopped_ = true;
- socket_.close();
+ boost::system::error_code ignored_ec;
+ socket_.close(ignored_ec);
     deadline_.cancel();
     heartbeat_timer_.cancel();
   }

Modified: trunk/libs/asio/example/timeouts/blocking_tcp_client.cpp
==============================================================================
--- trunk/libs/asio/example/timeouts/blocking_tcp_client.cpp (original)
+++ trunk/libs/asio/example/timeouts/blocking_tcp_client.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -178,7 +178,8 @@
       // The deadline has passed. The socket is closed so that any outstanding
       // asynchronous operations are cancelled. This allows the blocked
       // connect(), read_line() or write_line() functions to return.
- socket_.close();
+ boost::system::error_code ignored_ec;
+ socket_.close(ignored_ec);
 
       // There is no longer an active deadline. The expiry is set to positive
       // infinity so that the actor takes no action until a new deadline is set.

Modified: trunk/libs/asio/example/timeouts/server.cpp
==============================================================================
--- trunk/libs/asio/example/timeouts/server.cpp (original)
+++ trunk/libs/asio/example/timeouts/server.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -177,7 +177,8 @@
   {
     channel_.leave(shared_from_this());
 
- socket_.close();
+ boost::system::error_code ignored_ec;
+ socket_.close(ignored_ec);
     input_deadline_.cancel();
     non_empty_output_queue_.cancel();
     output_deadline_.cancel();

Modified: trunk/libs/asio/example/tutorial/timer5/timer.cpp
==============================================================================
--- trunk/libs/asio/example/tutorial/timer5/timer.cpp (original)
+++ trunk/libs/asio/example/tutorial/timer5/timer.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -10,7 +10,7 @@
 
 #include <iostream>
 #include <boost/asio.hpp>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 

Added: trunk/libs/asio/test/archetypes/gettable_socket_option.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/archetypes/gettable_socket_option.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,54 @@
+//
+// gettable_socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+#ifndef ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
+#define ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP
+
+#include <cstddef>
+
+namespace archetypes {
+
+template <typename PointerType>
+class gettable_socket_option
+{
+public:
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ PointerType* data(const Protocol&)
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t)
+ {
+ }
+};
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP

Added: trunk/libs/asio/test/archetypes/settable_socket_option.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/archetypes/settable_socket_option.hpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,49 @@
+//
+// settable_socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+#ifndef ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
+#define ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP
+
+#include <cstddef>
+
+namespace archetypes {
+
+template <typename PointerType>
+class settable_socket_option
+{
+public:
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ const PointerType* data(const Protocol&) const
+ {
+ return 0;
+ }
+
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return 0;
+ }
+};
+
+} // namespace archetypes
+
+#endif // ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP

Modified: trunk/libs/asio/test/deadline_timer.cpp
==============================================================================
--- trunk/libs/asio/test/deadline_timer.cpp (original)
+++ trunk/libs/asio/test/deadline_timer.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -16,7 +16,7 @@
 // Test that header file is self-contained.
 #include <boost/asio/deadline_timer.hpp>
 
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/placeholders.hpp>

Modified: trunk/libs/asio/test/io_service.cpp
==============================================================================
--- trunk/libs/asio/test/io_service.cpp (original)
+++ trunk/libs/asio/test/io_service.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -17,7 +17,7 @@
 #include <boost/asio/io_service.hpp>
 
 #include <sstream>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/asio/deadline_timer.hpp>
 #include "unit_test.hpp"

Modified: trunk/libs/asio/test/ip/tcp.cpp
==============================================================================
--- trunk/libs/asio/test/ip/tcp.cpp (original)
+++ trunk/libs/asio/test/ip/tcp.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -26,7 +26,9 @@
 #include <boost/asio/read.hpp>
 #include <boost/asio/write.hpp>
 #include "../unit_test.hpp"
+#include "../archetypes/gettable_socket_option.hpp"
 #include "../archetypes/io_control_command.hpp"
+#include "../archetypes/settable_socket_option.hpp"
 
 //------------------------------------------------------------------------------
 
@@ -156,6 +158,12 @@
     const char const_char_buffer[128] = "";
     socket_base::message_flags in_flags = 0;
     socket_base::keep_alive socket_option;
+ archetypes::settable_socket_option<void> settable_socket_option1;
+ archetypes::settable_socket_option<int> settable_socket_option2;
+ archetypes::settable_socket_option<double> settable_socket_option3;
+ archetypes::gettable_socket_option<void> gettable_socket_option1;
+ archetypes::gettable_socket_option<int> gettable_socket_option2;
+ archetypes::gettable_socket_option<double> gettable_socket_option3;
     archetypes::io_control_command io_control_command;
     boost::system::error_code ec;
 
@@ -233,11 +241,19 @@
     socket1.async_connect(ip::tcp::endpoint(ip::tcp::v4(), 0), connect_handler);
     socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), connect_handler);
 
- socket1.set_option(socket_option);
- socket1.set_option(socket_option, ec);
-
- socket1.get_option(socket_option);
- socket1.get_option(socket_option, ec);
+ socket1.set_option(settable_socket_option1);
+ socket1.set_option(settable_socket_option1, ec);
+ socket1.set_option(settable_socket_option2);
+ socket1.set_option(settable_socket_option2, ec);
+ socket1.set_option(settable_socket_option3);
+ socket1.set_option(settable_socket_option3, ec);
+
+ socket1.get_option(gettable_socket_option1);
+ socket1.get_option(gettable_socket_option1, ec);
+ socket1.get_option(gettable_socket_option2);
+ socket1.get_option(gettable_socket_option2, ec);
+ socket1.get_option(gettable_socket_option3);
+ socket1.get_option(gettable_socket_option3, ec);
 
     socket1.io_control(io_control_command);
     socket1.io_control(io_control_command, ec);

Modified: trunk/libs/asio/test/ip/udp.cpp
==============================================================================
--- trunk/libs/asio/test/ip/udp.cpp (original)
+++ trunk/libs/asio/test/ip/udp.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -21,7 +21,9 @@
 #include <boost/asio/io_service.hpp>
 #include <boost/asio/placeholders.hpp>
 #include "../unit_test.hpp"
+#include "../archetypes/gettable_socket_option.hpp"
 #include "../archetypes/io_control_command.hpp"
+#include "../archetypes/settable_socket_option.hpp"
 
 //------------------------------------------------------------------------------
 
@@ -55,7 +57,12 @@
     char mutable_char_buffer[128] = "";
     const char const_char_buffer[128] = "";
     socket_base::message_flags in_flags = 0;
- socket_base::keep_alive socket_option;
+ archetypes::settable_socket_option<void> settable_socket_option1;
+ archetypes::settable_socket_option<int> settable_socket_option2;
+ archetypes::settable_socket_option<double> settable_socket_option3;
+ archetypes::gettable_socket_option<void> gettable_socket_option1;
+ archetypes::gettable_socket_option<int> gettable_socket_option2;
+ archetypes::gettable_socket_option<double> gettable_socket_option3;
     archetypes::io_control_command io_control_command;
     boost::system::error_code ec;
 
@@ -133,11 +140,19 @@
     socket1.async_connect(ip::udp::endpoint(ip::udp::v4(), 0), connect_handler);
     socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), connect_handler);
 
- socket1.set_option(socket_option);
- socket1.set_option(socket_option, ec);
-
- socket1.get_option(socket_option);
- socket1.get_option(socket_option, ec);
+ socket1.set_option(settable_socket_option1);
+ socket1.set_option(settable_socket_option1, ec);
+ socket1.set_option(settable_socket_option2);
+ socket1.set_option(settable_socket_option2, ec);
+ socket1.set_option(settable_socket_option3);
+ socket1.set_option(settable_socket_option3, ec);
+
+ socket1.get_option(gettable_socket_option1);
+ socket1.get_option(gettable_socket_option1, ec);
+ socket1.get_option(gettable_socket_option2);
+ socket1.get_option(gettable_socket_option2, ec);
+ socket1.get_option(gettable_socket_option3);
+ socket1.get_option(gettable_socket_option3, ec);
 
     socket1.io_control(io_control_command);
     socket1.io_control(io_control_command, ec);

Modified: trunk/libs/asio/test/strand.cpp
==============================================================================
--- trunk/libs/asio/test/strand.cpp (original)
+++ trunk/libs/asio/test/strand.cpp 2011-03-02 03:27:32 EST (Wed, 02 Mar 2011)
@@ -17,7 +17,7 @@
 #include <boost/asio/strand.hpp>
 
 #include <sstream>
-#include <boost/thread.hpp>
+#include <boost/thread/thread.hpp>
 #include <boost/bind.hpp>
 #include <boost/asio/deadline_timer.hpp>
 #include <boost/asio/io_service.hpp>


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