#if defined( LIBVLC_USE_PTHREAD )
# include <sched.h>
+# ifdef __linux__
+# include <sys/syscall.h> /* SYS_gettid */
+# endif
#else
static vlc_threadvar_t cancel_key;
#endif
# include <execinfo.h>
#endif
+#ifdef __APPLE__
+# include <sys/time.h> /* gettimeofday in vlc_cond_timedwait */
+#endif
+
/**
* Print a backtrace to the standard error for debugging purpose.
*/
static inline unsigned long vlc_threadid (void)
{
-#if defined(LIBVLC_USE_PTHREAD)
+#if defined (LIBVLC_USE_PTHREAD)
+# if defined (__linux__)
+ return syscall (SYS_gettid);
+
+# else
union { pthread_t th; unsigned long int i; } v = { };
v.th = pthread_self ();
return v.i;
+#endif
#elif defined (WIN32)
return GetCurrentThreadId ();
static DWORD vlc_cancelable_wait (DWORD count, const HANDLE *handles,
DWORD delay)
{
- vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
if (nfo == NULL)
{
/* Main thread - cannot be cancelled anyway */
* Acquires a mutex. If needed, waits for any other thread to release it.
* Beware of deadlocks when locking multiple mutexes at the same time,
* or when using mutexes from callbacks.
+ * This function is not a cancellation-point.
*
* @param p_mutex mutex initialized with vlc_mutex_init() or
* vlc_mutex_init_recursive()
#endif
}
+/**
+ * Acquires a mutex if and only if it is not currently held by another thread.
+ * This function never sleeps and can be used in delay-critical code paths.
+ * This function is not a cancellation-point.
+ *
+ * <b>Beware</b>: If this function fails, then the mutex is held... by another
+ * thread. The calling thread must deal with the error appropriately. That
+ * typically implies postponing the operations that would have required the
+ * mutex. If the thread cannot defer those operations, then it must use
+ * vlc_mutex_lock(). If in doubt, use vlc_mutex_lock() instead.
+ *
+ * @param p_mutex mutex initialized with vlc_mutex_init() or
+ * vlc_mutex_init_recursive()
+ * @return 0 if the mutex could be acquired, an error code otherwise.
+ */
+int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
+{
+#if defined(LIBVLC_USE_PTHREAD)
+ int val = pthread_mutex_trylock( p_mutex );
+
+ if (val != EBUSY)
+ VLC_THREAD_ASSERT ("locking mutex");
+ return val;
+
+#elif defined( WIN32 )
+ if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
+ { /* ^^ We could also lock super_mutex all the time... sluggish */
+ assert (p_mutex != &super_mutex); /* this one cannot be static */
+
+ vlc_mutex_lock (&super_mutex);
+ if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
+ vlc_mutex_init (p_mutex);
+ /* FIXME: destroy the mutex some time... */
+ vlc_mutex_unlock (&super_mutex);
+ }
+ assert (InterlockedExchange (&p_mutex->initialized, 1) == 1);
+ return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
+
+#endif
+}
/**
* Releases a mutex (or crashes if the mutex is not locked by the caller).
mtime_t deadline)
{
#if defined(LIBVLC_USE_PTHREAD)
+#ifdef __APPLE__
+ /* mdate() is mac_absolute_time on osx, which we must convert to do
+ * the same base than gettimeofday() on which pthread_cond_timedwait
+ * counts on. */
+ mtime_t oldbase = mdate();
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ mtime_t newbase = (mtime_t)tv.tv_sec * 1000000 + (mtime_t) tv.tv_usec;
+ deadline = deadline - oldbase + newbase;
+#endif
lldiv_t d = lldiv( deadline, CLOCK_FREQ );
struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
#endif
}
+/**
+ * Sets a thread-local variable.
+ * @param key thread-local variable key (created with vlc_threadvar_create())
+ * @param value new value for the variable for the calling thread
+ * @return 0 on success, a system error code otherwise.
+ */
+int vlc_threadvar_set (vlc_threadvar_t key, void *value)
+{
+#if defined(LIBVLC_USE_PTHREAD)
+ return pthread_setspecific (key, value);
+#elif defined( UNDER_CE ) || defined( WIN32 )
+ return TlsSetValue (key, p_value) ? ENOMEM : 0;
+#else
+# error Unimplemented!
+#endif
+}
+
+/**
+ * Gets the value of a thread-local variable for the calling thread.
+ * This function cannot fail.
+ * @return the value associated with the given variable for the calling
+ * or NULL if there is no value.
+ */
+void *vlc_threadvar_get (vlc_threadvar_t key)
+{
+#if defined(LIBVLC_USE_PTHREAD)
+ return pthread_getspecific (key);
+#elif defined( UNDER_CE ) || defined( WIN32 )
+ return TlsGetValue (key);
+#else
+# error Unimplemented!
+#endif
+}
+
#if defined (LIBVLC_USE_PTHREAD)
#elif defined (WIN32)
static unsigned __stdcall vlc_entry (void *data)
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);
return 0;
}
free(th);
return errno;
}
- hThread = CreateThread (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
+ hThread = CreateThread (NULL, 128*1024, vlc_entry, th, CREATE_SUSPENDED, NULL);
#else
hThread = (HANDLE)(uintptr_t)
_beginthreadex (NULL, 0, vlc_entry, th, CREATE_SUSPENDED, NULL);
VLC_THREAD_ASSERT ("saving cancellation");
#else
- vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
if (nfo == NULL)
return false; /* Main thread - cannot be cancelled anyway */
# endif
#else
- vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
assert (state == false || state == true);
if (nfo == NULL)
pthread_testcancel ();
#else
- vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
if (nfo == NULL)
return; /* Main thread - cannot be cancelled anyway */
#else
va_list ap;
- vlc_cancel_t *nfo = vlc_threadvar_get (&cancel_key);
+ vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
if (nfo == NULL)
{
#ifdef WIN32
if (nfo == NULL)
return; /* Uho! Expect problems! */
*nfo = VLC_CANCEL_INIT;
- vlc_threadvar_set (&cancel_key, nfo);
+ vlc_threadvar_set (cancel_key, nfo);
#endif
}