[vlc-devel] [PATCH] win32: in debug builds make sure the non-recursive locks are not reentrant

Steve Lhomme robux4 at gmail.com
Sun Jun 5 14:55:15 CEST 2016


On Sun, Jun 5, 2016 at 2:41 PM, Rémi Denis-Courmont <remi at remlab.net> wrote:
> Le 2016-06-05 14:35, Steve Lhomme a écrit :
>>
>> Use a semaphore with a single token for non recursive locks
>> Use the same code as non-debug builds with recursive locks
>>
>> --
>> hopefully fixes the make check header issue in
>> https://patches.videolan.org/patch/13618/
>> ---
>>  include/vlc_threads.h |  4 ++++
>>  src/win32/thread.c    | 49
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 53 insertions(+)
>>
>> diff --git a/include/vlc_threads.h b/include/vlc_threads.h
>> index 33b9b53..08b10f2 100644
>> --- a/include/vlc_threads.h
>> +++ b/include/vlc_threads.h
>> @@ -66,6 +66,10 @@ typedef struct
>>              unsigned long contention;
>>          };
>>          CRITICAL_SECTION mutex;
>> +
>> +        /* non-recursive semaphore */
>> +        HANDLE hMutex;
>> +        unsigned long lock_thread_id;
>>      };
>>  } vlc_mutex_t;
>>  #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
>> diff --git a/src/win32/thread.c b/src/win32/thread.c
>> index 963a8d7..0fab5ad 100644
>> --- a/src/win32/thread.c
>> +++ b/src/win32/thread.c
>> @@ -43,6 +43,12 @@
>>  static vlc_mutex_t super_mutex;
>>  static vlc_cond_t  super_variable;
>>
>> +#ifndef NDEBUG
>> +#define MUTEX_ALWAYS_RECURSIVE 0
>> +#else
>> +#define MUTEX_ALWAYS_RECURSIVE 1
>> +#endif
>> +
>>  #define IS_INTERRUPTIBLE (!VLC_WINSTORE_APP || _WIN32_WINNT >= 0x0A00)
>>
>>  /*** Threads ***/
>> @@ -71,13 +77,20 @@ void vlc_mutex_init( vlc_mutex_t *p_mutex )
>>  {
>>      /* This creates a recursive mutex. This is OK as fast mutexes have
>>       * no defined behavior in case of recursive locking. */
>> +#if MUTEX_ALWAYS_RECURSIVE
>>      InitializeCriticalSection (&p_mutex->mutex);
>> +#else
>> +    p_mutex->hMutex = CreateSemaphore( NULL, 1, 1, NULL );
>> +#endif
>
>
> Isn't a mutex a lot slower than a critical section, as it's a kernel handle?
> If you want to rule out recursive locking, you just need a boolean on top of
> the critical section, AFAICT.

Yes, that might work.

>>      p_mutex->dynamic = true;
>>  }
>>
>>  void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
>>  {
>>      InitializeCriticalSection( &p_mutex->mutex );
>> +#if !MUTEX_ALWAYS_RECURSIVE
>> +    p_mutex->hMutex = INVALID_HANDLE_VALUE;
>> +#endif
>>      p_mutex->dynamic = true;
>>  }
>>
>> @@ -85,6 +98,11 @@ void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
>>  void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
>>  {
>>      assert (p_mutex->dynamic);
>> +#if !MUTEX_ALWAYS_RECURSIVE
>> +    if ( p_mutex->hMutex != INVALID_HANDLE_VALUE )
>> +        CloseHandle( p_mutex->hMutex );
>> +    else
>> +#endif
>>      DeleteCriticalSection (&p_mutex->mutex);
>>  }
>>
>> @@ -108,6 +126,15 @@ void vlc_mutex_lock (vlc_mutex_t *p_mutex)
>>          return;
>>      }
>>
>> +#if !MUTEX_ALWAYS_RECURSIVE
>> +    if ( p_mutex->hMutex != INVALID_HANDLE_VALUE )
>> +    {
>> +        assert(p_mutex->lock_thread_id != vlc_thread_id());
>
>
> What prevents another thread from writing lock_thread_id concurrently?

The only way the assert will fail is if the lock is actually locked by
the same thread. If it doesn't assert, it may still produce a deadlock
that can still be debugged.

>> +        WaitForSingleObject( p_mutex->hMutex, INFINITE );
>> +        p_mutex->lock_thread_id = vlc_thread_id();
>> +    }
>> +    else
>> +#endif
>>      EnterCriticalSection (&p_mutex->mutex);
>>  }
>>
>> @@ -128,6 +155,20 @@ int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
>>          return ret;
>>      }
>>
>> +#if !MUTEX_ALWAYS_RECURSIVE
>> +    if ( p_mutex->hMutex != INVALID_HANDLE_VALUE )
>> +    {
>> +        assert(p_mutex->lock_thread_id != vlc_thread_id());
>> +        if ( WaitForSingleObject( p_mutex->hMutex, 0 ) == WAIT_OBJECT_0 )
>> +        {
>> +            p_mutex->lock_thread_id = vlc_thread_id();
>> +            return 0;
>> +        }
>> +        else
>> +            return EBUSY;
>> +    }
>> +    else
>> +#endif
>>      return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
>>  }
>>
>> @@ -146,6 +187,14 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
>>          return;
>>      }
>>
>> +#if !MUTEX_ALWAYS_RECURSIVE
>> +    if ( p_mutex->hMutex != INVALID_HANDLE_VALUE )
>> +    {
>> +        p_mutex->lock_thread_id = 0;
>> +        ReleaseSemaphore( p_mutex->hMutex, 1, NULL );
>> +    }
>> +    else
>> +#endif
>>      LeaveCriticalSection (&p_mutex->mutex);
>>  }
>
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list