Added a workaround for the missing pthread_cancel on Android.
authorTobias Brunner <tobias@strongswan.org>
Tue, 22 Dec 2009 09:51:11 +0000 (10:51 +0100)
committerTobias Brunner <tobias@strongswan.org>
Wed, 23 Dec 2009 16:03:42 +0000 (17:03 +0100)
configure.in
src/libstrongswan/threading/thread.c

index f5de580..9272097 100644 (file)
@@ -306,6 +306,8 @@ dnl check if we actually are able to configure attributes on cond vars
 AC_CHECK_FUNCS(pthread_condattr_init)
 dnl instead of pthread_condattr_setclock Android has this function
 AC_CHECK_FUNCS(pthread_cond_timedwait_monotonic)
+dnl check if we can cancel threads
+AC_CHECK_FUNCS(pthread_cancel)
 dnl check if native rwlocks are available
 AC_CHECK_FUNCS(pthread_rwlock_init)
 LIBS=$saved_LIBS
index 14f92dc..f2028df 100644 (file)
@@ -113,6 +113,18 @@ static mutex_t *id_mutex;
  */
 static thread_value_t *current_thread;
 
+#ifndef HAVE_PTHREAD_CANCEL
+/* if pthread_cancel is not available, we emulate it using a signal */
+#define SIG_CANCEL (SIGRTMIN+7)
+
+/* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
+ * "cancelled" thread */
+static void cancel_signal_handler(int sig)
+{
+       pthread_exit(NULL);
+}
+#endif
+
 
 /**
  * Destroy an internal thread object.
@@ -146,7 +158,11 @@ static void cancel(private_thread_t *this)
                DBG1("!!! CANNOT CANCEL CURRENT THREAD !!!");
                return;
        }
+#ifdef HAVE_PTHREAD_CANCEL
        pthread_cancel(this->thread_id);
+#else
+       pthread_kill(this->thread_id, SIG_CANCEL);
+#endif /* HAVE_PTHREAD_CANCEL */
        this->mutex->unlock(this->mutex);
 }
 
@@ -355,10 +371,18 @@ void thread_cleanup_pop(bool execute)
  */
 bool thread_cancelability(bool enable)
 {
+#ifdef HAVE_PTHREAD_CANCEL
        int old;
        pthread_setcancelstate(enable ? PTHREAD_CANCEL_ENABLE
                                                                  : PTHREAD_CANCEL_DISABLE, &old);
        return old == PTHREAD_CANCEL_ENABLE;
+#else
+       sigset_t new, old;
+       sigemptyset(&new);
+       sigaddset(&new, SIG_CANCEL);
+       pthread_sigmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &new, &old);
+       return sigismember(&old, SIG_CANCEL) == 0;
+#endif /* HAVE_PTHREAD_CANCEL */
 }
 
 /**
@@ -367,7 +391,9 @@ bool thread_cancelability(bool enable)
 void thread_cancellation_point()
 {
        bool old = thread_cancelability(TRUE);
+#ifdef HAVE_PTHREAD_CANCEL
        pthread_testcancel();
+#endif /* HAVE_PTHREAD_CANCEL */
        thread_cancelability(old);
 }
 
@@ -390,6 +416,15 @@ void threads_init()
        current_thread = thread_value_create(NULL);
        current_thread->set(current_thread, (void*)main_thread);
        id_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
+
+#ifndef HAVE_PTHREAD_CANCEL
+       {       /* install a signal handler for our custom SIG_CANCEL */
+               struct sigaction action = {
+                       .sa_handler = cancel_signal_handler
+               };
+               sigaction(SIG_CANCEL, &action, NULL);
+       }
+#endif /* HAVE_PTHREAD_CANCEL */
 }
 
 /**