[TSan] Switch TSan runtime to use ThreadRegistry class from sanitizer_common
llvm-svn: 177154
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
index f25fb41..ad7d505 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -20,13 +20,124 @@
namespace __tsan {
-#ifndef TSAN_GO
-const int kThreadQuarantineSize = 16;
-#else
-const int kThreadQuarantineSize = 64;
-#endif
+// ThreadContext implementation.
-static void MaybeReportThreadLeak(ThreadContext *tctx) {
+ThreadContext::ThreadContext(int tid)
+ : ThreadContextBase(tid)
+ , thr()
+ , sync()
+ , epoch0()
+ , epoch1()
+ , dead_info() {
+}
+
+void ThreadContext::OnDead() {
+ sync.Reset();
+}
+
+void ThreadContext::OnJoined(void *arg) {
+ ThreadState *caller_thr = static_cast<ThreadState *>(arg);
+ caller_thr->clock.acquire(&sync);
+ StatInc(caller_thr, StatSyncAcquire);
+}
+
+struct OnCreatedArgs {
+ ThreadState *thr;
+ uptr pc;
+};
+
+void ThreadContext::OnCreated(void *arg) {
+ thr = 0;
+ if (tid != 0) {
+ OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
+ args->thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
+ args->thr->clock.set(args->thr->tid, args->thr->fast_state.epoch());
+ args->thr->fast_synch_epoch = args->thr->fast_state.epoch();
+ args->thr->clock.release(&sync);
+ StatInc(args->thr, StatSyncRelease);
+ creation_stack.ObtainCurrent(args->thr, args->pc);
+ }
+}
+
+void ThreadContext::OnReset(void *arg) {
+ OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
+ StatInc(args->thr, StatThreadReuse);
+ sync.Reset();
+}
+
+struct OnStartedArgs {
+ ThreadState *thr;
+ uptr stk_addr;
+ uptr stk_size;
+ uptr tls_addr;
+ uptr tls_size;
+};
+
+void ThreadContext::OnStarted(void *arg) {
+ OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
+ // RoundUp so that one trace part does not contain events
+ // from different threads.
+ epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
+ epoch1 = (u64)-1;
+ new(args->thr) ThreadState(CTX(), tid, unique_id,
+ epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
+#ifdef TSAN_GO
+ // Setup dynamic shadow stack.
+ const int kInitStackSize = 8;
+ args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+ kInitStackSize * sizeof(uptr));
+ args->thr->shadow_stack_pos = thr->shadow_stack;
+ args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+#endif
+#ifndef TSAN_GO
+ AllocatorThreadStart(args->thr);
+#endif
+ thr = args->thr;
+ thr->fast_synch_epoch = epoch0;
+ thr->clock.set(tid, epoch0);
+ thr->clock.acquire(&sync);
+ thr->fast_state.SetHistorySize(flags()->history_size);
+ const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
+ thr->trace.headers[trace].epoch0 = epoch0;
+ StatInc(thr, StatSyncAcquire);
+ DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
+ "tls_addr=%zx tls_size=%zx\n",
+ tid, (uptr)epoch0, stk_addr, stk_size, tls_addr, tls_size);
+ thr->is_alive = true;
+}
+
+void ThreadContext::OnFinished() {
+ if (!detached) {
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.release(&sync);
+ StatInc(thr, StatSyncRelease);
+ }
+ // Save from info about the thread.
+ dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo)))
+ ThreadDeadInfo();
+ for (uptr i = 0; i < TraceParts(); i++) {
+ dead_info->trace.headers[i].epoch0 = thr->trace.headers[i].epoch0;
+ dead_info->trace.headers[i].stack0.CopyFrom(
+ thr->trace.headers[i].stack0);
+ }
+ epoch1 = thr->fast_state.epoch();
+
+#ifndef TSAN_GO
+ AllocatorThreadFinish(thr);
+#endif
+ thr->~ThreadState();
+ StatAggregate(CTX()->stat, thr->stat);
+ thr = 0;
+}
+
+static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *unused) {
+ ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
if (tctx->detached)
return;
if (tctx->status != ThreadStatusCreated
@@ -42,122 +153,27 @@
CHECK_GT(thr->in_rtl, 0);
if (!flags()->report_thread_leaks)
return;
- Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- for (unsigned i = 0; i < kMaxTid; i++) {
- ThreadContext *tctx = ctx->threads[i];
- if (tctx == 0)
- continue;
- MaybeReportThreadLeak(tctx);
- }
+ ThreadRegistryLock l(CTX()->thread_registry);
+ CTX()->thread_registry->RunCallbackForEachThreadLocked(
+ MaybeReportThreadLeak, 0);
}
int ThreadCount(ThreadState *thr) {
CHECK_GT(thr->in_rtl, 0);
Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- int cnt = 0;
- for (unsigned i = 0; i < kMaxTid; i++) {
- ThreadContext *tctx = ctx->threads[i];
- if (tctx == 0)
- continue;
- if (tctx->status != ThreadStatusCreated
- && tctx->status != ThreadStatusRunning)
- continue;
- cnt++;
- }
- return cnt;
-}
-
-static void ThreadDead(ThreadState *thr, ThreadContext *tctx) {
- Context *ctx = CTX();
- CHECK_GT(thr->in_rtl, 0);
- CHECK(tctx->status == ThreadStatusRunning
- || tctx->status == ThreadStatusFinished);
- DPrintf("#%d: ThreadDead uid=%zu\n", thr->tid, tctx->user_id);
- tctx->status = ThreadStatusDead;
- tctx->user_id = 0;
- tctx->sync.Reset();
-
- // Put to dead list.
- tctx->dead_next = 0;
- if (ctx->dead_list_size == 0)
- ctx->dead_list_head = tctx;
- else
- ctx->dead_list_tail->dead_next = tctx;
- ctx->dead_list_tail = tctx;
- ctx->dead_list_size++;
+ uptr result;
+ ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
+ return (int)result;
}
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
CHECK_GT(thr->in_rtl, 0);
- Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
StatInc(thr, StatThreadCreate);
- int tid = -1;
- ThreadContext *tctx = 0;
- if (ctx->dead_list_size > kThreadQuarantineSize
- || ctx->thread_seq >= kMaxTid) {
- // Reusing old thread descriptor and tid.
- if (ctx->dead_list_size == 0) {
- Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
- kMaxTid);
- Die();
- }
- StatInc(thr, StatThreadReuse);
- tctx = ctx->dead_list_head;
- ctx->dead_list_head = tctx->dead_next;
- ctx->dead_list_size--;
- if (ctx->dead_list_size == 0) {
- CHECK_EQ(tctx->dead_next, 0);
- ctx->dead_list_head = 0;
- }
- CHECK_EQ(tctx->status, ThreadStatusDead);
- tctx->status = ThreadStatusInvalid;
- tctx->reuse_count++;
- tctx->sync.Reset();
- tid = tctx->tid;
- DestroyAndFree(tctx->dead_info);
- if (tctx->name) {
- internal_free(tctx->name);
- tctx->name = 0;
- }
- } else {
- // Allocating new thread descriptor and tid.
- StatInc(thr, StatThreadMaxTid);
- tid = ctx->thread_seq++;
- void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
- tctx = new(mem) ThreadContext(tid);
- ctx->threads[tid] = tctx;
- MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event));
- }
- CHECK_NE(tctx, 0);
- CHECK_GE(tid, 0);
- CHECK_LT(tid, kMaxTid);
+ Context *ctx = CTX();
+ OnCreatedArgs args = { thr, pc };
+ int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
- CHECK_EQ(tctx->status, ThreadStatusInvalid);
- ctx->alive_threads++;
- if (ctx->max_alive_threads < ctx->alive_threads) {
- ctx->max_alive_threads++;
- CHECK_EQ(ctx->max_alive_threads, ctx->alive_threads);
- StatInc(thr, StatThreadMaxAlive);
- }
- tctx->status = ThreadStatusCreated;
- tctx->thr = 0;
- tctx->user_id = uid;
- tctx->unique_id = ctx->unique_thread_seq++;
- tctx->detached = detached;
- if (tid) {
- thr->fast_state.IncrementEpoch();
- // Can't increment epoch w/o writing to the trace as well.
- TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&tctx->sync);
- StatInc(thr, StatSyncRelease);
- tctx->creation_stack.ObtainCurrent(thr, pc);
- tctx->creation_tid = thr->tid;
- }
+ StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
return tid;
}
@@ -188,42 +204,8 @@
}
}
- Lock l(&CTX()->thread_mtx);
- ThreadContext *tctx = CTX()->threads[tid];
- CHECK_NE(tctx, 0);
- CHECK_EQ(tctx->status, ThreadStatusCreated);
- tctx->status = ThreadStatusRunning;
- tctx->os_id = os_id;
- // RoundUp so that one trace part does not contain events
- // from different threads.
- tctx->epoch0 = RoundUp(tctx->epoch1 + 1, kTracePartSize);
- tctx->epoch1 = (u64)-1;
- new(thr) ThreadState(CTX(), tid, tctx->unique_id,
- tctx->epoch0, stk_addr, stk_size,
- tls_addr, tls_size);
-#ifdef TSAN_GO
- // Setup dynamic shadow stack.
- const int kInitStackSize = 8;
- thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
- kInitStackSize * sizeof(uptr));
- thr->shadow_stack_pos = thr->shadow_stack;
- thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
-#endif
-#ifndef TSAN_GO
- AllocatorThreadStart(thr);
-#endif
- tctx->thr = thr;
- thr->fast_synch_epoch = tctx->epoch0;
- thr->clock.set(tid, tctx->epoch0);
- thr->clock.acquire(&tctx->sync);
- thr->fast_state.SetHistorySize(flags()->history_size);
- const uptr trace = (tctx->epoch0 / kTracePartSize) % TraceParts();
- thr->trace.headers[trace].epoch0 = tctx->epoch0;
- StatInc(thr, StatSyncAcquire);
- DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
- "tls_addr=%zx tls_size=%zx\n",
- tid, (uptr)tctx->epoch0, stk_addr, stk_size, tls_addr, tls_size);
- thr->is_alive = true;
+ OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
+ CTX()->thread_registry->StartThread(tid, os_id, &args);
}
void ThreadFinish(ThreadState *thr) {
@@ -242,57 +224,22 @@
}
thr->is_alive = false;
Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- ThreadContext *tctx = ctx->threads[thr->tid];
- CHECK_NE(tctx, 0);
- CHECK_EQ(tctx->status, ThreadStatusRunning);
- CHECK_GT(ctx->alive_threads, 0);
- ctx->alive_threads--;
- if (tctx->detached) {
- ThreadDead(thr, tctx);
- } else {
- thr->fast_state.IncrementEpoch();
- // Can't increment epoch w/o writing to the trace as well.
- TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&tctx->sync);
- StatInc(thr, StatSyncRelease);
- tctx->status = ThreadStatusFinished;
- }
+ ctx->thread_registry->FinishThread(thr->tid);
+}
- // Save from info about the thread.
- tctx->dead_info = new(internal_alloc(MBlockDeadInfo, sizeof(ThreadDeadInfo)))
- ThreadDeadInfo();
- for (uptr i = 0; i < TraceParts(); i++) {
- tctx->dead_info->trace.headers[i].epoch0 = thr->trace.headers[i].epoch0;
- tctx->dead_info->trace.headers[i].stack0.CopyFrom(
- thr->trace.headers[i].stack0);
+static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
+ uptr uid = (uptr)arg;
+ if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
+ tctx->user_id = 0;
+ return true;
}
- tctx->epoch1 = thr->fast_state.epoch();
-
-#ifndef TSAN_GO
- AllocatorThreadFinish(thr);
-#endif
- thr->~ThreadState();
- StatAggregate(ctx->stat, thr->stat);
- tctx->thr = 0;
+ return false;
}
int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
CHECK_GT(thr->in_rtl, 0);
Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- int res = -1;
- for (unsigned tid = 0; tid < kMaxTid; tid++) {
- ThreadContext *tctx = ctx->threads[tid];
- if (tctx != 0 && tctx->user_id == uid
- && tctx->status != ThreadStatusInvalid) {
- tctx->user_id = 0;
- res = tid;
- break;
- }
- }
+ int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
return res;
}
@@ -303,18 +250,7 @@
CHECK_LT(tid, kMaxTid);
DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- ThreadContext *tctx = ctx->threads[tid];
- if (tctx->status == ThreadStatusInvalid) {
- Printf("ThreadSanitizer: join of non-existent thread\n");
- return;
- }
- // FIXME(dvyukov): print message and continue (it's user error).
- CHECK_EQ(tctx->detached, false);
- CHECK_EQ(tctx->status, ThreadStatusFinished);
- thr->clock.acquire(&tctx->sync);
- StatInc(thr, StatSyncAcquire);
- ThreadDead(thr, tctx);
+ ctx->thread_registry->JoinThread(tid, thr);
}
void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
@@ -322,31 +258,12 @@
CHECK_GT(tid, 0);
CHECK_LT(tid, kMaxTid);
Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- ThreadContext *tctx = ctx->threads[tid];
- if (tctx->status == ThreadStatusInvalid) {
- Printf("ThreadSanitizer: detach of non-existent thread\n");
- return;
- }
- if (tctx->status == ThreadStatusFinished) {
- ThreadDead(thr, tctx);
- } else {
- tctx->detached = true;
- }
+ ctx->thread_registry->DetachThread(tid);
}
void ThreadSetName(ThreadState *thr, const char *name) {
- Context *ctx = CTX();
- Lock l(&ctx->thread_mtx);
- ThreadContext *tctx = ctx->threads[thr->tid];
- CHECK_NE(tctx, 0);
- CHECK_EQ(tctx->status, ThreadStatusRunning);
- if (tctx->name) {
- internal_free(tctx->name);
- tctx->name = 0;
- }
- if (name)
- tctx->name = internal_strdup(name);
+ CHECK_GT(thr->in_rtl, 0);
+ CTX()->thread_registry->SetThreadName(thr->tid, name);
}
void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,