On 2011-12-06 21:08:39 -0800, Ronald S. Bultje wrote:
> On Tue, Dec 6, 2011 at 8:33 PM, Ronald S. Bultje <[email protected]> wrote:
> >
> > Attached patch ports x264's layer. 100% untested.
> >
> 
> This one is tested, works. I'm not claiming copyright over it, just being
> the messenger.
> 
> From 6f27c3c25449978b8ded361d939b8cdf1e8aa8f4 Mon Sep 17 00:00:00 2001
> From: Ronald S. Bultje <[email protected]>
> Date: Tue, 6 Dec 2011 20:42:55 -0800
> Subject: [PATCH] w32thread: port fixes to pthread_cond_broadcast() from x264.
> 
> ---
>  libavcodec/w32pthreads.h |   54 +++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 46 insertions(+), 8 deletions(-)
> 
> diff --git a/libavcodec/w32pthreads.h b/libavcodec/w32pthreads.h
> index c015b87..95dcdaa 100644
> --- a/libavcodec/w32pthreads.h
> +++ b/libavcodec/w32pthreads.h
> @@ -115,9 +115,12 @@ static inline int pthread_mutex_unlock(pthread_mutex_t 
> *m)
>  /* for pre-Windows 6.0 platforms we need to define and use our own condition
>   * variable and api */
>  typedef struct {
> +    pthread_mutex_t mtx_broadcast;
>      pthread_mutex_t mtx_waiter_count;
>      volatile int waiter_count;
>      HANDLE semaphore;
> +    HANDLE waiters_done;
> +    int is_broadcast;
>  } win32_cond_t;
>  
>  static void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
> @@ -136,8 +139,12 @@ static void pthread_cond_init(pthread_cond_t *cond, 
> const void *unused_attr)
>      win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
>      if (!win32_cond->semaphore)
>          return;
> +    win32_cond->waiters_done = CreateEvent(NULL, FALSE, FALSE, NULL);
> +    if (!win32_cond->waiters_done)
> +        return -1;
>  
>      pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL);
> +    pthread_mutex_init(&win32_cond->mtx_broadcast, NULL);
>  }
>  
>  static void pthread_cond_destroy(pthread_cond_t *cond)
> @@ -149,7 +156,9 @@ static void pthread_cond_destroy(pthread_cond_t *cond)
>  
>      /* non native condition variables */
>      CloseHandle(win32_cond->semaphore);
> +    CloseHandle(win32_cond->waiters_done);
>      pthread_mutex_destroy(&win32_cond->mtx_waiter_count);
> +    pthread_mutex_destroy(&win32_cond->mtx_broadcast);
>      av_freep(&win32_cond);
>      cond->ptr = NULL;
>  }
> @@ -157,41 +166,70 @@ static void pthread_cond_destroy(pthread_cond_t *cond)
>  static void pthread_cond_broadcast(pthread_cond_t *cond)
>  {
>      win32_cond_t *win32_cond = cond->ptr;
> +    int have_waiter;
> +
>      if (cond_broadcast) {
>          cond_broadcast(cond);
>          return;
>      }
>  
>      /* non native condition variables */
> +    pthread_mutex_lock(&win32_cond->mtx_broadcast);
>      pthread_mutex_lock(&win32_cond->mtx_waiter_count);
> +    have_waiter = 0;
> +
>      if (win32_cond->waiter_count) {
> -        ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, 
> NULL);
> -        win32_cond->waiter_count = 0;
> +        win32_cond->is_broadcast = 1;
> +        have_waiter = 1;
>      }
> -    pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
> +
> +    if (have_waiter) {

I don't see why have_waiter is needed here, it makes 

> +        ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, 
> NULL);
> +        pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
> +        WaitForSingleObject(win32_cond->waiters_done, INFINITE);
> +        win32_cond->is_broadcast = 0;
> +    } else
> +        pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
> +    pthread_mutex_unlock(&win32_cond->mtx_broadcast);
>  }
>  
>  static void pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
>  {
>      win32_cond_t *win32_cond = cond->ptr;
> +    int last_waiter;
>      if (cond_wait) {
>          cond_wait(cond, mutex, INFINITE);
>          return;
>      }
>  
>      /* non native condition variables */
> +    pthread_mutex_lock(&win32_cond->mtx_broadcast);
> +    pthread_mutex_unlock(&win32_cond->mtx_broadcast);
> +
>      pthread_mutex_lock(&win32_cond->mtx_waiter_count);

any reason why locking mtx_waiter_count is not done while mtx_broadcast
is locked? I think this could theoretically dead lock if waiter_count
is increased after the next broadcast was called.

I have seen that you just copied from x264.

>      win32_cond->waiter_count++;
>      pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
>  
> +    // unlock the external mutex
>      pthread_mutex_unlock(mutex);
>      WaitForSingleObject(win32_cond->semaphore, INFINITE);
> -    pthread_mutex_lock(mutex);
> +
> +    pthread_mutex_lock(&win32_cond->mtx_waiter_count);
> +    win32_cond->waiter_count--;
> +    last_waiter = !win32_cond->waiter_count && win32_cond->is_broadcast;
> +    pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
> +
> +    if (last_waiter)
> +        SetEvent(win32_cond->waiters_done);
> +
> +    // lock the external mutex
> +    return pthread_mutex_lock(mutex);
>  }
>  
>  static void pthread_cond_signal(pthread_cond_t *cond)
>  {
>      win32_cond_t *win32_cond = cond->ptr;
> +    int have_waiter;
>      if (cond_signal) {
>          cond_signal(cond);
>          return;
> @@ -199,11 +237,11 @@ static void pthread_cond_signal(pthread_cond_t *cond)
>  
>      /* non-native condition variables */
>      pthread_mutex_lock(&win32_cond->mtx_waiter_count);
> -    if (win32_cond->waiter_count) {
> -        ReleaseSemaphore(win32_cond->semaphore, 1, NULL);
> -        win32_cond->waiter_count--;
> -    }
> +    have_waiter = win32_cond->waiter_count;
>      pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
> +
> +    if (have_waiter)
> +        ReleaseSemaphore(win32_cond->semaphore, 1, NULL);
>  }

have_waiter looks not strictly necessary but ok since the thread
waiting on the semaphore tries to lock mtx_waiter_count immediately.

Janne
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to