summaryrefslogtreecommitdiff
path: root/lib/lsan/lsan_thread.cc
diff options
context:
space:
mode:
authorSergey Matveev <earthdok@google.com>2013-05-20 10:57:53 +0000
committerSergey Matveev <earthdok@google.com>2013-05-20 10:57:53 +0000
commit56f77a7570d96aa4c6afb7ab26e58925b2506f86 (patch)
tree9b5a5d5f885cd1801cca3b6764fa887282f24d87 /lib/lsan/lsan_thread.cc
parentc99de512472c5635e554d983c225aa3a92a20202 (diff)
[lsan] Thread registry for standalone LSan.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@182246 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/lsan/lsan_thread.cc')
-rw-r--r--lib/lsan/lsan_thread.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc
new file mode 100644
index 000000000..3a60036a9
--- /dev/null
+++ b/lib/lsan/lsan_thread.cc
@@ -0,0 +1,163 @@
+//=-- lsan_thread.cc ------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// See lsan_thread.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lsan_thread.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "lsan_allocator.h"
+
+namespace __lsan {
+
+const u32 kInvalidTid = (u32) -1;
+
+static ThreadRegistry *thread_registry;
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+
+static ThreadContextBase *CreateThreadContext(u32 tid) {
+ void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
+ return new(mem) ThreadContext(tid);
+}
+
+static const uptr kMaxThreads = 1 << 13;
+static const uptr kThreadQuarantineSize = 64;
+
+void InitializeThreadRegistry() {
+ static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64);
+ thread_registry = new(thread_registry_placeholder)
+ ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
+}
+
+u32 GetCurrentThread() {
+ return current_thread_tid;
+}
+
+void SetCurrentThread(u32 tid) {
+ current_thread_tid = tid;
+}
+
+ThreadContext::ThreadContext(int tid)
+ : ThreadContextBase(tid),
+ stack_begin_(0),
+ stack_end_(0),
+ cache_begin_(0),
+ cache_end_(0),
+ tls_begin_(0),
+ tls_end_(0) {}
+
+struct OnStartedArgs {
+ uptr stack_begin, stack_end,
+ cache_begin, cache_end,
+ tls_begin, tls_end;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ OnStartedArgs *args = reinterpret_cast<OnStartedArgs *>(arg);
+ stack_begin_ = args->stack_begin;
+ stack_end_ = args->stack_end;
+ tls_begin_ = args->tls_begin;
+ tls_end_ = args->tls_end;
+ cache_begin_ = args->cache_begin;
+ cache_end_ = args->cache_end;
+}
+
+void ThreadContext::OnFinished() {
+ AllocatorThreadFinish();
+}
+
+u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
+ return thread_registry->CreateThread(user_id, detached, parent_tid,
+ /* arg */ 0);
+}
+
+void ThreadStart(u32 tid, uptr os_id) {
+ OnStartedArgs args;
+ uptr stack_size = 0;
+ uptr tls_size = 0;
+ GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size,
+ &args.tls_begin, &tls_size);
+ args.stack_end = args.stack_begin + stack_size;
+ args.tls_end = args.tls_begin + tls_size;
+ GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ thread_registry->StartThread(tid, os_id, &args);
+}
+
+void ThreadFinish() {
+ thread_registry->FinishThread(GetCurrentThread());
+}
+
+ThreadContext *CurrentThreadContext() {
+ if (!thread_registry) return 0;
+ if (GetCurrentThread() == kInvalidTid)
+ return 0;
+ // No lock needed when getting current thread.
+ return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
+}
+
+bool FindThreadByOsIdCallback(ThreadContextBase *tctx, void *arg) {
+ return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
+ tctx->status != ThreadStatusDead);
+}
+
+ThreadContext *FindThreadByOsIDLocked(uptr os_id) {
+ ThreadContextBase *tctx =
+ thread_registry->FindThreadContextLocked(FindThreadByOsIdCallback,
+ (void*)os_id);
+ return static_cast<ThreadContext *>(tctx);
+}
+
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+ return true;
+ }
+ return false;
+}
+
+u32 ThreadTid(uptr uid) {
+ return thread_registry->FindThread(FindThreadByUid, (void*)uid);
+}
+
+void ThreadJoin(u32 tid) {
+ CHECK_NE(tid, kInvalidTid);
+ thread_registry->JoinThread(tid, /* arg */0);
+}
+
+///// Interface to the common LSan module. /////
+
+bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+ uptr *tls_begin, uptr *tls_end,
+ uptr *cache_begin, uptr *cache_end) {
+ ThreadContext *context = FindThreadByOsIDLocked(os_id);
+ if (!context)
+ return false;
+ *stack_begin = context->stack_begin();
+ *stack_end = context->stack_end();
+ *tls_begin = context->tls_begin();
+ *tls_end = context->tls_end();
+ *cache_begin = context->cache_begin();
+ *cache_end = context->cache_end();
+ return true;
+}
+
+void LockThreadRegistry() {
+ thread_registry->Lock();
+}
+
+void UnlockThreadRegistry() {
+ thread_registry->Unlock();
+}
+
+} // namespace __lsan