[compiler-rt] r206035 - tsan: fix vector clocks
Dmitry Vyukov
dvyukov at google.com
Fri Apr 11 08:38:03 PDT 2014
Author: dvyukov
Date: Fri Apr 11 10:38:03 2014
New Revision: 206035
URL: http://llvm.org/viewvc/llvm-project?rev=206035&view=rev
Log:
tsan: fix vector clocks
the new optimizations break when thread ids gets reused (clocks go backwards)
add the necessary tests as well
Modified:
compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.cc
compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.h
compiler-rt/trunk/lib/tsan/Makefile.old
compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h
compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
compiler-rt/trunk/lib/tsan/tests/unit/tsan_clock_test.cc
compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.cc Fri Apr 11 10:38:03 2014
@@ -17,8 +17,9 @@
namespace __sanitizer {
ThreadContextBase::ThreadContextBase(u32 tid)
- : tid(tid), unique_id(0), os_id(0), user_id(0), status(ThreadStatusInvalid),
- detached(false), reuse_count(0), parent_tid(0), next(0) {
+ : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
+ status(ThreadStatusInvalid),
+ detached(false), parent_tid(0), next(0) {
name[0] = '\0';
}
@@ -78,7 +79,6 @@ void ThreadContextBase::SetCreated(uptr
void ThreadContextBase::Reset() {
status = ThreadStatusInvalid;
- reuse_count++;
SetName(0);
OnReset();
}
@@ -88,10 +88,11 @@ void ThreadContextBase::Reset() {
const u32 ThreadRegistry::kUnknownTid = ~0U;
ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
- u32 thread_quarantine_size)
+ u32 thread_quarantine_size, u32 max_reuse)
: context_factory_(factory),
max_threads_(max_threads),
thread_quarantine_size_(thread_quarantine_size),
+ max_reuse_(max_reuse),
mtx_(),
n_contexts_(0),
total_threads_(0),
@@ -282,6 +283,9 @@ void ThreadRegistry::QuarantinePush(Thre
dead_threads_.pop_front();
CHECK_EQ(tctx->status, ThreadStatusDead);
tctx->Reset();
+ tctx->reuse_count++;
+ if (max_reuse_ > 0 && tctx->reuse_count >= max_reuse_)
+ return;
invalid_threads_.push_back(tctx);
}
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.h?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_thread_registry.h Fri Apr 11 10:38:03 2014
@@ -38,13 +38,13 @@ class ThreadContextBase {
const u32 tid; // Thread ID. Main thread should have tid = 0.
u64 unique_id; // Unique thread ID.
+ u32 reuse_count; // Number of times this tid was reused.
uptr os_id; // PID (used for reporting).
uptr user_id; // Some opaque user thread id (e.g. pthread_t).
char name[64]; // As annotated by user.
ThreadStatus status;
bool detached;
- int reuse_count;
u32 parent_tid;
ThreadContextBase *next; // For storing thread contexts in a list.
@@ -77,7 +77,7 @@ class ThreadRegistry {
static const u32 kUnknownTid;
ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
- u32 thread_quarantine_size);
+ u32 thread_quarantine_size, u32 max_reuse = 0);
void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0);
uptr GetMaxAliveThreads();
@@ -119,6 +119,7 @@ class ThreadRegistry {
const ThreadContextFactory context_factory_;
const u32 max_threads_;
const u32 thread_quarantine_size_;
+ const u32 max_reuse_;
BlockingMutex mtx_;
Modified: compiler-rt/trunk/lib/tsan/Makefile.old
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/Makefile.old?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/Makefile.old (original)
+++ compiler-rt/trunk/lib/tsan/Makefile.old Fri Apr 11 10:38:03 2014
@@ -1,5 +1,5 @@
DEBUG=0
-LDFLAGS=-ldl -lpthread -pie
+LDFLAGS=-ldl -lrt -lpthread -pie
CXXFLAGS = -std=c++11 -fPIE -fno-rtti -g -Wall -Werror \
-DGTEST_HAS_RTTI=0 -DTSAN_DEBUG=$(DEBUG) -DSANITIZER_DEBUG=$(DEBUG)
CLANG=clang
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_clock.cc Fri Apr 11 10:38:03 2014
@@ -69,13 +69,15 @@
//
// Description of SyncClock state:
// clk_ - variable size vector clock, low kClkBits hold timestamp,
-// the remaining bits hold "last_acq" counter;
-// if last_acq == release_seq_, then the respective thread has already
+// the remaining bits hold "acquired" flag (the actual value is thread's
+// reused counter);
+// if acquried == thr->reused_, then the respective thread has already
// acquired this clock (except possibly dirty_tids_).
// dirty_tids_ - holds up to two indeces in the vector clock that other threads
-// need to acquire regardless of last_acq value;
+// need to acquire regardless of "acquired" flag value;
// release_store_tid_ - denotes that the clock state is a result of
// release-store operation by the thread with release_store_tid_ index.
+// release_store_reused_ - reuse count of release_store_tid_.
// We don't have ThreadState in these methods, so this is an ugly hack that
// works only in C++.
@@ -89,11 +91,15 @@ namespace __tsan {
const unsigned kInvalidTid = (unsigned)-1;
-ThreadClock::ThreadClock(unsigned tid)
- : tid_(tid) {
- DCHECK_LT(tid, kMaxTidInClock);
+ThreadClock::ThreadClock(unsigned tid, unsigned reused)
+ : tid_(tid)
+ , reused_(reused + 1) { // 0 has special meaning
+ CHECK_LT(tid, kMaxTidInClock);
+ CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
nclk_ = tid_ + 1;
+ last_acquire_ = 0;
internal_memset(clk_, 0, sizeof(clk_));
+ clk_[tid_].reused = reused_;
}
void ThreadClock::acquire(const SyncClock *src) {
@@ -108,37 +114,25 @@ void ThreadClock::acquire(const SyncCloc
return;
}
- // If the clock is a result of release-store operation, and the current thread
- // has already acquired from that thread after or at that time,
- // don't need to do anything (src can't contain anything new for the
- // current thread).
- unsigned tid1 = src->release_store_tid_;
- if (tid1 != kInvalidTid && (src->clk_[tid1] & kClkMask) <= clk_[tid1]) {
- CPP_STAT_INC(StatClockAcquireFastRelease);
- return;
- }
-
// Check if we've already acquired src after the last release operation on src
bool acquired = false;
if (nclk > tid_) {
CPP_STAT_INC(StatClockAcquireLarge);
- u64 myepoch = src->clk_[tid_];
- u64 last_acq = myepoch >> kClkBits;
- if (last_acq == src->release_seq_) {
+ if (src->clk_[tid_].reused == reused_) {
CPP_STAT_INC(StatClockAcquireRepeat);
for (unsigned i = 0; i < kDirtyTids; i++) {
unsigned tid = src->dirty_tids_[i];
if (tid != kInvalidTid) {
- u64 epoch = src->clk_[tid] & kClkMask;
- if (clk_[tid] < epoch) {
- clk_[tid] = epoch;
+ u64 epoch = src->clk_[tid].epoch;
+ if (clk_[tid].epoch < epoch) {
+ clk_[tid].epoch = epoch;
acquired = true;
}
}
}
if (acquired) {
CPP_STAT_INC(StatClockAcquiredSomething);
- last_acquire_ = clk_[tid_];
+ last_acquire_ = clk_[tid_].epoch;
}
return;
}
@@ -148,28 +142,26 @@ void ThreadClock::acquire(const SyncCloc
CPP_STAT_INC(StatClockAcquireFull);
nclk_ = max(nclk_, nclk);
for (uptr i = 0; i < nclk; i++) {
- u64 epoch = src->clk_[i] & kClkMask;
- if (clk_[i] < epoch) {
- clk_[i] = epoch;
+ u64 epoch = src->clk_[i].epoch;
+ if (clk_[i].epoch < epoch) {
+ clk_[i].epoch = epoch;
acquired = true;
}
}
// Remember that this thread has acquired this clock.
- if (nclk > tid_) {
- u64 myepoch = src->clk_[tid_];
- src->clk_[tid_] = (myepoch & kClkMask) | (src->release_seq_ << kClkBits);
- }
+ if (nclk > tid_)
+ src->clk_[tid_].reused = reused_;
if (acquired) {
CPP_STAT_INC(StatClockAcquiredSomething);
- last_acquire_ = clk_[tid_];
+ last_acquire_ = clk_[tid_].epoch;
}
}
void ThreadClock::release(SyncClock *dst) const {
- DCHECK(nclk_ <= kMaxTid);
- DCHECK(dst->clk_.Size() <= kMaxTid);
+ DCHECK_LE(nclk_, kMaxTid);
+ DCHECK_LE(dst->clk_.Size(), kMaxTid);
if (dst->clk_.Size() == 0) {
// ReleaseStore will correctly set release_store_tid_,
@@ -188,9 +180,10 @@ void ThreadClock::release(SyncClock *dst
// Check if we had not acquired anything from other threads
// since the last release on dst. If so, we need to update
// only dst->clk_[tid_].
- if ((dst->clk_[tid_] & kClkMask) > last_acquire_) {
+ if (dst->clk_[tid_].epoch > last_acquire_) {
UpdateCurrentThread(dst);
- if (dst->release_store_tid_ != tid_)
+ if (dst->release_store_tid_ != tid_ ||
+ dst->release_store_reused_ != reused_)
dst->release_store_tid_ = kInvalidTid;
return;
}
@@ -202,22 +195,23 @@ void ThreadClock::release(SyncClock *dst
if (acquired)
CPP_STAT_INC(StatClockReleaseAcquired);
// Update dst->clk_.
- for (uptr i = 0; i < nclk_; i++)
- dst->clk_[i] = max(dst->clk_[i] & kClkMask, clk_[i]);
- // Clear last_acq in the remaining elements.
+ for (uptr i = 0; i < nclk_; i++) {
+ dst->clk_[i].epoch = max(dst->clk_[i].epoch, clk_[i].epoch);
+ dst->clk_[i].reused = 0;
+ }
+ // Clear 'acquired' flag in the remaining elements.
if (nclk_ < dst->clk_.Size())
CPP_STAT_INC(StatClockReleaseClearTail);
for (uptr i = nclk_; i < dst->clk_.Size(); i++)
- dst->clk_[i] = dst->clk_[i] & kClkMask;
- // Since we've cleared all last_acq, we can reset release_seq_ as well.
- dst->release_seq_ = 1;
+ dst->clk_[i].reused = 0;
for (unsigned i = 0; i < kDirtyTids; i++)
dst->dirty_tids_[i] = kInvalidTid;
dst->release_store_tid_ = kInvalidTid;
+ dst->release_store_reused_ = 0;
// If we've acquired dst, remember this fact,
// so that we don't need to acquire it on next acquire.
if (acquired)
- dst->clk_[tid_] = dst->clk_[tid_] | (1ULL << kClkBits);
+ dst->clk_[tid_].reused = reused_;
}
void ThreadClock::ReleaseStore(SyncClock *dst) const {
@@ -232,7 +226,8 @@ void ThreadClock::ReleaseStore(SyncClock
}
if (dst->release_store_tid_ == tid_ &&
- (dst->clk_[tid_] & kClkMask) > last_acquire_) {
+ dst->release_store_reused_ == reused_ &&
+ dst->clk_[tid_].epoch > last_acquire_) {
CPP_STAT_INC(StatClockStoreFast);
UpdateCurrentThread(dst);
return;
@@ -240,21 +235,22 @@ void ThreadClock::ReleaseStore(SyncClock
// O(N) release-store.
CPP_STAT_INC(StatClockStoreFull);
- for (uptr i = 0; i < nclk_; i++)
- dst->clk_[i] = clk_[i];
+ for (uptr i = 0; i < nclk_; i++) {
+ dst->clk_[i].epoch = clk_[i].epoch;
+ dst->clk_[i].reused = 0;
+ }
// Clear the tail of dst->clk_.
if (nclk_ < dst->clk_.Size()) {
internal_memset(&dst->clk_[nclk_], 0,
(dst->clk_.Size() - nclk_) * sizeof(dst->clk_[0]));
CPP_STAT_INC(StatClockStoreTail);
}
- // Since we've cleared all last_acq, we can reset release_seq_ as well.
- dst->release_seq_ = 1;
for (unsigned i = 0; i < kDirtyTids; i++)
dst->dirty_tids_[i] = kInvalidTid;
dst->release_store_tid_ = tid_;
+ dst->release_store_reused_ = reused_;
// Rememeber that we don't need to acquire it in future.
- dst->clk_[tid_] = clk_[tid_] | (1ULL << kClkBits);
+ dst->clk_[tid_].reused = reused_;
}
void ThreadClock::acq_rel(SyncClock *dst) {
@@ -265,8 +261,8 @@ void ThreadClock::acq_rel(SyncClock *dst
// Updates only single element related to the current thread in dst->clk_.
void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
- // Update the threads time, but preserve last_acq.
- dst->clk_[tid_] = clk_[tid_] | (dst->clk_[tid_] & ~kClkMask);
+ // Update the threads time, but preserve 'acquired' flag.
+ dst->clk_[tid_].epoch = clk_[tid_].epoch;
for (unsigned i = 0; i < kDirtyTids; i++) {
if (dst->dirty_tids_[i] == tid_) {
@@ -279,29 +275,23 @@ void ThreadClock::UpdateCurrentThread(Sy
return;
}
}
- CPP_STAT_INC(StatClockReleaseFast3);
- dst->release_seq_++;
+ // Reset all 'acquired' flags, O(N).
+ CPP_STAT_INC(StatClockReleaseSlow);
+ for (uptr i = 0; i < dst->clk_.Size(); i++) {
+ dst->clk_[i].reused = 0;
+ }
for (unsigned i = 0; i < kDirtyTids; i++)
dst->dirty_tids_[i] = kInvalidTid;
- if ((dst->release_seq_ << kClkBits) == 0) {
- CPP_STAT_INC(StatClockReleaseLastOverflow);
- dst->release_seq_ = 1;
- for (uptr i = 0; i < dst->clk_.Size(); i++)
- dst->clk_[i] = dst->clk_[i] & kClkMask;
- }
}
// Checks whether the current threads has already acquired src.
bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
- u64 myepoch = src->clk_[tid_];
- u64 last_acq = myepoch >> kClkBits;
- if (last_acq != src->release_seq_)
+ if (src->clk_[tid_].reused != reused_)
return false;
for (unsigned i = 0; i < kDirtyTids; i++) {
unsigned tid = src->dirty_tids_[i];
if (tid != kInvalidTid) {
- u64 epoch = src->clk_[tid] & kClkMask;
- if (clk_[tid] < epoch)
+ if (clk_[tid].epoch < src->clk_[tid].epoch)
return false;
}
}
@@ -312,32 +302,36 @@ bool ThreadClock::IsAlreadyAcquired(cons
// This function is called only from weird places like AcquireGlobal.
void ThreadClock::set(unsigned tid, u64 v) {
DCHECK_LT(tid, kMaxTid);
- DCHECK_GE(v, clk_[tid]);
- clk_[tid] = v;
+ DCHECK_GE(v, clk_[tid].epoch);
+ clk_[tid].epoch = v;
if (nclk_ <= tid)
nclk_ = tid + 1;
- last_acquire_ = clk_[tid_];
+ last_acquire_ = clk_[tid_].epoch;
}
void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
printf("clock=[");
for (uptr i = 0; i < nclk_; i++)
- printf("%s%llu", i == 0 ? "" : ",", clk_[i]);
- printf("] tid=%u last_acq=%llu", tid_, last_acquire_);
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
+ printf("] reused=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
+ printf("] tid=%u/%u last_acq=%llu",
+ tid_, reused_, last_acquire_);
}
SyncClock::SyncClock()
: clk_(MBlockClock) {
+ release_store_tid_ = kInvalidTid;
+ release_store_reused_ = 0;
for (uptr i = 0; i < kDirtyTids; i++)
dirty_tids_[i] = kInvalidTid;
- release_seq_ = 0;
- release_store_tid_ = kInvalidTid;
}
void SyncClock::Reset() {
clk_.Reset();
- release_seq_ = 0;
release_store_tid_ = kInvalidTid;
+ release_store_reused_ = 0;
for (uptr i = 0; i < kDirtyTids; i++)
dirty_tids_[i] = kInvalidTid;
}
@@ -345,11 +339,12 @@ void SyncClock::Reset() {
void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
printf("clock=[");
for (uptr i = 0; i < clk_.Size(); i++)
- printf("%s%llu", i == 0 ? "" : ",", clk_[i] & kClkMask);
- printf("] last_acq=[");
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
+ printf("] reused=[");
for (uptr i = 0; i < clk_.Size(); i++)
- printf("%s%llu", i == 0 ? "" : ",", clk_[i] >> kClkBits);
- printf("] release_seq=%llu release_store_tid=%d dirty_tids=%d/%d",
- release_seq_, release_store_tid_, dirty_tids_[0], dirty_tids_[1]);
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
+ printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
+ release_store_tid_, release_store_reused_,
+ dirty_tids_[0], dirty_tids_[1]);
}
} // namespace __tsan
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_clock.h Fri Apr 11 10:38:03 2014
@@ -18,7 +18,10 @@
namespace __tsan {
-const u64 kClkMask = (1ULL << kClkBits) - 1;
+struct ClockElem {
+ u64 epoch : kClkBits;
+ u64 reused : 64 - kClkBits;
+};
// The clock that lives in sync variables (mutexes, atomics, etc).
class SyncClock {
@@ -31,7 +34,7 @@ class SyncClock {
u64 get(unsigned tid) const {
DCHECK_LT(tid, clk_.Size());
- return clk_[tid] & kClkMask;
+ return clk_[tid].epoch;
}
void Reset();
@@ -39,34 +42,33 @@ class SyncClock {
void DebugDump(int(*printf)(const char *s, ...));
private:
- u64 release_seq_;
unsigned release_store_tid_;
+ unsigned release_store_reused_;
static const uptr kDirtyTids = 2;
unsigned dirty_tids_[kDirtyTids];
- mutable Vector<u64> clk_;
+ mutable Vector<ClockElem> clk_;
friend struct ThreadClock;
};
// The clock that lives in threads.
struct ThreadClock {
public:
- explicit ThreadClock(unsigned tid);
+ explicit ThreadClock(unsigned tid, unsigned reused = 0);
u64 get(unsigned tid) const {
DCHECK_LT(tid, kMaxTidInClock);
- DCHECK_EQ(clk_[tid], clk_[tid] & kClkMask);
- return clk_[tid];
+ return clk_[tid].epoch;
}
void set(unsigned tid, u64 v);
void set(u64 v) {
- DCHECK_GE(v, clk_[tid_]);
- clk_[tid_] = v;
+ DCHECK_GE(v, clk_[tid_].epoch);
+ clk_[tid_].epoch = v;
}
void tick() {
- clk_[tid_]++;
+ clk_[tid_].epoch++;
}
uptr size() const {
@@ -78,14 +80,16 @@ struct ThreadClock {
void acq_rel(SyncClock *dst);
void ReleaseStore(SyncClock *dst) const;
+ void DebugReset();
void DebugDump(int(*printf)(const char *s, ...));
private:
static const uptr kDirtyTids = SyncClock::kDirtyTids;
const unsigned tid_;
+ const unsigned reused_;
u64 last_acquire_;
uptr nclk_;
- u64 clk_[kMaxTidInClock];
+ ClockElem clk_[kMaxTidInClock];
bool IsAlreadyAcquired(const SyncClock *src) const;
void UpdateCurrentThread(SyncClock *dst) const;
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_defs.h Fri Apr 11 10:38:03 2014
@@ -41,6 +41,7 @@ const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 42;
+const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
const uptr kShadowStackSize = 64 * 1024;
const uptr kTraceStackSize = 256;
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.cc Fri Apr 11 10:38:03 2014
@@ -75,7 +75,7 @@ Context::Context()
, nreported()
, nmissed_expected()
, thread_registry(new(thread_registry_placeholder) ThreadRegistry(
- CreateThreadContext, kMaxTid, kThreadQuarantineSize))
+ CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
, racy_stacks(MBlockRacyStacks)
, racy_addresses(MBlockRacyAddresses)
, fired_suppressions(8) {
@@ -83,6 +83,7 @@ Context::Context()
// The objects are allocated in TLS, so one may rely on zero-initialization.
ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size)
: fast_state(tid, epoch)
@@ -90,7 +91,7 @@ ThreadState::ThreadState(Context *ctx, i
// they may be accessed before the ctor.
// , ignore_reads_and_writes()
// , ignore_interceptors()
- , clock(tid)
+ , clock(tid, reuse_count)
#ifndef TSAN_GO
, jmp_bufs(MBlockJmpBuf)
#endif
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Fri Apr 11 10:38:03 2014
@@ -467,6 +467,7 @@ struct ThreadState {
int nomalloc;
explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
+ unsigned reuse_count,
uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size);
};
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_thread.cc Fri Apr 11 10:38:03 2014
@@ -85,8 +85,8 @@ void ThreadContext::OnStarted(void *arg)
// from different threads.
epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
epoch1 = (u64)-1;
- new(thr) ThreadState(ctx, tid, unique_id,
- epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
+ new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count,
+ args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
#ifndef TSAN_GO
thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
thr->shadow_stack_pos = thr->shadow_stack;
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.cc Fri Apr 11 10:38:03 2014
@@ -85,11 +85,10 @@ void StatOutput(u64 *stat) {
name[StatClockReleaseResize] = " resize ";
name[StatClockReleaseFast1] = " fast1 ";
name[StatClockReleaseFast2] = " fast2 ";
- name[StatClockReleaseFast3] = " fast3 ";
+ name[StatClockReleaseSlow] = " dirty overflow (slow) ";
name[StatClockReleaseFull] = " full (slow) ";
name[StatClockReleaseAcquired] = " was acquired ";
name[StatClockReleaseClearTail] = " clear tail ";
- name[StatClockReleaseLastOverflow] = " last overflow ";
name[StatClockStore] = "Clock release store ";
name[StatClockStoreResize] = " resize ";
name[StatClockStoreFast] = " fast ";
Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_stat.h Fri Apr 11 10:38:03 2014
@@ -82,11 +82,10 @@ enum StatType {
StatClockReleaseResize,
StatClockReleaseFast1,
StatClockReleaseFast2,
- StatClockReleaseFast3,
+ StatClockReleaseSlow,
StatClockReleaseFull,
StatClockReleaseAcquired,
StatClockReleaseClearTail,
- StatClockReleaseLastOverflow,
// Clocks - release store.
StatClockStore,
StatClockStoreResize,
Modified: compiler-rt/trunk/lib/tsan/tests/unit/tsan_clock_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/tests/unit/tsan_clock_test.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/tests/unit/tsan_clock_test.cc (original)
+++ compiler-rt/trunk/lib/tsan/tests/unit/tsan_clock_test.cc Fri Apr 11 10:38:03 2014
@@ -13,6 +13,7 @@
#include "tsan_clock.h"
#include "tsan_rtl.h"
#include "gtest/gtest.h"
+#include <time.h>
namespace __tsan {
@@ -63,6 +64,19 @@ TEST(Clock, AcquireRelease) {
ASSERT_EQ(vector2.get(100), 1U);
}
+TEST(Clock, RepeatedAcquire) {
+ ThreadClock thr1(1);
+ thr1.tick();
+ ThreadClock thr2(2);
+ thr2.tick();
+
+ SyncClock sync;
+ thr1.ReleaseStore(&sync);
+
+ thr2.acquire(&sync);
+ thr2.acquire(&sync);
+}
+
TEST(Clock, ManyThreads) {
SyncClock chunked;
for (unsigned i = 0; i < 100; i++) {
@@ -130,6 +144,10 @@ struct SimpleSyncClock {
uptr size;
SimpleSyncClock() {
+ Reset();
+ }
+
+ void Reset() {
size = 0;
for (uptr i = 0; i < kThreads; i++)
clock[i] = 0;
@@ -211,9 +229,11 @@ static bool ClockFuzzer(bool printing) {
// Create kThreads thread clocks.
SimpleThreadClock *thr0[kThreads];
ThreadClock *thr1[kThreads];
+ unsigned reused[kThreads];
for (unsigned i = 0; i < kThreads; i++) {
+ reused[i] = 0;
thr0[i] = new SimpleThreadClock(i);
- thr1[i] = new ThreadClock(i);
+ thr1[i] = new ThreadClock(i, reused[i]);
}
// Create kClocks sync clocks.
@@ -232,7 +252,7 @@ static bool ClockFuzzer(bool printing) {
thr0[tid]->tick();
thr1[tid]->tick();
- switch (rand() % 4) {
+ switch (rand() % 6) {
case 0:
if (printing)
printf("acquire thr%d <- clk%d\n", tid, cid);
@@ -257,6 +277,24 @@ static bool ClockFuzzer(bool printing) {
thr0[tid]->ReleaseStore(sync0[cid]);
thr1[tid]->ReleaseStore(sync1[cid]);
break;
+ case 4:
+ if (printing)
+ printf("reset clk%d\n", cid);
+ sync0[cid]->Reset();
+ sync1[cid]->Reset();
+ break;
+ case 5:
+ if (printing)
+ printf("reset thr%d\n", tid);
+ u64 epoch = thr0[tid]->clock[tid] + 1;
+ reused[tid]++;
+ delete thr0[tid];
+ thr0[tid] = new SimpleThreadClock(tid);
+ thr0[tid]->clock[tid] = epoch;
+ delete thr1[tid];
+ thr1[tid] = new ThreadClock(tid, reused[tid]);
+ thr1[tid]->set(epoch);
+ break;
}
if (printing) {
@@ -297,7 +335,9 @@ static bool ClockFuzzer(bool printing) {
}
TEST(Clock, Fuzzer) {
- int seed = time(0);
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ int seed = ts.tv_sec + ts.tv_nsec;
printf("seed=%d\n", seed);
srand(seed);
if (!ClockFuzzer(false)) {
Modified: compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc?rev=206035&r1=206034&r2=206035&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc (original)
+++ compiler-rt/trunk/lib/tsan/tests/unit/tsan_stack_test.cc Fri Apr 11 10:38:03 2014
@@ -18,7 +18,7 @@
namespace __tsan {
static void TestStackTrace(StackTrace *trace) {
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
uptr stack[128];
thr.shadow_stack = &stack[0];
thr.shadow_stack_pos = &stack[0];
@@ -62,7 +62,7 @@ TEST(StackTrace, StaticTrim) {
uptr buf[2];
StackTrace trace(buf, 2);
- ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0);
+ ThreadState thr(0, 0, 0, 0, 0, 0, 0, 0, 0);
uptr stack[128];
thr.shadow_stack = &stack[0];
thr.shadow_stack_pos = &stack[0];
More information about the llvm-commits
mailing list