2

In my code I use ACE_Mutex from the ACE library on a system (QNX) that has pthreads. Now I'm experiencing the problem that it seems like the destructor of ACE_Mutex doesn't call pthread_mutex_destroy. This gives trouble when a subsequent mutex at the same memory location is initialized, because pthread_mutex_init returns errno=16 (EBUSY).

Looking at the code of ACE_Mutex::remove (in Mutex.inl), I see a strange set of precompiler directives:

ACE_INLINE int
ACE_Mutex::remove (void)
{
// ACE_TRACE ("ACE_Mutex::remove");
  int result = 0;
#if defined (ACE_HAS_PTHREADS) || defined (ACE_HAS_STHREADS)
  // In the case of a interprocess mutex, the owner is the first
  // process that created the shared memory object. In this case, the
  // lockname_ pointer will be non-zero (points to allocated memory
  // for the name).  Owner or not, the memory needs to be unmapped
  // from the process.  If we are the owner, the file used for
  // shm_open needs to be deleted as well.
  if (this->process_lock_)
    {
      if (this->removed_ == false)
        {
          this->removed_ = true;
          // Only destroy the lock if we're the ones who initialized
          // it.
          if (!this->lockname_)
            ACE_OS::munmap ((void *) this->process_lock_,
                            sizeof (ACE_mutex_t));
          else
            {
              result = ACE_OS::mutex_destroy (this->process_lock_);
              ACE_OS::munmap ((void *) this->process_lock_,
                              sizeof (ACE_mutex_t));
              ACE_OS::shm_unlink (this->lockname_);
              ACE_OS::free (
                static_cast<void *> (
                  const_cast<ACE_TCHAR *> (this->lockname_)));
            }
        }
    }
  else
  {
#else /* !ACE_HAS_PTHREADS && !ACE_HAS_STHREADS */
    if (this->removed_ == false)
      {
        this->removed_ = true;
        result = ACE_OS::mutex_destroy (&this->lock_);
      }
#endif /* ACE_HAS_PTHREADS || ACE_HAS_STHREADS */
#if defined (ACE_HAS_PTHREADS) || defined (ACE_HAS_STHREADS)
  }
#endif /* ACE_HAS_PTHREADS || ACE_HAS_STHREADS */
  return result;
}

Specifically I don't understand why the call to ACE_OS::mutex_destroy is conditional and thus not called when pthreads are enabled. This effectively renders the remove method empty-bodied for non-interprocess mutexes. Can someone explain the rationale for this piece of code?

Kris
  • 2,108
  • 18
  • 19
  • Aren't those comments in the beginning of the function make it crystal clear that you don't destroy what you haven't created? –  Nov 30 '12 at 14:05
  • Hmm... the `#if defined(PTHREADS)` block also calls `ACE_OS::mutex_destroy`, but only if your process was the one that created the mutex. – Christian.K Nov 30 '12 at 14:06
  • @VladLazarenko: yes, but I'm not using an interprocess mutex. Just a simple thread mutex. So you end up in the else part, which is empty for pthreads. – Kris Nov 30 '12 at 15:24
  • Wow - that sure looks like a bug, and from browsing the SVN web interface it's a pretty long standing bug. That makes me feel like I must be missing something, but it really does appear that you're right. – Michael Burr Dec 01 '12 at 11:17
  • 2
    ACE_Mutex is hardly used, I would recommend you use an ACE_Thread_Mutex and at the same moment report an issue on the ACE mailing list for this – Johnny Willemsen Dec 03 '12 at 08:34
  • @JohnnyWillemsen: that's exactly what I did to resolve the issue. I'll report the possible bug on the mailing list. Thanks. – Kris Dec 03 '12 at 10:39

0 Answers0