Boost C++ Libraries: Ticket #3307: Stream descriptor blocking state set on close https://svn.boost.org/trac10/ticket/3307 <p> Say you have the following situation: </p> <p> class A { </p> <blockquote> <p> asio::posix::stream_descriptor stdin; </p> </blockquote> <p> public: </p> <blockquote> <p> A() : stdin(svc, dup(STDIN_FILENO)) { </p> <blockquote> <p> stdin.async_read_some(..., &amp;A::read); </p> </blockquote> <p> } void read() { </p> <blockquote> <p> <em> do something stdin.async_read_some(..., &amp;A::read); </em></p> </blockquote> <p> } </p> </blockquote> <p> } </p> <p> A *obj; </p> <p> void read() { </p> <blockquote> <p> obj = new A; </p> </blockquote> <p> } </p> <p> void foo() { </p> <blockquote> <p> asio::posix::stream_descriptor stdin(dup(STDIN_FILENO)); </p> </blockquote> <blockquote> <p> stdin.async_read_some(..., &amp;read) </p> </blockquote> <blockquote> <p> while (!obj) </p> <blockquote> <p> sleep(1); </p> </blockquote> </blockquote> <p> } </p> <p> In this case, a stream descriptor is created from a dup(STDIN_FILENO) twice (assume there are technical reasons why the original stream_descriptor cannot be passed through). So the following happens: </p> <p> stdin constructed stdin - data read async request (set non-blocking) stdin - data read A constructed (A::stdin constructed) A::stdin - data read async request (set non-blocking) stdin destroyed (set blocking) A::stdin - data read A::stdin - data read async request (BLOCKS!) </p> <p> The problem here is that all dups of a file handle share blocking state, and three things are happening in the above. </p> <ol><li>A::stdin is ASSUMED to be blocking when constructed (current blocking state is not checked). This is not a problem, but if I had tried to do a sync read/write, it would have been. </li><li>Blocking state is maintained by an internal flag, so once the FD has been set non-blocking it does not try to set it non-blocking again. But worse, there is no way to 'override' this if you know for a fact that the descriptor has been set blocking out of ASIO's control. Even stream_descriptor::command with non_blocking_io just sets a flag, rather than doing an actual operation. </li><li>For no apparent reason, a descriptor that ASIO knows was set non-blocking, gets set back to blocking in close() or destroy(). There is no apparent reason for this really, if the FD is about to be closed, it does not matter what it's blocking state is doing so. </li></ol><p> I can work around this by manually calling ioctl on A::stdin.native() in the first invocation of A::read(), however this is a hack, and only required because of <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/2" title="#2: Bugs: list::size should be const (closed: fixed)">#2</a> above. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3307 Trac 1.4.3 chris_kohlhoff Sat, 27 Mar 2010 10:54:46 GMT <link>https://svn.boost.org/trac10/ticket/3307#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:1</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/60869" title="Always call ioctl on underlying descriptor when modifying blocking ...">[60869]</a>) Always call ioctl on underlying descriptor when modifying blocking mode. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3307" title="#3307: Bugs: Stream descriptor blocking state set on close (closed: fixed)">#3307</a>. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>chris_kohlhoff</dc:creator> <pubDate>Tue, 30 Mar 2010 01:20:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3307#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:2</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/60924" title="Merge from trunk. ........ r60869 | chris_kohlhoff | 2010-03-27 ...">[60924]</a>) Merge from trunk. </p> <p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60869" title="Always call ioctl on underlying descriptor when modifying blocking ...">r60869</a> | chris_kohlhoff | 2010-03-27 21:54:44 +1100 (Sat, 27 Mar 2010) | 2 lines </p> </blockquote> <p> </p> <blockquote> <p> Always call ioctl on underlying descriptor when modifying blocking mode. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3307" title="#3307: Bugs: Stream descriptor blocking state set on close (closed: fixed)">#3307</a>. </p> </blockquote> <p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60882" title="Change the resolver implementation to no longer require the typedefs ...">r60882</a> | chris_kohlhoff | 2010-03-28 09:22:59 +1100 (Sun, 28 Mar 2010) | 12 lines </p> </blockquote> <p> </p> <blockquote> <p> Change the resolver implementation to no longer require the typedefs InternetProtocol::resolver_query and InternetProtocol::resolver_iterator, as neither typedef is part of the documented <a class="missing wiki">InternetProtocol</a> requirements. </p> </blockquote> <p> </p> <blockquote> <p> The following typedefs are now marked as deprecated: </p> </blockquote> <ul><li>ip::icmp::resolver_query </li><li>ip::icmp::resolver_iterator </li><li>ip::tcp::resolver_query </li><li>ip::tcp::resolver_iterator </li><li>ip::udp::resolver_query </li><li>ip::udp::resolver_iterator </li></ul><p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60883" title="Fix unused variable warnings. ">r60883</a> | chris_kohlhoff | 2010-03-28 10:04:56 +1100 (Sun, 28 Mar 2010) | 2 lines </p> </blockquote> <p> </p> <blockquote> <p> Fix unused variable warnings. </p> </blockquote> <p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60921" title="Document basic_resolver_query's constructor arguments. ">r60921</a> | chris_kohlhoff | 2010-03-30 10:51:15 +1100 (Tue, 30 Mar 2010) | 2 lines </p> </blockquote> <p> </p> <blockquote> <p> Document basic_resolver_query's constructor arguments. </p> </blockquote> <p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60922" title="Work around an apparent doxygen bug to show template parameter lists ...">r60922</a> | chris_kohlhoff | 2010-03-30 10:55:00 +1100 (Tue, 30 Mar 2010) | 3 lines </p> </blockquote> <p> </p> <blockquote> <p> Work around an apparent doxygen bug to show template parameter lists on inherited member functions. </p> </blockquote> <p> ........ </p> <blockquote> <p> <a class="changeset" href="https://svn.boost.org/trac10/changeset/60923" title="Regenerate documentation. ">r60923</a> | chris_kohlhoff | 2010-03-30 10:57:25 +1100 (Tue, 30 Mar 2010) | 2 lines </p> </blockquote> <p> </p> <blockquote> <p> Regenerate documentation. </p> </blockquote> <p> ........ </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Dean Michael Berris</dc:creator> <pubDate>Mon, 29 Nov 2010 09:12:43 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3307#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:3</guid> <description> <p> Chris, did you mean to close this issue too? Should we mark this as <code>fixed</code>? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>chris_kohlhoff</dc:creator> <pubDate>Mon, 29 Nov 2010 09:17:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3307#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:4</guid> <description> <p> No, there are further API changes planned in relation to this issue. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>chris_kohlhoff</dc:creator> <pubDate>Wed, 23 Feb 2011 01:06:36 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3307#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:5</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/69194" title="Changes for asio version 1.5.0: * Added support for timeouts on ...">[69194]</a>) Changes for asio version 1.5.0: </p> <ul><li>Added support for timeouts on socket iostreams, such as ip::tcp::iostream. A timeout is set by calling expires_at() or expires_from_now() to establish a deadline. Any socket operations which occur past the deadline will put the iostream into a bad state. </li></ul><ul><li>Added a new error() member function to socket iostreams, for retrieving the error code from the most recent system call. </li></ul><ul><li>Added a new basic_deadline_timer::cancel_one() function. This function lets you cancel a single waiting handler on a timer. Handlers are cancelled in FIFO order. </li></ul><ul><li>Added a new transfer_exactly() completion condition. This can be used to send or receive a specified number of bytes even if the total size of the buffer (or buffer sequence) is larger. </li></ul><ul><li>Added new free functions connect() and async_connect(). These operations try each endpoint in a list until the socket is successfully connected. </li></ul><ul><li>Extended the buffer_size() function so that it works for buffer sequences in addition to individual buffers. </li></ul><ul><li>Added a new buffer_copy() function that can be used to copy the raw bytes between individual buffers and buffer sequences. </li></ul><ul><li>Added new non-throwing overloads of read(), read_at(), write() and write_at() that do not require a completion condition. </li></ul><ul><li>Added friendlier compiler errors for when a completion handler does not meet the necessary type requirements. When C++0x is available (currently supported for g++ 4.5 or later, and MSVC 10), static_assert is also used to generate an informative error message. Checking may be disabled by defining BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS. </li></ul><ul><li>Made the is_loopback(), is_unspecified() and is_multicast() functions consistently available across the ip::address, ip::address_v4 and ip::address_v6 classes. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3939" title="#3939: Feature Requests: Determination on wither ip::address is a multicast address (closed: fixed)">#3939</a>. </li></ul><ul><li>Added new non_blocking() functions for managing the non-blocking behaviour of a socket or descriptor. The io_control() commands named non_blocking_io are now deprecated in favour of these new functions. </li></ul><ul><li>Added new native_non_blocking() functions for managing the non-blocking mode of the underlying socket or descriptor. These functions are intended to allow the encapsulation of arbitrary non-blocking system calls as asynchronous operations, in a way that is transparent to the user of the socket object. The functions have no effect on the behaviour of the synchronous operations of the socket or descriptor. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3307" title="#3307: Bugs: Stream descriptor blocking state set on close (closed: fixed)">#3307</a>. </li></ul><ul><li>Added the io_control() member function for socket acceptors. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3297" title="#3297: Bugs: io_control not exposed on tcp::connector in asio (closed: fixed)">#3297</a>. </li></ul><ul><li>For consistency with the C++0x standard library, deprecated the native_type typedefs in favour of native_handle_type, and the native() member functions in favour of native_handle(). </li></ul><ul><li>Added a release() member function to posix descriptors. This function releases ownership of the underlying native descriptor to the caller. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3900" title="#3900: Feature Requests: Request for support of &#34;release&#34; member function or assign without ... (closed: fixed)">#3900</a>. </li></ul><ul><li>Added support for sequenced packet sockets (SOCK_SEQPACKET). </li></ul><ul><li>Added a new io_service::stopped() function that can be used to determine whether the io_service has stopped (i.e. a reset() call is needed prior to any further calls to run(), run_one(), poll() or poll_one()). </li></ul><ul><li>Reduced the copying of handler function objects. </li></ul><ul><li>Added support for C++0x move construction to further reduce copying of handler objects. Move support is enabled when compiling in -std=c++0x mode on g++ 4.5 or higher, or when using MSVC10. </li></ul><ul><li>Removed the dependency on OS-provided macros for the well-known IPv4 and IPv6 addresses. This should eliminate the annoying "missing braces around initializer" warnings. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3741" title="#3741: Bugs: asio::ip::address_v6.hpp: Missing braces around anonymous union (closed: fixed)">#3741</a>. </li></ul><ul><li>Reduced the size of ip::basic_endpoint&lt;&gt; objects (such as ip::tcp::endpoint and ip::udp::endpoint). </li></ul><ul><li>Changed the reactor backends to assume that any descriptors or sockets added using assign() may have been dup()-ed, and so require explicit deregistration from the reactor. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4971" title="#4971: Bugs: stream_descriptor not remove descriptor from epoll_reactor (closed: fixed)">#4971</a>. </li></ul><ul><li>Changed the SSL error category to return error strings from the OpenSSL library. </li></ul><ul><li>Changed the separate compilation support such that, to use Asio's SSL capabilities, you should also include 'asio/ssl/impl/src.hpp in one source file in your program. </li></ul><ul><li>Removed the deprecated member functions named io_service(). The get_io_service() member functions should be used instead. </li></ul><ul><li>Removed the deprecated typedefs resolver_query and resolver_iterator from the ip::tcp, ip::udp and ip::icmp classes. </li></ul><ul><li>Fixed a compile error on some versions of g++ due to anonymous enums. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4883" title="#4883: Patches: epoll_reactor.hpp doesn`t compile with some versions of gcc (closed: fixed)">#4883</a>. </li></ul><ul><li>Added an explicit cast to the FIONBIO constant to int to suppress a compiler warning on some platforms. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/5128" title="#5128: Bugs: Implicit constant overflow in non_blocking_io::name() (closed: fixed)">#5128</a>. </li></ul><ul><li>Fixed warnings reported by g++'s -Wshadow compiler option. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3905" title="#3905: Bugs: asio boost headers fail with g++-4.3.2 and -Wshadow -Werror (closed: fixed)">#3905</a>. </li></ul> </description> <category>Ticket</category> </item> <item> <dc:creator>chris_kohlhoff</dc:creator> <pubDate>Wed, 02 Mar 2011 08:28:04 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/3307#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3307#comment:6</guid> <description> <p> (In <a class="changeset" href="https://svn.boost.org/trac10/changeset/69467" title="* Add support for the fork() system call. Programs that use fork must ...">[69467]</a>) * Add support for the fork() system call. Programs that use fork must call </p> <blockquote> <p> io_service.notify_fork() at the appropriate times. Two new examples have been added showing how to use this feature. Refs <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3238" title="#3238: Bugs: asio, kqueue_reactor, result of kevent() isn't checked for error (closed: fixed)">#3238</a>, <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/4162" title="#4162: Feature Requests: io_service can't be used correctly after fork(). (closed: fixed)">#4162</a>. </p> </blockquote> <ul><li>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 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/3307" title="#3307: Bugs: Stream descriptor blocking state set on close (closed: fixed)">#3307</a>. </li></ul><ul><li>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 <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/5021" title="#5021: Bugs: io_service destructor hangs on Mac OS X (closed: fixed)">#5021</a>. </li></ul><ul><li>Include function name in exception what() messages. </li></ul><ul><li>Fix insufficient initialisers warning with MinGW. </li></ul><ul><li>Make the shutdown_service() member functions private. </li></ul><ul><li>Add archetypes for testing socket option functions. </li></ul><ul><li>Add missing lock in signal_set_service::cancel(). </li></ul><ul><li>Fix copy/paste error in <a class="missing wiki">SignalHandler</a> example. </li></ul><ul><li>The signal header needs to be included in signal_set_service.hpp so that we can use constants like NSIG and SIGRTMAX. </li></ul><ul><li>Don't use Boost.Thread's convenience header. Use the header file that is specifically for the boost::thread class instead. </li></ul> </description> <category>Ticket</category> </item> <item> <dc:creator>chris_kohlhoff</dc:creator> <pubDate>Mon, 06 Jun 2011 01:42:05 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3307#comment:7 https://svn.boost.org/trac10/ticket/3307#comment:7 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Merged to release branch in <a class="changeset" href="https://svn.boost.org/trac10/changeset/72428" title="Merge asio from trunk.">[72428]</a>. </p> Ticket