From: Pierre Ynard Date: Tue, 25 Nov 2008 13:22:24 +0000 (+0100) Subject: Thread cancellation on WinCE X-Git-Tag: 1.0.0-pre1~2025 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=b3eb9ab9bdba36e85d63ca0234cc8e95d2188eed;p=vlc Thread cancellation on WinCE This patch adds support for thread cancellation on Windows CE. It emulates missing functions such as WaitForSingleObjectEx, by creating a cancellation event handle, and forwarding the wait functions to wait on both the original handles and the cancellation event. The thread can then be cancelled by triggering the event from another thread. Signed-off-by: RĂ©mi Denis-Courmont --- diff --git a/include/vlc_threads.h b/include/vlc_threads.h index 7b66e5b07c..0232dc78df 100644 --- a/include/vlc_threads.h +++ b/include/vlc_threads.h @@ -115,6 +115,9 @@ typedef struct HANDLE handle; void *(*entry) (void *); void *data; +#if defined( UNDER_CE ) + HANDLE cancel_event; +#endif } *vlc_thread_t; typedef struct diff --git a/src/misc/mtime.c b/src/misc/mtime.c index c5b1bc2234..bc622c1a35 100644 --- a/src/misc/mtime.c +++ b/src/misc/mtime.c @@ -52,10 +52,6 @@ # include #endif -#if defined( UNDER_CE ) -# define SleepEx(a,b) Sleep(a) -#endif - #if defined(HAVE_SYS_TIME_H) # include #endif diff --git a/src/misc/threads.c b/src/misc/threads.c index 80872df2c4..c7d79574b2 100644 --- a/src/misc/threads.c +++ b/src/misc/threads.c @@ -49,10 +49,6 @@ static vlc_threadvar_t cancel_key; # include #endif -#ifdef UNDER_CE -# define WaitForSingleObjectEx(a,b,c) WaitForSingleObject(a,b) -#endif - /** * Print a backtrace to the standard error for debugging purpose. */ @@ -144,9 +140,95 @@ typedef struct vlc_cancel_t vlc_cleanup_t *cleaners; bool killable; bool killed; +# ifdef UNDER_CE + HANDLE cancel_event; +# endif } vlc_cancel_t; -# define VLC_CANCEL_INIT { NULL, true, false } +# ifndef UNDER_CE +# define VLC_CANCEL_INIT { NULL, true, false } +# else +# define VLC_CANCEL_INIT { NULL, true, false, NULL } +# endif +#endif + +#ifdef UNDER_CE +static void CALLBACK vlc_cancel_self (ULONG_PTR dummy); + +static DWORD vlc_cancelable_wait (DWORD count, const HANDLE *handles, + DWORD delay) +{ + vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key); + if (nfo == NULL) + { + /* Main thread - cannot be cancelled anyway */ + return WaitForMultipleObjects (count, handles, FALSE, delay); + } + HANDLE new_handles[count + 1]; + memcpy(new_handles, handles, count * sizeof(HANDLE)); + new_handles[count] = nfo->cancel_event; + DWORD result = WaitForMultipleObjects (count + 1, new_handles, FALSE, + delay); + if (result == WAIT_OBJECT_0 + count) + { + vlc_cancel_self (NULL); + return WAIT_IO_COMPLETION; + } + else + { + return result; + } +} + +DWORD SleepEx (DWORD dwMilliseconds, BOOL bAlertable) +{ + if (bAlertable) + { + DWORD result = vlc_cancelable_wait (0, NULL, dwMilliseconds); + return (result == WAIT_TIMEOUT) ? 0 : WAIT_IO_COMPLETION; + } + else + { + Sleep(dwMilliseconds); + return 0; + } +} + +DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds, + BOOL bAlertable) +{ + if (bAlertable) + { + /* The MSDN documentation specifies different return codes, + * but in practice they are the same. We just check that it + * remains so. */ +#if WAIT_ABANDONED != WAIT_ABANDONED_0 +# error Windows headers changed, code needs to be rewritten! +#endif + return vlc_cancelable_wait (1, &hHandle, dwMilliseconds); + } + else + { + return WaitForSingleObject (hHandle, dwMilliseconds); + } +} + +DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles, + BOOL bWaitAll, DWORD dwMilliseconds, + BOOL bAlertable) +{ + if (bAlertable) + { + /* We do not support the bWaitAll case */ + assert (! bWaitAll); + return vlc_cancelable_wait (nCount, lpHandles, dwMilliseconds); + } + else + { + return WaitForMultipleObjects (nCount, lpHandles, bWaitAll, + dwMilliseconds); + } +} #endif #ifdef WIN32 @@ -391,10 +473,6 @@ void vlc_cond_broadcast (vlc_cond_t *p_condvar) #endif } -#ifdef UNDER_CE -# define WaitForMultipleObjectsEx(a,b,c) WaitForMultipleObjects(a,b) -#endif - /** * Waits for a condition variable. The calling thread will be suspended until * another thread calls vlc_cond_signal() or vlc_cond_broadcast() on the same @@ -536,6 +614,9 @@ static unsigned __stdcall vlc_entry (void *data) { vlc_cancel_t cancel_data = VLC_CANCEL_INIT; vlc_thread_t self = data; +#ifdef UNDER_CE + cancel_data.cancel_event = self->cancel_event; +#endif vlc_threadvar_set (&cancel_key, &cancel_data); self->data = self->entry (self->data); @@ -633,6 +714,12 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data, th->data = data; th->entry = entry; #if defined( UNDER_CE ) + th->cancel_event = CreateEvent (NULL, FALSE, FALSE, NULL); + if (th->cancel_event == NULL) + { + free(th); + return errno; + } hThread = CreateThread (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL); #else hThread = (HANDLE)(uintptr_t) @@ -694,18 +781,7 @@ void vlc_cancel (vlc_thread_t thread_id) #if defined (LIBVLC_USE_PTHREAD_CANCEL) pthread_cancel (thread_id); #elif defined (UNDER_CE) - /* HACK:There is no way to use something - * like QueueUserAPC on Windows CE, so I rely - * on some crappy arch specific code */ - CONTEXT context; - context.ContextFlags = CONTEXT_CONTROL; - GetThreadContext (thread_id->handle, &context); - /* Setting the instruction pointer for the canceled thread */ -#if defined(_ARM_) || defined(ARM) - context.Pc = (DWORD_PTR) vlc_cancel_self; -#endif - SetThreadContext (thread_id->handle, &context); - + SetEvent (thread_id->cancel_event); #elif defined (WIN32) QueueUserAPC (vlc_cancel_self, thread_id->handle, 0); #else @@ -738,6 +814,9 @@ void vlc_join (vlc_thread_t handle, void **result) CloseHandle (handle->handle); if (result) *result = handle->data; +#if defined( UNDER_CE ) + CloseHandle (handle->cancel_event); +#endif free (handle); #endif