+ vlc_thread_t self = data;
+ self->data = self->entry (self->data);
+ return 0;
+}
+#endif
+
+/**
+ * Creates and starts new thread.
+ *
+ * @param p_handle [OUT] pointer to write the handle of the created thread to
+ * @param entry entry point for the thread
+ * @param data data parameter given to the entry point
+ * @param priority thread priority value
+ * @return 0 on success, a standard error code on error.
+ */
+int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
+ int priority)
+{
+ int ret;
+
+#if defined( LIBVLC_USE_PTHREAD )
+ pthread_attr_t attr;
+ pthread_attr_init (&attr);
+
+ /* Block the signals that signals interface plugin handles.
+ * If the LibVLC caller wants to handle some signals by itself, it should
+ * block these before whenever invoking LibVLC. And it must obviously not
+ * start the VLC signals interface plugin.
+ *
+ * LibVLC will normally ignore any interruption caused by an asynchronous
+ * signal during a system call. But there may well be some buggy cases
+ * where it fails to handle EINTR (bug reports welcome). Some underlying
+ * libraries might also not handle EINTR properly.
+ */
+ sigset_t oldset;
+ {
+ sigset_t set;
+ sigemptyset (&set);
+ sigdelset (&set, SIGHUP);
+ sigaddset (&set, SIGINT);
+ sigaddset (&set, SIGQUIT);
+ sigaddset (&set, SIGTERM);
+
+ sigaddset (&set, SIGPIPE); /* We don't want this one, really! */
+ pthread_sigmask (SIG_BLOCK, &set, &oldset);
+ }
+ {
+ struct sched_param sp = { .sched_priority = priority, };
+ int policy;
+
+ if (sp.sched_priority <= 0)
+ sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
+ else
+ sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
+
+ pthread_attr_setschedpolicy (&attr, policy);
+ pthread_attr_setschedparam (&attr, &sp);
+ }
+
+ ret = pthread_create (p_handle, &attr, entry, data);
+ pthread_sigmask (SIG_SETMASK, &oldset, NULL);
+ pthread_attr_destroy (&attr);
+
+#elif defined( WIN32 ) || defined( UNDER_CE )
+ /* When using the MSVCRT C library you have to use the _beginthreadex
+ * function instead of CreateThread, otherwise you'll end up with
+ * memory leaks and the signal functions not working (see Microsoft
+ * Knowledge Base, article 104641) */
+ HANDLE hThread;
+ vlc_thread_t th = malloc (sizeof (*p_handle));
+
+ if (th == NULL)
+ return ENOMEM;
+
+ th->data = data;
+ th->entry = entry;
+#if defined( UNDER_CE )
+ hThread = CreateThread (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
+#else
+ hThread = (HANDLE)(uintptr_t)
+ _beginthreadex (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
+#endif
+
+ if (hThread)
+ {
+ /* Thread closes the handle when exiting, duplicate it here
+ * to be on the safe side when joining. */
+ if (!DuplicateHandle (GetCurrentProcess (), hThread,
+ GetCurrentProcess (), &th->handle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ CloseHandle (hThread);
+ free (th);
+ return ENOMEM;
+ }
+
+ ResumeThread (hThread);
+ if (priority)
+ SetThreadPriority (hThread, priority);
+
+ ret = 0;
+ *p_handle = th;
+ }
+ else
+ {
+ ret = errno;
+ free (th);
+ }
+
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+ *p_handle = spawn_thread( entry, psz_name, priority, data );
+ ret = resume_thread( *p_handle );
+
+#endif
+ 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