1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <pthread.h> 18#include <stdint.h> 19#include <string.h> 20#include <sys/types.h> 21#include <time.h> 22#include <ucontext.h> 23 24#include "BacktraceLog.h" 25#include "ThreadEntry.h" 26 27// Initialize static member variables. 28ThreadEntry* ThreadEntry::list_ = nullptr; 29pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER; 30 31// Assumes that ThreadEntry::list_mutex_ has already been locked before 32// creating a ThreadEntry object. 33ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) 34 : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), 35 wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), 36 next_(ThreadEntry::list_), prev_(nullptr) { 37 pthread_condattr_t attr; 38 pthread_condattr_init(&attr); 39 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); 40 pthread_cond_init(&wait_cond_, &attr); 41 42 // Add ourselves to the list. 43 if (ThreadEntry::list_) { 44 ThreadEntry::list_->prev_ = this; 45 } 46 ThreadEntry::list_ = this; 47} 48 49ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) { 50 pthread_mutex_lock(&ThreadEntry::list_mutex_); 51 ThreadEntry* entry = list_; 52 while (entry != nullptr) { 53 if (entry->Match(pid, tid)) { 54 break; 55 } 56 entry = entry->next_; 57 } 58 59 if (!entry) { 60 if (create) { 61 entry = new ThreadEntry(pid, tid); 62 } 63 } else { 64 entry->ref_count_++; 65 } 66 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 67 68 return entry; 69} 70 71void ThreadEntry::Remove(ThreadEntry* entry) { 72 entry->Unlock(); 73 74 pthread_mutex_lock(&ThreadEntry::list_mutex_); 75 if (--entry->ref_count_ == 0) { 76 delete entry; 77 } 78 pthread_mutex_unlock(&ThreadEntry::list_mutex_); 79} 80 81// Assumes that ThreadEntry::list_mutex_ has already been locked before 82// deleting a ThreadEntry object. 83ThreadEntry::~ThreadEntry() { 84 if (list_ == this) { 85 list_ = next_; 86 } else { 87 if (next_) { 88 next_->prev_ = prev_; 89 } 90 prev_->next_ = next_; 91 } 92 93 next_ = nullptr; 94 prev_ = nullptr; 95 96 pthread_cond_destroy(&wait_cond_); 97} 98 99bool ThreadEntry::Wait(int value) { 100 timespec ts; 101 clock_gettime(CLOCK_MONOTONIC, &ts); 102 ts.tv_sec += 5; 103 104 bool wait_completed = true; 105 pthread_mutex_lock(&wait_mutex_); 106 while (wait_value_ != value) { 107 int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); 108 if (ret != 0) { 109 BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret)); 110 wait_completed = false; 111 break; 112 } 113 } 114 pthread_mutex_unlock(&wait_mutex_); 115 116 return wait_completed; 117} 118 119void ThreadEntry::Wake() { 120 pthread_mutex_lock(&wait_mutex_); 121 wait_value_++; 122 pthread_mutex_unlock(&wait_mutex_); 123 124 pthread_cond_signal(&wait_cond_); 125} 126 127void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { 128 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext); 129 // The only thing the unwinder cares about is the mcontext data. 130 memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)); 131} 132