+/**
+ * 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_CANCEL)
+ pthread_cancel (thread_id);
+#elif defined (UNDER_CE)
+ SetEvent (thread_id->cancel_event);
+#elif defined (WIN32)
+ QueueUserAPC (vlc_cancel_self, thread_id->handle, 0);
+#else
+# warning vlc_cancel is not implemented!
+#endif
+}
+
+/**
+ * Waits for a thread to complete (if needed), and destroys it.
+ * This is a cancellation point; in case of cancellation, the join does _not_
+ * occur.
+ *
+ * @param handle thread handle
+ * @param p_result [OUT] pointer to write the thread return value or NULL
+ * @return 0 on success, a standard error code otherwise.
+ */
+void vlc_join (vlc_thread_t handle, void **result)
+{
+#if defined( LIBVLC_USE_PTHREAD )
+ int val = pthread_join (handle, result);
+ VLC_THREAD_ASSERT ("joining thread");
+
+#elif defined( UNDER_CE ) || defined( WIN32 )
+ do
+ vlc_testcancel ();
+ while (WaitForSingleObjectEx (handle->handle, INFINITE, TRUE)
+ == WAIT_IO_COMPLETION);
+
+ CloseHandle (handle->handle);
+ if (result)
+ *result = handle->data;
+#if defined( UNDER_CE )
+ CloseHandle (handle->cancel_event);
+#endif
+ free (handle);
+
+#endif
+}
+
+/**
+ * Save the current cancellation state (enabled or disabled), then disable
+ * cancellation for the calling thread.
+ * This function must be called before entering a piece of code that is not
+ * cancellation-safe, unless it can be proven that the calling thread will not
+ * be cancelled.
+ * @return Previous cancellation state (opaque value for vlc_restorecancel()).
+ */
+int vlc_savecancel (void)
+{
+ int state;
+
+#if defined (LIBVLC_USE_PTHREAD_CANCEL)
+ int val = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
+ VLC_THREAD_ASSERT ("saving cancellation");
+
+#else
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+ if (nfo == NULL)
+ return false; /* Main thread - cannot be cancelled anyway */
+
+ state = nfo->killable;
+ nfo->killable = false;
+
+#endif
+ return state;
+}
+
+/**
+ * Restore the cancellation state for the calling thread.
+ * @param state previous state as returned by vlc_savecancel().
+ * @return Nothing, always succeeds.
+ */
+void vlc_restorecancel (int state)
+{
+#if defined (LIBVLC_USE_PTHREAD_CANCEL)
+# ifndef NDEBUG
+ int oldstate, val;
+
+ val = pthread_setcancelstate (state, &oldstate);
+ /* This should fail if an invalid value for given for state */
+ VLC_THREAD_ASSERT ("restoring cancellation");
+
+ if (oldstate != PTHREAD_CANCEL_DISABLE)
+ vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL,
+ __func__, __FILE__, __LINE__);
+# else
+ pthread_setcancelstate (state, NULL);
+# endif
+
+#else
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+ assert (state == false || state == true);
+
+ if (nfo == NULL)
+ return; /* Main thread - cannot be cancelled anyway */
+
+ assert (!nfo->killable);
+ nfo->killable = state != 0;
+
+#endif
+}
+
+/**
+ * Issues an explicit deferred cancellation point.
+ * This has no effect if thread cancellation is disabled.
+ * This can be called when there is a rather slow non-sleeping operation.
+ * This is also used to force a cancellation point in a function that would
+ * otherwise "not always" be a one (block_FifoGet() is an example).
+ */
+void vlc_testcancel (void)
+{
+#if defined (LIBVLC_USE_PTHREAD_CANCEL)
+ pthread_testcancel ();
+
+#else
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+ if (nfo == NULL)
+ return; /* Main thread - cannot be cancelled anyway */
+
+ if (nfo->killable && nfo->killed)