diff options
Diffstat (limited to 'libbacktrace/BacktraceThread.cpp')
-rw-r--r-- | libbacktrace/BacktraceThread.cpp | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index b47cd2a..439cc3b 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -17,14 +17,15 @@ #include <errno.h> #include <inttypes.h> #include <limits.h> -#include <linux/futex.h> #include <pthread.h> #include <signal.h> +#include <stdlib.h> #include <string.h> #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> #include <ucontext.h> +#include <unistd.h> #include <cutils/atomic.h> @@ -32,10 +33,6 @@ #include "BacktraceThread.h" #include "thread_utils.h" -static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) { - return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3); -} - //------------------------------------------------------------------------- // ThreadEntry implementation. //------------------------------------------------------------------------- @@ -45,7 +42,14 @@ pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; // Assumes that ThreadEntry::list_mutex_ has already been locked before // creating a ThreadEntry object. ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) - : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) { + : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), + wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), + next_(ThreadEntry::list_), prev_(NULL) { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&wait_cond_, &attr); + // Add ourselves to the list. if (ThreadEntry::list_) { ThreadEntry::list_->prev_ = this; @@ -99,22 +103,35 @@ ThreadEntry::~ThreadEntry() { next_ = NULL; prev_ = NULL; + + pthread_cond_destroy(&wait_cond_); } void ThreadEntry::Wait(int value) { timespec ts; - ts.tv_sec = 10; - ts.tv_nsec = 0; - errno = 0; - futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0); - if (errno != 0 && errno != EWOULDBLOCK) { - BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno)); + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { + BACK_LOGW("clock_gettime failed: %s", strerror(errno)); + abort(); } + ts.tv_sec += 10; + + pthread_mutex_lock(&wait_mutex_); + while (wait_value_ != value) { + int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); + if (ret != 0) { + BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); + break; + } + } + pthread_mutex_unlock(&wait_mutex_); } void ThreadEntry::Wake() { - futex_++; - futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); + pthread_mutex_lock(&wait_mutex_); + wait_value_++; + pthread_mutex_unlock(&wait_mutex_); + + pthread_cond_signal(&wait_cond_); } void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { @@ -142,7 +159,7 @@ static void SignalHandler(int, siginfo_t*, void* sigcontext) { // Pause the thread until the unwind is complete. This avoids having // the thread run ahead causing problems. - entry->Wait(1); + entry->Wait(2); ThreadEntry::Remove(entry); } @@ -194,7 +211,7 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { } // Wait for the thread to get the ucontext. - entry->Wait(0); + entry->Wait(1); // After the thread has received the signal, allow other unwinders to // continue. |