Uploaded image for project: 'C Driver'
  1. C Driver
  2. CDRIVER-4067

Debug assertion mutex_is_locked is incorrect if lock occurs during a condition variable wait

    • Type: Icon: Task Task
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Testing
    • Labels:

      Motivation
      The mutex_is_locked is a debug test assertion to enforce the expectation that a mutex is locked in functions that expect callers to lock. It is only enabled in tests on Linux when -DENABLE_DEBUG_ASSERTIONS=ON is configured.

      It breaks down in the case where:

      • Thread T1 locks L
      • Thread T1 waits on a condition variable CV with lock L
      • While T1 is waiting, thread T2 locks and unlocks L
      • T1 wakes up, and does hold the lock L, but mutex_is_locked returns false.

      Scope
      To keep mutex_is_locked working correctly, the condition variable functions mongoc_cond_wait and mongoc_cond_timedwait should be overridden to work with the debug form of bson_mutex_t.

      Repro
      The following is a test written to show the bug:

      #include "mongoc/mongoc-thread-private.h"
      
      #include "TestSuite.h"
      #include "test-libmongoc.h"
      
      /* Locks and unlocks the passed mutex */
      BSON_THREAD_FUN (locker_fn, arg)
      {
         bson_mutex_t *lock = (bson_mutex_t *) arg;
         /* Wait 10ms. */
         _mongoc_usleep (10 * 1000);
         bson_mutex_lock (lock);
         bson_mutex_unlock (lock);
         return NULL;
      }
      
      /* Test the mutex_is_locked assertion when a mutex is locked/unlocked by another
       * thread while waiting for a condition variable.
       *
       * This requires compiling on Linux and configuring cmake with
       * -DENABLE_DEBUG_ASSERTIONS
       */
      static void
      test_mutex_assertion (void *unused)
      {
         bson_mutex_t mutex;
         mongoc_cond_t cond;
         bson_thread_t locker_thread;
      
         bson_mutex_init (&mutex);
         mongoc_cond_init (&cond);
      
         COMMON_PREFIX (thread_create) (&locker_thread, locker_fn, &mutex);
         int r = mongoc_cond_timedwait (&cond, &mutex, 100);
         COMMON_PREFIX (thread_join) (locker_thread);
         BSON_ASSERT (r == ETIMEDOUT);
         BSON_ASSERT (COMMON_PREFIX (mutex_is_locked (&mutex))); /* Fails */
         bson_mutex_unlock (&mutex);
      
         mongoc_cond_destroy (&cond);
         bson_mutex_destroy (&mutex);
      }
      
      
      void
      test_thread_install (TestSuite *suite)
      {
         TestSuite_AddFull (suite,
                            "/Thread/mutex_assertion",
                            test_mutex_assertion,
                            NULL /* dtor */,
                            NULL /* ctx */,
                            NULL);
      }
      

            Assignee:
            Unassigned Unassigned
            Reporter:
            kevin.albertson@mongodb.com Kevin Albertson
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: