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

Rémi Denis-Courmont remi at remlab.net
Sun Jun 5 15:47:21 CEST 2016


Le 2016-06-05 14:55, Steve Lhomme a écrit :
> 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.

The assert is undefined if another thread writes the value, either to 
lock or unlock the mutex. And I don't see how you ensure that is not 
happening concurrently.

>
>>> +        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
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

-- 
Rémi Denis-Courmont
http://www.remlab.net/


More information about the vlc-devel mailing list