#include <vlc_common.h>
#include "libvlc.h"
+#include <stdarg.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
(void)action; (void)error; (void)file; (void)line;
abort();
}
+
+static vlc_threadvar_t cancel_key;
#endif
/*****************************************************************************
vlc_threadvar_create( &thread_object_key, NULL );
#endif
vlc_threadvar_create( &msg_context_global_key, msg_StackDestroy );
+#ifndef LIBVLC_USE_PTHREAD
+ vlc_threadvar_create( &cancel_key, free );
+#endif
}
i_initializations++;
if( i_initializations == 1 )
{
vlc_object_release( p_root );
+#ifndef LIBVLC_USE_PTHREAD
+ vlc_threadvar_delete( &cancel_key );
+#endif
vlc_threadvar_delete( &msg_context_global_key );
#ifndef NDEBUG
vlc_threadvar_delete( &thread_object_key );
}
ResumeThread (hThread);
- th->handle = hThread;
if (priority)
SetThreadPriority (hThread, priority);
return ret;
}
+#if defined (WIN32)
+/* APC procedure for thread cancellation */
+static void CALLBACK vlc_cancel_self (ULONG_PTR dummy)
+{
+ (void)dummy;
+ vlc_control_cancel (VLC_DO_CANCEL);
+}
+#endif
+
+/**
+ * Marks a thread as cancelled. Next time the target thread reaches a
+ * cancellation point (while not having disabled cancellation), it will
+ * run its cancellation cleanup handler, the thread variable destructors, and
+ * terminate. vlc_join() must be used afterward regardless of a thread being
+ * cancelled or not.
+ */
+void vlc_cancel (vlc_thread_t thread_id)
+{
+#if defined (LIBVLC_USE_PTHREAD)
+ pthread_cancel (thread_id);
+#elif defined (WIN32)
+ QueueUserAPC (vlc_cancel_self, thread_id->handle, 0);
+#endif
+}
+
/**
* Waits for a thread to complete (if needed), and destroys it.
* @param handle thread handle
p_priv->b_thread = false;
}
+
+void vlc_thread_cancel (vlc_object_t *obj)
+{
+ vlc_object_internals_t *priv = vlc_internals (obj);
+
+ if (priv->b_thread)
+ vlc_cancel (priv->thread_id);
+}
+
+typedef struct vlc_cleanup_t
+{
+ struct vlc_cleanup_t *next;
+ void (*proc) (void *);
+ void *data;
+} vlc_cleanup_t;
+
+typedef struct vlc_cancel_t
+{
+ vlc_cleanup_t *cleaners;
+ bool killable;
+ bool killed;
+} vlc_cancel_t;
+
+void vlc_control_cancel (int cmd, ...)
+{
+#ifdef LIBVLC_USE_PTHREAD
+ (void) cmd;
+ assert (0);
+#else
+ va_list ap;
+
+ va_start (ap, cmd);
+
+ vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ if (nfo == NULL)
+ {
+ nfo = malloc (sizeof (*nfo));
+ if (nfo == NULL)
+ abort ();
+ nfo->cleaners = NULL;
+ nfo->killed = false;
+ nfo->killable = true;
+ }
+
+ switch (cmd)
+ {
+ case VLC_SAVE_CANCEL:
+ {
+ int *p_state = va_arg (ap, int *);
+ *p_state = nfo->killable;
+ nfo->killable = false;
+ break;
+ }
+
+ case VLC_RESTORE_CANCEL:
+ {
+ int state = va_arg (ap, int);
+ nfo->killable = state != 0;
+ break;
+ }
+
+ case VLC_TEST_CANCEL:
+ if (nfo->killable && nfo->killed)
+ {
+ for (vlc_cleanup_t *p = nfo->cleaners; p != NULL; p = p->next)
+ p->proc (p->data);
+ free (nfo);
+#if defined (LIBVLC_USE_PTHREAD)
+ pthread_exit (PTHREAD_CANCELLED);
+#elif defined (WIN32)
+ _endthread ();
+#else
+# error Not implemented!
+#endif
+ }
+ break;
+
+ case VLC_DO_CANCEL:
+ nfo->killed = true;
+ break;
+ }
+ va_end (ap);
+#endif
+}