Boost C++ Libraries: Ticket #3238: asio, kqueue_reactor, result of kevent() isn't checked for error https://svn.boost.org/trac10/ticket/3238 <p> No kevent() result checking. </p> <pre class="wiki">asio/detail/kqueue_reactor.hpp:438 ... wait_in_progress_ = true; lock.unlock(); // Block on the kqueue descriptor. struct kevent events[128]; int num_events = (block || need_kqueue_wait_) ? kevent(kqueue_fd_, 0, 0, events, 128, timeout) : 0; lock.lock(); wait_in_progress_ = false; // Block signals while performing operations. boost::asio::detail::signal_blocker sb; // Dispatch the waiting events. for (int i = 0; i &lt; num_events; ++i) { // processing events ... </pre><p> Here is <strong>int num_events = kevent(kqueue_fd_, ...</strong>, then <strong>for (int i = 0; i &lt; num_events</strong> but <strong>num_events</strong> can be -1 here, and all this code makes no sense then. </p> <p> Suppose we have such code: </p> <pre class="wiki">smtp_queue q("/var/spool/smtpq"); asio::io_service io_service; smtp_server s(io_service, 25, q); smtp_client c(io_service, "target.host", "smtp", q); if(fork()) exit(0); // daemonize io_service.run(); </pre><p> Here we call <strong>fork()</strong> then <strong>io_service.run()</strong>. fork doesn't copy kqueue descriptor and subsequent kevent(fd,...) calls return -1 with errno = 9 (EBADFD, "Bad file descriptor"). This case makes asio's kqueue reactor hangup. Probably, kevent() result should be checked for error and exception thrown if any. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3238 Trac 1.4.3 anonymous Mon, 29 Nov 2010 05:12:40 GMT status, version changed; resolution set https://svn.boost.org/trac10/ticket/3238#comment:1 https://svn.boost.org/trac10/ticket/3238#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>version</strong> <span class="trac-field-old">Boost 1.38.0</span> → <span class="trac-field-new">Boost Development Trunk</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> This appears to have been fixed, at least in trunk. Marking as fixed. </p> <p> Please re-open in case the symptom still exhibits. Unfortunately, I don't think sharing the already initialized io_service across processes is supported (unless I'm missing something). At any rate, the code in question has since been refactored and the implementation handles the case where kevent(...) is -1. </p> Ticket chris_kohlhoff Mon, 29 Nov 2010 06:40:10 GMT status changed; milestone set; resolution deleted https://svn.boost.org/trac10/ticket/3238#comment:2 https://svn.boost.org/trac10/ticket/3238#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">closed</span> → <span class="trac-field-new">reopened</span> </li> <li><strong>resolution</strong> <span class="trac-field-deleted">fixed</span> </li> <li><strong>milestone</strong> → <span class="trac-field-new">To Be Determined</span> </li> </ul> <p> This is a difficult to fix rainy-day bug. It is not fixed on trunk. Please see: </p> <p> <a class="ext-link" href="http://article.gmane.org/gmane.comp.lib.boost.asio.user/3383"><span class="icon">​</span>http://article.gmane.org/gmane.comp.lib.boost.asio.user/3383</a> </p> <p> The following program will reproduce the issue: </p> <pre class="wiki">#include &lt;boost/asio/io_service.hpp&gt; #include &lt;boost/asio/ip/udp.hpp&gt; #include &lt;iostream&gt; int main() { boost::asio::io_service io_service; boost::asio::io_service::work work(io_service); boost::asio::use_service&lt; boost::asio::ip::udp::socket::service_type&gt;( io_service); if (fork()) exit(0); io_service.run(); } </pre><p> On Mac OS X, kevent() failure means the forked child consumes 100% CPU. Compiling with -DBOOST_ASIO_DISABLE_KQUEUE gives the desired behaviour, which is that the forked child consumes no CPU. </p> Ticket devel@… Mon, 29 Nov 2010 08:34:05 GMT <link>https://svn.boost.org/trac10/ticket/3238#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3238#comment:3</guid> <description> <p> rfork(RFPROC) (no RFFDG) does a trick on *BSD </p> </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/3238#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/3238#comment:4</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:49:22 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/3238#comment:5 https://svn.boost.org/trac10/ticket/3238#comment:5 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</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