Boost C++ Libraries: Ticket #7461: detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 https://svn.boost.org/trac10/ticket/7461 <p> <a class="missing wiki">ReleaseSemaphore</a> is documented by Microsoft as: "... lReleaseCount [in] The amount by which the semaphore object's current count is to be increased. The value must be greater than zero" <a class="ext-link" href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms685071(v=vs.85).aspx"><span class="icon">​</span>http://msdn.microsoft.com/en-us/library/windows/desktop/ms685071(v=vs.85).aspx</a> </p> <p> When I run boundschecker on boost threads, I get a error because count_to_release is 0 in the following: </p> <blockquote> <p> void release(unsigned count_to_release) { </p> <blockquote> <p> notified=true; detail::win32::<a class="missing wiki">ReleaseSemaphore</a>(semaphore,count_to_release,0); </p> </blockquote> <p> } </p> </blockquote> <p> (this is line 71 in boost_1_51_0/boost/thread/win32/condition_variable.hpp) </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7461 Trac 1.4.3 Jesper Storm Bache <jsbache@…> Tue, 02 Oct 2012 20:01:34 GMT summary changed https://svn.boost.org/trac10/ticket/7461#comment:1 https://svn.boost.org/trac10/ticket/7461#comment:1 <ul> <li><strong>summary</strong> <span class="trac-field-old">detail::win32::ReleaseSemaphore may be called with count_to_release euql to 0</span> → <span class="trac-field-new">detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0</span> </li> </ul> Ticket viboes Tue, 09 Oct 2012 23:35:45 GMT owner, status, version changed https://svn.boost.org/trac10/ticket/7461#comment:2 https://svn.boost.org/trac10/ticket/7461#comment:2 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> <li><strong>version</strong> <span class="trac-field-old">Boost 1.52.0</span> → <span class="trac-field-new">Boost 1.51.0</span> </li> </ul> Ticket viboes Wed, 10 Oct 2012 23:21:23 GMT <link>https://svn.boost.org/trac10/ticket/7461#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:3</guid> <description> <p> Hi, </p> <p> I don't know how the tool you are using has deduced such an issue. </p> <p> The count_to_release parameter seems to be always &gt; 0. </p> <p> Please let me know if I'm missing something. </p> <p> Either it is called with 1 </p> <pre class="wiki"> for(generation_list::iterator it=generations.begin(), end=generations.end(); it!=end;++it) { (*it)-&gt;release(1); } </pre><p> or with the contents of waiters. </p> <pre class="wiki"> void release_waiters() { release(detail::interlocked_read_acquire(&amp;waiters)); } </pre><p> This variable is initialized as follows </p> <pre class="wiki"> waiters(1),notified(false),references(0) </pre><p> and updated by </p> <pre class="wiki"> void add_waiter() { BOOST_INTERLOCKED_INCREMENT(&amp;waiters); } void remove_waiter() { BOOST_INTERLOCKED_DECREMENT(&amp;waiters); } </pre><p> But remove_waiter is always called after add_waiter </p> <pre class="wiki"> entry_ptr get_wait_entry() { boost::lock_guard&lt;boost::mutex&gt; internal_lock(internal_mutex); if(!wake_sem) { wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); BOOST_ASSERT(wake_sem); } detail::interlocked_write_release(&amp;total_count,total_count+1); if(generations.empty() || generations.back()-&gt;is_notified()) { entry_ptr new_entry(new list_entry(wake_sem)); generations.push_back(new_entry); return new_entry; } else { generations.back()-&gt;add_waiter(); return generations.back(); } } struct entry_manager { entry_ptr const entry; BOOST_THREAD_NO_COPYABLE(entry_manager) entry_manager(entry_ptr const&amp; entry_): entry(entry_) {} ~entry_manager() { entry-&gt;remove_waiter(); } list_entry* operator-&gt;() { return entry.get(); } }; protected: template&lt;typename lock_type&gt; bool do_wait(lock_type&amp; lock,timeout abs_time) { relocker&lt;lock_type&gt; locker(lock); entry_manager entry(get_wait_entry()); locker.unlock(); bool woken=false; while(!woken) { if(!entry-&gt;wait(abs_time)) { return false; } woken=entry-&gt;woken(); } return woken; } </pre><p> Any deep explanation of on which circumstances this issue appear is welcome. </p> </description> <category>Ticket</category> </item> <item> <author>jsbache@…</author> <pubDate>Thu, 11 Oct 2012 17:25:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:4</guid> <description> <p> I apologize for the terseness. Here are a few detais. When I notice a zero count, the stack is: </p> <blockquote> <p> c4test.exe!boost::detail::basic_cv_list_entry::release(unsigned int count_to_release=0) Line 68 c4test.exe!boost::detail::basic_cv_list_entry::release_waiters() Line 73 </p> </blockquote> <blockquote> <p> c4test.exe!boost::detail::basic_condition_variable::notify_all() Line 285 + 0x1a bytes </p> </blockquote> <p> My conditional breakpoint (condition: "count_to_release == 0) is on the following line (before we modify notified) </p> <pre class="wiki"> void release(unsigned count_to_release) { --break-- notified=true; </pre><p> When I hit this, code I have the following state of the local variables. Note that notified = true at this point in time, </p> <pre class="wiki">it {px=0x0000000001dde7b0 } [ptr] 0x0000000001dd75b8 {px=0x0000000001dde7b0 } px 0x0000000001dde7b0 semaphore {handle_to_manage=0x0000000000000100 } wake_sem {handle_to_manage=0x0000000000000184 } waiters 0 notified true references 1 this 0x00000000003dee28 internal_mutex {...} boost::mutex total_count 0 long active_generation_count 0 unsigned int generations [2]({px=0x0000000001dde630 },{px=0x0000000001dde7b0 }) wake_sem {handle_to_manage=0x0000000000000198 } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 12 Oct 2012 22:18:58 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:5</guid> <description> <p> Thanks for the details. Please, could you attach the example? Could you see when waiters become 0? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 12 Oct 2012 22:42:24 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:6</guid> <description> <p> Hi again, </p> <p> I think I have an hint. Could you check if defining ~entry_manager as follows avoid the problem? </p> <pre class="wiki"> ~entry_manager() { if(! entry-&gt;is_notified()) { entry-&gt;remove_waiter(); } } </pre> </description> <category>Ticket</category> </item> <item> <author>jsbache@…</author> <pubDate>Fri, 12 Oct 2012 23:05:57 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:7</guid> <description> <p> The proposed solution does solve the issue, meaning that with this change I no longer observe a call to basic_cv_list_entry::release with count_to_release equal to 0. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 13 Oct 2012 13:46:49 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:8</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7461#comment:7" title="Comment 7">jsbache@…</a>: </p> <blockquote class="citation"> <p> The proposed solution does solve the issue, meaning that with this change I no longer observe a call to basic_cv_list_entry::release with count_to_release equal to 0. </p> </blockquote> <p> Thanks for checking. I will apply the modification and run the test on windows as soon as i have access to a windows machine. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 20 Oct 2012 09:30:21 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/7461#comment:9 https://svn.boost.org/trac10/ticket/7461#comment:9 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.52.0</span> </li> </ul> Ticket viboes Sat, 20 Oct 2012 15:20:18 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/7461#comment:10 https://svn.boost.org/trac10/ticket/7461#comment:10 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Committed revision <a class="changeset" href="https://svn.boost.org/trac10/changeset/81024" title="Thread: merge 80986">[81024]</a>. </p> Ticket viboes Thu, 08 Nov 2012 18:53:50 GMT status changed; resolution deleted https://svn.boost.org/trac10/ticket/7461#comment:11 https://svn.boost.org/trac10/ticket/7461#comment:11 <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> </ul> <p> Hi, </p> <p> it seems that the patch introduce a severe restriction, see <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/7657" title="#7657: Bugs: Serious performance and memory consumption hit if condition_variable ... (closed: fixed)">#7657</a>. I will rollback the change and take the time to analyze your issue. </p> Ticket viboes Sat, 10 Nov 2012 11:50:10 GMT milestone changed https://svn.boost.org/trac10/ticket/7461#comment:12 https://svn.boost.org/trac10/ticket/7461#comment:12 <ul> <li><strong>milestone</strong> <span class="trac-field-old">Boost 1.52.0</span> → <span class="trac-field-new">To Be Determined</span> </li> </ul> Ticket viboes Sun, 09 Jun 2013 20:13:13 GMT status changed https://svn.boost.org/trac10/ticket/7461#comment:13 https://svn.boost.org/trac10/ticket/7461#comment:13 <ul> <li><strong>status</strong> <span class="trac-field-old">reopened</span> → <span class="trac-field-new">new</span> </li> </ul> Ticket viboes Sun, 09 Jun 2013 20:13:26 GMT status changed https://svn.boost.org/trac10/ticket/7461#comment:14 https://svn.boost.org/trac10/ticket/7461#comment:14 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket viboes Sat, 14 Sep 2013 15:24:39 GMT <link>https://svn.boost.org/trac10/ticket/7461#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:15</guid> <description> <p> Hi, </p> <p> I don't reach to understand how your issue can arrive. </p> <p> Could you add a small example reproduce the issue? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 15 Sep 2013 16:12:30 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7461#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7461#comment:16</guid> <description> <p> I suspect that the following sequence is possible. </p> <ol><li>thread A call wait and it stands in <a class="changeset" href="https://svn.boost.org/trac10/changeset/1" title="Import core sources for SVNmanger 0.38 ">[1]</a> below. The value for waiters is 1. </li><li>thread B notify_all and after wake the waiters in <a class="changeset" href="https://svn.boost.org/trac10/changeset/2" title="Add Boost Disclaimer">[2]</a> the scheduler choose the ready thread A. </li><li>thread A ends the call to do_wait and the entry_manager destructor calls. The value for waiters is 0. in <a class="changeset" href="https://svn.boost.org/trac10/changeset/3" title="Tweak disclaimer text">[3]</a> the scheduler choose the ready thread B. </li><li>thread B calls release_waiters() in <a class="changeset" href="https://svn.boost.org/trac10/changeset/4" title="Tweak disclaimer formatting, again">[4]</a> which calls to release(0). </li></ol><p> Current Code </p> <pre class="wiki"> template&lt;typename lock_type&gt; bool do_wait(lock_type&amp; lock,timeout abs_time) { relocker&lt;lock_type&gt; locker(lock); entry_manager entry(get_wait_entry()); locker.unlock(); bool woken=false; while(!woken) { if(!entry-&gt;wait(abs_time)) // [1] { return false; } woken=entry-&gt;woken(); } return woken; } // [3] void notify_all() BOOST_NOEXCEPT { if(detail::interlocked_read_acquire(&amp;total_count)) { boost::lock_guard&lt;boost::mutex&gt; internal_lock(internal_mutex); if(!total_count) { return; } wake_waiters(total_count); // [2] for(generation_list::iterator it=generations.begin(), end=generations.end(); it!=end;++it) { (*it)-&gt;release_waiters(); [4] } generations.clear(); wake_sem=detail::win32::handle(0); } } </pre><p> I suspect that the call to entry-&gt;remove_waiter() inside entry_manager() must be protected </p> <p> Could some one check if the following patch for boost/thread/win32/condition_variable.hpp works </p> <pre class="wiki">=================================================================== --- condition_variable.hpp (revision 85663) +++ condition_variable.hpp (working copy) @@ -191,18 +191,17 @@ struct entry_manager { entry_ptr const entry; + boost::mutex&amp; internal_mutex; BOOST_THREAD_NO_COPYABLE(entry_manager) - entry_manager(entry_ptr const&amp; entry_): - entry(entry_) + entry_manager(entry_ptr const&amp; entry_, boost::mutex&amp; mutex_): + entry(entry_), internal_mutex(mutex_) {} ~entry_manager() { - //if(! entry-&gt;is_notified()) // several regression #7657 - { + boost::lock_guard&lt;boost::mutex&gt; internal_lock(internal_mutex); entry-&gt;remove_waiter(); - } } list_entry* operator-&gt;() @@ -218,7 +217,7 @@ { relocker&lt;lock_type&gt; locker(lock); - entry_manager entry(get_wait_entry()); + entry_manager entry(get_wait_entry(), internal_mutex); locker.unlock(); </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Tue, 17 Sep 2013 21:01:37 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/7461#comment:17 https://svn.boost.org/trac10/ticket/7461#comment:17 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.55.0</span> </li> </ul> <p> Committed revision <a class="changeset" href="https://svn.boost.org/trac10/changeset/85733" title="Thread: try to fix win32 condition_variable issue #7461.">[85733]</a>. </p> Ticket viboes Sat, 21 Sep 2013 20:47:37 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/7461#comment:18 https://svn.boost.org/trac10/ticket/7461#comment:18 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Committed revision <a class="changeset" href="https://svn.boost.org/trac10/changeset/85815" title="Thread: merge from trunk to fix 8070 and possibly 7461.">[85815]</a>. </p> Ticket