]> git.sesse.net Git - vlc/blobdiff - src/misc/pthread.c
Maemo: work-around segmentation fault when poll() unwinds
[vlc] / src / misc / pthread.c
index ceac6fca1ab3643ee38806f4bded69d0796b0313..5385d7c0a08594b43ea54e783023690300eb0481 100644 (file)
@@ -35,6 +35,7 @@
 #include <assert.h>
 #include <unistd.h> /* fsync() */
 #include <signal.h>
+#include <errno.h>
 
 #include <sched.h>
 #ifdef __linux__
@@ -47,6 +48,7 @@
 
 #ifdef __APPLE__
 # include <sys/time.h> /* gettimeofday in vlc_cond_timedwait */
+# include <mach/mach_init.h> /* mach_task_self in semaphores */
 #endif
 
 /**
@@ -88,6 +90,7 @@ static void
 vlc_thread_fatal (const char *action, int error,
                   const char *function, const char *file, unsigned line)
 {
+    int canc = vlc_savecancel ();
     fprintf (stderr, "LibVLC fatal error %s (%d) in thread %lu ",
              action, error, vlc_threadid ());
     vlc_trace (function, file, line);
@@ -118,11 +121,13 @@ vlc_thread_fatal (const char *action, int error,
 #endif
     fflush (stderr);
 
+    vlc_restorecancel (canc);
     abort ();
 }
 
 # define VLC_THREAD_ASSERT( action ) \
-    if (val) vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
+    if (unlikely(val)) \
+        vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
 #else
 # define VLC_THREAD_ASSERT( action ) ((void)val)
 #endif
@@ -139,17 +144,19 @@ void vlc_mutex_init( vlc_mutex_t *p_mutex )
 {
     pthread_mutexattr_t attr;
 
-    if( pthread_mutexattr_init( &attr ) )
+    if (unlikely(pthread_mutexattr_init (&attr)))
         abort();
-#ifndef NDEBUG
+#ifdef NDEBUG
+    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL );
+#else
     /* Create error-checking mutex to detect problems more easily. */
-# if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6)
+# if defined (__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 6)
     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
 # else
     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
 # endif
 #endif
-    if( pthread_mutex_init( p_mutex, &attr ) )
+    if (unlikely(pthread_mutex_init (p_mutex, &attr)))
         abort();
     pthread_mutexattr_destroy( &attr );
 }
@@ -161,13 +168,14 @@ void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
 {
     pthread_mutexattr_t attr;
 
-    pthread_mutexattr_init( &attr );
-#if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6)
+    if (unlikely(pthread_mutexattr_init (&attr)))
+        abort();
+#if defined (__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 6)
     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_RECURSIVE_NP );
 #else
     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
 #endif
-    if( pthread_mutex_init( p_mutex, &attr ) )
+    if (unlikely(pthread_mutex_init (p_mutex, &attr)))
         abort();
     pthread_mutexattr_destroy( &attr );
 }
@@ -249,14 +257,14 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
     VLC_THREAD_ASSERT ("unlocking mutex");
 }
 
-/*****************************************************************************
- * vlc_cond_init: initialize a condition variable
- *****************************************************************************/
-void vlc_cond_init( vlc_cond_t *p_condvar )
+/**
+ * Initializes a condition variable.
+ */
+void vlc_cond_init (vlc_cond_t *p_condvar)
 {
     pthread_condattr_t attr;
 
-    if (pthread_condattr_init (&attr))
+    if (unlikely(pthread_condattr_init (&attr)))
         abort ();
 #if !defined (_POSIX_CLOCK_SELECTION)
    /* Fairly outdated POSIX support (that was defined in 2001) */
@@ -267,11 +275,22 @@ void vlc_cond_init( vlc_cond_t *p_condvar )
     pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
 #endif
 
-    if (pthread_cond_init (p_condvar, &attr))
+    if (unlikely(pthread_cond_init (p_condvar, &attr)))
         abort ();
     pthread_condattr_destroy (&attr);
 }
 
