Re: std::mutex bug: Windows handle growth

Corinna Vinschen via Cygwin <[email protected]>
Newsgroups gmane.os.cygwin
Message-ID <[email protected]>
On Mar 17 18:40, ASSI via Cygwin wrote:
> Frank Eskesen via Cygwin writes:
> > I've run into a problem that occurs on Cygwin that doesn't occur on
> > Linux systems: When a std::mutex is used, it doesn't clean up a
> > Windows handle that it uses. This sample program demonstrates the
> > problem, failing in under 60 seconds. Run this while using Window task
> > manager to watch the handle count rise. On my machine, the count
> > rapidly grows to about 16 million and then a std::exception is thrown.
> 
> This is likely a bug in upstream libstadc++, more specifically by making
> a wrong assumption about the behaviour of the pthread library.  It looks
> like Corinna has identified a potential workaround, but that is a bit
> hack-ish and I'd rather not carry such a patch that will likely not get
> accepted upstream.
> 
> Can you please report this bug upstream and send the link to the
> bugreport here?  Meanwhile, I'd be interested to know if maybe that was
> already fixed in a later version of gcc / libstdc++, so if you could try
> one (or all) of the gcc test versions on your code that would be
> helpful.

My assumption is more or less correct, I was just looking cross-eyed
into the class definition for a while.  Here's the code in question from
bits/std_mutex.h:

--- SNIP ---

  class __mutex_base
  {
  protected:
    typedef __gthread_mutex_t                   __native_type;

#ifdef __GTHREAD_MUTEX_INIT
    __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;

    constexpr __mutex_base() noexcept = default;
#else
    __native_type  _M_mutex;

    __mutex_base() noexcept
    {
      // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
      __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
    }

    ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
#endif

    __mutex_base(const __mutex_base&) = delete;
    __mutex_base& operator=(const __mutex_base&) = delete;
  };

--- SNAP ---

The actual problem here is the `#ifdef __GTHREAD_MUTEX_INIT'.

__GTHREAD_MUTEX_INIT translates into PTHREAD_MUTEX_INIT.  If this is
defined, you will notice the there's *no* destructor defined for class
__mutex_base.  Apparently the assumption is made that the underlying
pthread_mutex_t type is a trivial type which doesn't need a destroy(),
if PTHREAD_MUTEX_INIT exists.

However, this is wrong for Cygwin.  It defines PTHREAD_MUTEX_INIT, but
it still needs a pthread_mutex_destroy() call, because the pthread_mutex_t
type is not a trivial one.

Thus, we need a destructor even if __GTHREAD_MUTEX_INIT is defined.

A potential fix would be 

diff --git a/libstdc++-v3/include/bits/std_mutex.h b/libstdc++-v3/include/bits/std_mutex.h
index 7ef33fe5d0d7..f060c75abf21 100644
--- a/libstdc++-v3/include/bits/std_mutex.h
+++ b/libstdc++-v3/include/bits/std_mutex.h
@@ -68,6 +68,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __native_type  _M_mutex = __GTHREAD_MUTEX_INIT;
 
     constexpr __mutex_base() noexcept = default;
+#ifdef __CYGWIN__
+    ~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
+#endif
 #else
     __native_type  _M_mutex;

@Stromeko, can you please discuss this upstream?
 

Thanks,
Corinna

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.