Commit b3eb9ab9 authored by Pierre Ynard's avatar Pierre Ynard Committed by Rémi Denis-Courmont

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: default avatarRémi Denis-Courmont <rdenis@simphalempin.com>
parent b190a796
...@@ -115,6 +115,9 @@ typedef struct ...@@ -115,6 +115,9 @@ typedef struct
HANDLE handle; HANDLE handle;
void *(*entry) (void *); void *(*entry) (void *);
void *data; void *data;
#if defined( UNDER_CE )
HANDLE cancel_event;
#endif
} *vlc_thread_t; } *vlc_thread_t;
typedef struct typedef struct
......
...@@ -52,10 +52,6 @@ ...@@ -52,10 +52,6 @@
# include <mmsystem.h> # include <mmsystem.h>
#endif #endif
#if defined( UNDER_CE )
# define SleepEx(a,b) Sleep(a)
#endif
#if defined(HAVE_SYS_TIME_H) #if defined(HAVE_SYS_TIME_H)
# include <sys/time.h> # include <sys/time.h>
#endif #endif
......
...@@ -49,10 +49,6 @@ static vlc_threadvar_t cancel_key; ...@@ -49,10 +49,6 @@ static vlc_threadvar_t cancel_key;
# include <execinfo.h> # include <execinfo.h>
#endif #endif
#ifdef UNDER_CE
# define WaitForSingleObjectEx(a,b,c) WaitForSingleObject(a,b)
#endif
/** /**
* Print a backtrace to the standard error for debugging purpose. * Print a backtrace to the standard error for debugging purpose.
*/ */
...@@ -144,9 +140,95 @@ typedef struct vlc_cancel_t ...@@ -144,9 +140,95 @@ typedef struct vlc_cancel_t
vlc_cleanup_t *cleaners; vlc_cleanup_t *cleaners;
bool killable; bool killable;
bool killed; bool killed;
# ifdef UNDER_CE
HANDLE cancel_event;
# endif
} vlc_cancel_t; } 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 #endif
#ifdef WIN32 #ifdef WIN32
...@@ -391,10 +473,6 @@ void vlc_cond_broadcast (vlc_cond_t *p_condvar) ...@@ -391,10 +473,6 @@ void vlc_cond_broadcast (vlc_cond_t *p_condvar)
#endif #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 * 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 * another thread calls vlc_cond_signal() or vlc_cond_broadcast() on the same
...@@ -536,6 +614,9 @@ static unsigned __stdcall vlc_entry (void *data) ...@@ -536,6 +614,9 @@ static unsigned __stdcall vlc_entry (void *data)
{ {
vlc_cancel_t cancel_data = VLC_CANCEL_INIT; vlc_cancel_t cancel_data = VLC_CANCEL_INIT;
vlc_thread_t self = data; vlc_thread_t self = data;
#ifdef UNDER_CE
cancel_data.cancel_event = self->cancel_event;
#endif
vlc_threadvar_set (&cancel_key, &cancel_data); vlc_threadvar_set (&cancel_key, &cancel_data);
self->data = self->entry (self->data); self->data = self->entry (self->data);
...@@ -633,6 +714,12 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data, ...@@ -633,6 +714,12 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
th->data = data; th->data = data;
th->entry = entry; th->entry = entry;
#if defined( UNDER_CE ) #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); hThread = CreateThread (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
#else #else
hThread = (HANDLE)(uintptr_t) hThread = (HANDLE)(uintptr_t)
...@@ -694,18 +781,7 @@ void vlc_cancel (vlc_thread_t thread_id) ...@@ -694,18 +781,7 @@ void vlc_cancel (vlc_thread_t thread_id)
#if defined (LIBVLC_USE_PTHREAD_CANCEL) #if defined (LIBVLC_USE_PTHREAD_CANCEL)
pthread_cancel (thread_id); pthread_cancel (thread_id);
#elif defined (UNDER_CE) #elif defined (UNDER_CE)
/* HACK:There is no way to use something SetEvent (thread_id->cancel_event);
* 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);
#elif defined (WIN32) #elif defined (WIN32)
QueueUserAPC (vlc_cancel_self, thread_id->handle, 0); QueueUserAPC (vlc_cancel_self, thread_id->handle, 0);
#else #else
...@@ -738,6 +814,9 @@ void vlc_join (vlc_thread_t handle, void **result) ...@@ -738,6 +814,9 @@ void vlc_join (vlc_thread_t handle, void **result)
CloseHandle (handle->handle); CloseHandle (handle->handle);
if (result) if (result)
*result = handle->data; *result = handle->data;
#if defined( UNDER_CE )
CloseHandle (handle->cancel_event);
#endif
free (handle); free (handle);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment