]> git.sesse.net Git - vlc/blobdiff - src/misc/threads.c
Deinline vlc_threadvar_(|s)get and kill useless indirection
[vlc] / src / misc / threads.c
index 97fa5deee544854681b202b523e64ce95de98d00..75aed7077c54218d39648cc27a1cc68b02e8028e 100644 (file)
@@ -41,6 +41,9 @@
 
 #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
@@ -49,6 +52,10 @@ static vlc_threadvar_t cancel_key;
 # 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.
  */
@@ -68,11 +75,16 @@ void vlc_trace (const char *fn, const char *file, unsigned line)
 
 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 ();
 
@@ -158,7 +170,7 @@ 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);
+    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
     if (nfo == NULL)
     {
         /* Main thread - cannot be cancelled anyway */
@@ -344,6 +356,7 @@ void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
  * 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()
@@ -371,6 +384,46 @@ void vlc_mutex_lock (vlc_mutex_t *p_mutex)
 #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).
@@ -548,6 +601,16 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
                         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) };
 
@@ -611,6 +674,40 @@ void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
 #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)
@@ -621,7 +718,7 @@ 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;
 }
@@ -723,7 +820,7 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
         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);
@@ -841,7 +938,7 @@ int vlc_savecancel (void)
     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 */
 
@@ -875,7 +972,7 @@ void vlc_restorecancel (int state)
 # 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)
@@ -900,7 +997,7 @@ void vlc_testcancel (void)
     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 */
 
@@ -1136,7 +1233,7 @@ void vlc_control_cancel (int cmd, ...)
 #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
@@ -1147,7 +1244,7 @@ void vlc_control_cancel (int cmd, ...)
         if (nfo == NULL)
             return; /* Uho! Expect problems! */
         *nfo = VLC_CANCEL_INIT;
-        vlc_threadvar_set (&cancel_key, nfo);
+        vlc_threadvar_set (cancel_key, nfo);
 #endif
     }