+/**
+ * Initializes a condition variable.
+ * Contrary to vlc_cond_init(), the wall clock will be used as a reference for
+ * the vlc_cond_timedwait() time-out parameter.
+ */
+void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
+{
+    if (unlikely(pthread_cond_init (p_condvar, NULL)))
+        abort ();
+}
+
 /**
  * Destroys a condition variable. No threads shall be waiting or signaling the
  * condition.
@@ -344,7 +363,11 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
 
 /**
  * Waits for a condition variable up to a certain date.
- * This works like vlc_cond_wait(), except for the additional timeout.
+ * This works like vlc_cond_wait(), except for the additional time-out.
+ *
+ * If the variable was initialized with vlc_cond_init(), the timeout has the
+ * same arbitrary origin as mdate(). If the variable was initialized with
+ * vlc_cond_init_daytime(), the timeout is expressed from the Unix epoch.
  *
  * @param p_condvar condition variable to wait on
  * @param p_mutex mutex which is unlocked while waiting,
@@ -375,12 +398,96 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
     return val;
 }
 
+/**
+ * Initializes a semaphore.
+ */
+void vlc_sem_init (vlc_sem_t *sem, unsigned value)
+{
+#if defined(__APPLE__)
+    if (unlikely(semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value) != KERN_SUCCESS))
+        abort ();
+#else
+    if (unlikely(sem_init (sem, 0, value)))
+        abort ();
+#endif
+}
+
+/**
+ * Destroys a semaphore.
+ */
+void vlc_sem_destroy (vlc_sem_t *sem)
+{
+    int val;
+
+#if defined(__APPLE__)
+    if (likely(semaphore_destroy(mach_task_self(), *sem) == KERN_SUCCESS))
+        return;
+
+    val = EINVAL;
+#else
+    if (likely(sem_destroy (sem) == 0))
+        return;
+
+    val = errno;
+#endif
+
+    VLC_THREAD_ASSERT ("destroying semaphore");
+}
+
+/**
+ * Increments the value of a semaphore.
+ * @return 0 on success, EOVERFLOW in case of integer overflow
+ */
+int vlc_sem_post (vlc_sem_t *sem)
+{
+    int val;
+
+#if defined(__APPLE__)
+    if (likely(semaphore_signal(*sem) == KERN_SUCCESS))
+        return 0;
+
+    val = EINVAL;
+#else
+    if (likely(sem_post (sem) == 0))
+        return 0;
+
+    val = errno;
+#endif
+
+    if (unlikely(val != EOVERFLOW))
+        VLC_THREAD_ASSERT ("unlocking semaphore");
+    return val;
+}
+
+/**
+ * Atomically wait for the semaphore to become non-zero (if needed),
+ * then decrements it.
+ */
+void vlc_sem_wait (vlc_sem_t *sem)
+{
+    int val;
+
+#if defined(__APPLE__)
+    if (likely(semaphore_wait(*sem) == KERN_SUCCESS))
+        return;
+
+    val = EINVAL;
+#else
+    do
+        if (likely(sem_wait (sem) == 0))
+            return;
+    while ((val = errno) == EINTR);
+#endif
+
+    VLC_THREAD_ASSERT ("locking semaphore");
+}
+
 /**
  * Initializes a read/write lock.
  */
 void vlc_rwlock_init (vlc_rwlock_t *lock)
 {
-    if (pthread_rwlock_init (lock, NULL))
+    if (unlikely(pthread_rwlock_init (lock, NULL)))
         abort ();
 }
 
@@ -475,10 +582,10 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc)
     if (!initialized)
     {
 #ifndef __APPLE__
-        if (config_GetInt (p_libvlc, "rt-priority"))
+        if (var_InheritBool (p_libvlc, "rt-priority"))
 #endif
         {
-            rt_offset = config_GetInt (p_libvlc, "rt-offset");
+            rt_offset = var_InheritInteger (p_libvlc, "rt-offset");
             rt_priorities = true;
         }
         initialized = true;
@@ -581,6 +688,9 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
 void vlc_cancel (vlc_thread_t thread_id)
 {
     pthread_cancel (thread_id);
+#ifdef HAVE_MAEMO
+    pthread_kill (thread_id, SIGRTMIN);
+#endif
 }
 
 /**
@@ -653,7 +763,7 @@ void vlc_restorecancel (int state)
     /* This should fail if an invalid value for given for state */
     VLC_THREAD_ASSERT ("restoring cancellation");
 
-    if (oldstate != PTHREAD_CANCEL_DISABLE)
+    if (unlikely(oldstate != PTHREAD_CANCEL_DISABLE))
          vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL,
                            __func__, __FILE__, __LINE__);
 #else
@@ -753,7 +863,7 @@ int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
 {
     struct vlc_timer *timer = malloc (sizeof (*timer));
 
-    if (timer == NULL)
+    if (unlikely(timer == NULL))
         return ENOMEM;
     vlc_mutex_init (&timer->lock);
     vlc_cond_init (&timer->wait);
@@ -810,11 +920,16 @@ void vlc_timer_destroy (vlc_timer_t timer)
 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
                          mtime_t value, mtime_t interval)
 {
+    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+
+    vlc_mutex_lock (&lock);
     vlc_mutex_lock (&timer->lock);
     if (timer->value)
     {
+        vlc_mutex_unlock (&timer->lock);
         vlc_cancel (timer->thread);
         vlc_join (timer->thread, NULL);
+        vlc_mutex_lock (&timer->lock);
         timer->value = 0;
     }
     if ((value != 0)
@@ -825,6 +940,7 @@ void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
         timer->interval = interval;
     }
     vlc_mutex_unlock (&timer->lock);
+    vlc_mutex_unlock (&lock);
 }
 
 /**