Update suspended threads info to be compatible with darwin

Summary:
On Darwin, we need to track thread and tid as separate values.
This patch splits out the implementation of the suspended threads list
to be OS-specific.

Reviewers: glider, kubamracek, kcc

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D31474

llvm-svn: 300491
This commit is contained in:
Francis Ricci 2017-04-17 20:29:38 +00:00
parent f7a4f3dd95
commit 5989dd241e
4 changed files with 119 additions and 37 deletions

View File

@ -200,10 +200,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
InternalScopedBuffer<uptr> registers(suspended_threads.RegisterCount());
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
uptr registers_end = registers_begin + registers.size();
for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
LOG_THREADS("Processing thread %d.\n", os_id);
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;

View File

@ -29,31 +29,21 @@ enum PtraceRegistersStatus {
// register contexts.
class SuspendedThreadsList {
public:
SuspendedThreadsList()
: thread_ids_(1024) {}
tid_t GetThreadID(uptr index) const {
CHECK_LT(index, thread_ids_.size());
return thread_ids_[index];
SuspendedThreadsList() = default;
// Can't declare pure virtual functions in sanitizer runtimes:
// __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead.
virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
uptr *sp) const {
UNIMPLEMENTED();
}
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
uptr *sp) const;
// The buffer in GetRegistersAndSP should be at least this big.
static uptr RegisterCount();
uptr thread_count() const { return thread_ids_.size(); }
bool Contains(tid_t thread_id) const {
for (uptr i = 0; i < thread_ids_.size(); i++) {
if (thread_ids_[i] == thread_id)
return true;
}
return false;
}
void Append(tid_t thread_id) {
thread_ids_.push_back(thread_id);
}
virtual uptr RegisterCount() const { UNIMPLEMENTED(); }
virtual uptr ThreadCount() const { UNIMPLEMENTED(); }
virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); }
private:
InternalMmapVector<tid_t> thread_ids_;
// Prohibit copy and assign.
SuspendedThreadsList(const SuspendedThreadsList&);
void operator=(const SuspendedThreadsList&);

View File

@ -82,6 +82,23 @@
namespace __sanitizer {
class SuspendedThreadsListLinux : public SuspendedThreadsList {
public:
SuspendedThreadsListLinux() : thread_ids_(1024) {}
tid_t GetThreadID(uptr index) const;
uptr ThreadCount() const;
bool ContainsTid(tid_t thread_id) const;
void Append(tid_t tid);
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
uptr *sp) const;
uptr RegisterCount() const;
private:
InternalMmapVector<tid_t> thread_ids_;
};
// Structure for passing arguments into the tracer thread.
struct TracerThreadArgument {
StopTheWorldCallback callback;
@ -105,12 +122,12 @@ class ThreadSuspender {
bool SuspendAllThreads();
void ResumeAllThreads();
void KillAllThreads();
SuspendedThreadsList &suspended_threads_list() {
SuspendedThreadsListLinux &suspended_threads_list() {
return suspended_threads_list_;
}
TracerThreadArgument *arg;
private:
SuspendedThreadsList suspended_threads_list_;
SuspendedThreadsListLinux suspended_threads_list_;
pid_t pid_;
bool SuspendThread(tid_t thread_id);
};
@ -119,8 +136,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) {
// Are we already attached to this thread?
// Currently this check takes linear time, however the number of threads is
// usually small.
if (suspended_threads_list_.Contains(tid))
return false;
if (suspended_threads_list_.ContainsTid(tid)) return false;
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr),
&pterrno)) {
@ -165,7 +181,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) {
}
void ThreadSuspender::ResumeAllThreads() {
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) {
pid_t tid = suspended_threads_list_.GetThreadID(i);
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr),
@ -181,7 +197,7 @@ void ThreadSuspender::ResumeAllThreads() {
}
void ThreadSuspender::KillAllThreads() {
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++)
for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++)
internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i),
nullptr, nullptr);
}
@ -492,9 +508,28 @@ typedef _user_regs_struct regs_struct;
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
uptr *buffer,
uptr *sp) const {
tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const {
CHECK_LT(index, thread_ids_.size());
return thread_ids_[index];
}
uptr SuspendedThreadsListLinux::ThreadCount() const {
return thread_ids_.size();
}
bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const {
for (uptr i = 0; i < thread_ids_.size(); i++) {
if (thread_ids_[i] == thread_id) return true;
}
return false;
}
void SuspendedThreadsListLinux::Append(tid_t tid) {
thread_ids_.push_back(tid);
}
PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
uptr index, uptr *buffer, uptr *sp) const {
pid_t tid = GetThreadID(index);
regs_struct regs;
int pterrno;
@ -524,7 +559,7 @@ PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
return REGISTERS_AVAILABLE;
}
uptr SuspendedThreadsList::RegisterCount() {
uptr SuspendedThreadsListLinux::RegisterCount() const {
return sizeof(regs_struct) / sizeof(uptr);
}
} // namespace __sanitizer

View File

@ -16,21 +16,78 @@
#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \
defined(__mips64) || defined(__i386))
#include <mach/mach.h>
#include "sanitizer_stoptheworld.h"
namespace __sanitizer {
typedef struct {
tid_t tid;
thread_t thread;
} SuspendedThreadInfo;
class SuspendedThreadsListMac : public SuspendedThreadsList {
public:
SuspendedThreadsListMac() : threads_(1024) {}
tid_t GetThreadID(uptr index) const;
thread_t GetThread(uptr index) const;
uptr ThreadCount() const;
bool ContainsThread(thread_t thread) const;
void Append(thread_t thread);
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
uptr *sp) const;
uptr RegisterCount() const;
private:
InternalMmapVector<SuspendedThreadInfo> threads_;
};
void StopTheWorld(StopTheWorldCallback callback, void *argument) {
CHECK(0 && "unimplemented");
}
PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
uptr *buffer,
uptr *sp) const {
tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const {
CHECK_LT(index, threads_.size());
return threads_[index].tid;
}
thread_t SuspendedThreadsListMac::GetThread(uptr index) const {
CHECK_LT(index, threads_.size());
return threads_[index].thread;
}
uptr SuspendedThreadsListMac::ThreadCount() const {
return threads_.size();
}
bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const {
for (uptr i = 0; i < threads_.size(); i++) {
if (threads_[i].thread == thread) return true;
}
return false;
}
void SuspendedThreadsListMac::Append(thread_t thread) {
thread_identifier_info_data_t info;
mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT;
kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO,
(thread_info_t)&info, &info_count);
if (err != KERN_SUCCESS) {
VReport(1, "Error - unable to get thread ident for a thread\n");
return;
}
threads_.push_back({info.thread_id, thread});
}
PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
uptr index, uptr *buffer, uptr *sp) const {
CHECK(0 && "unimplemented");
return REGISTERS_UNAVAILABLE_FATAL;
}
uptr SuspendedThreadsList::RegisterCount() {
uptr SuspendedThreadsListMac::RegisterCount() const {
CHECK(0 && "unimplemented");
return 0;
}