[vlc-commits] win32: use condition variable (fixes #14668)
Rémi Denis-Courmont
git at videolan.org
Fri May 27 23:43:03 CEST 2016
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Fri May 27 00:31:55 2016 +0300| [f09fc2aaf9132d5d7e0c00431558bd3c92b8f95f] | committer: Rémi Denis-Courmont
win32: use condition variable (fixes #14668)
This replaces the ever flawed condition variables implementation with
a less antique back-end. While designed for Windows 8 and later, a less
efficient fallback mode is provided for older supported versions.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f09fc2aaf9132d5d7e0c00431558bd3c92b8f95f
---
include/vlc_threads.h | 7 +--
src/win32/thread.c | 157 +++++++++++++++----------------------------------
2 files changed, 48 insertions(+), 116 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 181f863..4792cc1 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -68,12 +68,7 @@ typedef struct
};
} vlc_mutex_t;
#define VLC_STATIC_MUTEX { false, { { false, 0 } } }
-typedef struct
-{
- HANDLE semaphore;
- LONG waiters;
-} vlc_cond_t;
-#define VLC_STATIC_COND { NULL, 0 }
+#define LIBVLC_NEED_CONDVAR
typedef HANDLE vlc_sem_t;
#define LIBVLC_NEED_RWLOCK
typedef struct vlc_threadvar *vlc_threadvar_t;
diff --git a/src/win32/thread.c b/src/win32/thread.c
index a2597e2..d92df84 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -58,6 +58,12 @@ struct vlc_thread
void *(*entry) (void *);
void *data;
+
+ struct
+ {
+ atomic_int *addr;
+ CRITICAL_SECTION lock;
+ } wait;
};
/*** Common helpers ***/
@@ -209,113 +215,6 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
LeaveCriticalSection (&p_mutex->mutex);
}
-/*** Condition variables ***/
-void vlc_cond_init(vlc_cond_t *wait)
-{
- wait->semaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
- if (unlikely(wait->semaphore == NULL))
- abort();
- wait->waiters = 0;
-}
-
-void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
-{
- vlc_cond_init (p_condvar);
-}
-
-void vlc_cond_destroy(vlc_cond_t *wait)
-{
- CloseHandle(wait->semaphore);
-}
-
-static LONG InterlockedDecrementNonZero(LONG volatile *dst)
-{
- LONG cmp, val = 1;
-
- do
- {
- cmp = val;
- val = InterlockedCompareExchange(dst, val - 1, val);
- if (val == 0)
- return 0;
- }
- while (cmp != val);
-
- return val;
-}
-
-void vlc_cond_signal(vlc_cond_t *wait)
-{
- if (wait->semaphore == NULL)
- return;
-
- if (InterlockedDecrementNonZero(&wait->waiters) > 0)
- ReleaseSemaphore(wait->semaphore, 1, NULL);
-}
-
-void vlc_cond_broadcast(vlc_cond_t *wait)
-{
- if (wait->semaphore == NULL)
- return;
-
- LONG waiters = InterlockedExchange(&wait->waiters, 0);
- if (waiters > 0)
- ReleaseSemaphore(wait->semaphore, waiters, NULL);
-}
-
-static int vlc_cond_wait_delay(vlc_cond_t *wait, vlc_mutex_t *lock,
- mtime_t ms)
-{
- if (ms < 0)
- ms = 0;
- if (ms > 0x7fffffff && ms != INFINITE)
- ms = 0x7fffffff;
-
- DWORD delay = ms;
- DWORD result;
-
- vlc_testcancel();
-
- if (wait->semaphore == NULL)
- { /* FIXME FIXME FIXME */
- vlc_mutex_unlock(lock);
- result = SleepEx((delay > 50u) ? 50u : delay, TRUE);
- }
- else
- {
- InterlockedIncrement(&wait->waiters);
- vlc_mutex_unlock(lock);
- result = vlc_WaitForSingleObject(wait->semaphore, delay);
- }
- vlc_mutex_lock(lock);
-
- if (result == WAIT_IO_COMPLETION)
- vlc_testcancel();
- return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
-}
-
-void vlc_cond_wait(vlc_cond_t *wait, vlc_mutex_t *lock)
-{
- vlc_cond_wait_delay(wait, lock, INFINITE);
-}
-
-int vlc_cond_timedwait(vlc_cond_t *wait, vlc_mutex_t *lock, mtime_t deadline)
-{
- return vlc_cond_wait_delay(wait, lock, (deadline + 999 - mdate()) / 1000);
-}
-
-int vlc_cond_timedwait_daytime(vlc_cond_t *wait, vlc_mutex_t *lock,
- time_t deadline)
-{
- time_t now;
- mtime_t delay;
-
- time(&now);
- delay = ((mtime_t)deadline - (mtime_t)now) * 1000;
-
- return vlc_cond_wait_delay(wait, lock, delay);
-}
-
/*** Semaphore ***/
void vlc_sem_init (vlc_sem_t *sem, unsigned value)
{
@@ -616,6 +515,12 @@ static bool isCancelled(void)
}
#endif
+static void vlc_thread_destroy(vlc_thread_t th)
+{
+ DeleteCriticalSection(&th->wait.lock);
+ free(th);
+}
+
static unsigned __stdcall vlc_entry (void *p)
{
struct vlc_thread *th = p;
@@ -626,7 +531,7 @@ static unsigned __stdcall vlc_entry (void *p)
TlsSetValue(thread_key, NULL);
if (th->id == NULL) /* Detached thread */
- free(th);
+ vlc_thread_destroy(th);
return 0;
}
@@ -641,6 +546,8 @@ static int vlc_clone_attr (vlc_thread_t *p_handle, bool detached,
th->killable = false; /* not until vlc_entry() ! */
atomic_init(&th->killed, false);
th->cleaners = NULL;
+ th->wait.addr = NULL;
+ InitializeCriticalSection(&th->wait.lock);
/* When using the MSVCRT C library you have to use the _beginthreadex
* function instead of CreateThread, otherwise you'll end up with
@@ -686,7 +593,7 @@ void vlc_join (vlc_thread_t th, void **result)
if (result != NULL)
*result = th->data;
CloseHandle (th->id);
- free (th);
+ vlc_thread_destroy(th);
}
int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
@@ -729,6 +636,15 @@ static void CALLBACK vlc_cancel_self (ULONG_PTR self)
void vlc_cancel (vlc_thread_t th)
{
atomic_store_explicit(&th->killed, true, memory_order_relaxed);
+
+ EnterCriticalSection(&th->wait.lock);
+ if (th->wait.addr != NULL)
+ {
+ atomic_fetch_and_explicit(th->wait.addr, -2, memory_order_relaxed);
+ vlc_addr_broadcast(th->wait.addr);
+ }
+ LeaveCriticalSection(&th->wait.lock);
+
#if IS_INTERRUPTIBLE
QueueUserAPC (vlc_cancel_self, th->id, (uintptr_t)th);
#endif
@@ -774,7 +690,7 @@ void vlc_testcancel (void)
th->data = NULL; /* TODO: special value? */
if (th->id == NULL) /* Detached thread */
- free(th);
+ vlc_thread_destroy(th);
_endthreadex(0);
}
@@ -806,6 +722,27 @@ void vlc_control_cancel (int cmd, ...)
th->cleaners = th->cleaners->next;
break;
}
+
+ case VLC_CANCEL_ADDR_SET:
+ {
+ void *addr = va_arg(ap, void *);
+
+ EnterCriticalSection(&th->wait.lock);
+ th->wait.addr = addr;
+ LeaveCriticalSection(&th->wait.lock);
+ break;
+ }
+
+ case VLC_CANCEL_ADDR_CLEAR:
+ {
+ void *addr = va_arg(ap, void *);
+
+ EnterCriticalSection(&th->wait.lock);
+ assert(th->wait.addr == addr);
+ th->wait.addr = NULL;
+ LeaveCriticalSection(&th->wait.lock);
+ break;
+ }
}
va_end (ap);
}
More information about the vlc-commits
mailing list