Make climit and jslimit stack limits atomic.

This fixes TSAN failure caused by race between:
 - optimizing compiler thread setting climit
 - and json parser reading climit in the main thread.

BUG=

Review URL: https://codereview.chromium.org/1031223004

Cr-Commit-Position: refs/heads/master@{#27840}
This commit is contained in:
ulan 2015-04-15 04:37:07 -07:00 committed by Commit bot
parent dd06f905cb
commit 3a814e4c1a
2 changed files with 34 additions and 20 deletions

View File

@ -20,16 +20,16 @@ StackGuard::StackGuard()
void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
DCHECK(isolate_ != NULL);
thread_local_.jslimit_ = kInterruptLimit;
thread_local_.climit_ = kInterruptLimit;
thread_local_.set_jslimit(kInterruptLimit);
thread_local_.set_climit(kInterruptLimit);
isolate_->heap()->SetStackLimits();
}
void StackGuard::reset_limits(const ExecutionAccess& lock) {
DCHECK(isolate_ != NULL);
thread_local_.jslimit_ = thread_local_.real_jslimit_;
thread_local_.climit_ = thread_local_.real_climit_;
thread_local_.set_jslimit(thread_local_.real_jslimit_);
thread_local_.set_climit(thread_local_.real_climit_);
isolate_->heap()->SetStackLimits();
}
@ -354,11 +354,11 @@ void StackGuard::SetStackLimit(uintptr_t limit) {
// If the current limits are special (e.g. due to a pending interrupt) then
// leave them alone.
uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
if (thread_local_.jslimit_ == thread_local_.real_jslimit_) {
thread_local_.jslimit_ = jslimit;
if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
thread_local_.set_jslimit(jslimit);
}
if (thread_local_.climit_ == thread_local_.real_climit_) {
thread_local_.climit_ = limit;
if (thread_local_.climit() == thread_local_.real_climit_) {
thread_local_.set_climit(limit);
}
thread_local_.real_climit_ = limit;
thread_local_.real_jslimit_ = jslimit;
@ -474,9 +474,9 @@ void StackGuard::FreeThreadResources() {
void StackGuard::ThreadLocal::Clear() {
real_jslimit_ = kIllegalLimit;
jslimit_ = kIllegalLimit;
set_jslimit(kIllegalLimit);
real_climit_ = kIllegalLimit;
climit_ = kIllegalLimit;
set_climit(kIllegalLimit);
postpone_interrupts_ = NULL;
interrupt_flags_ = 0;
}
@ -489,9 +489,9 @@ bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
DCHECK(GetCurrentStackPosition() > kLimitSize);
uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
real_climit_ = limit;
climit_ = limit;
set_climit(limit);
should_set_stack_limits = true;
}
postpone_interrupts_ = NULL;

View File

@ -171,18 +171,14 @@ class StackGuard FINAL {
#undef V
};
uintptr_t climit() { return thread_local_.climit(); }
uintptr_t jslimit() { return thread_local_.jslimit(); }
// This provides an asynchronous read of the stack limits for the current
// thread. There are no locks protecting this, but it is assumed that you
// have the global V8 lock if you are using multiple V8 threads.
uintptr_t climit() {
return thread_local_.climit_;
}
uintptr_t real_climit() {
return thread_local_.real_climit_;
}
uintptr_t jslimit() {
return thread_local_.jslimit_;
}
uintptr_t real_jslimit() {
return thread_local_.real_jslimit_;
}
@ -256,9 +252,27 @@ class StackGuard FINAL {
// fail. Both the generated code and the runtime system check against the
// one without the real_ prefix.
uintptr_t real_jslimit_; // Actual JavaScript stack limit set for the VM.
uintptr_t jslimit_;
uintptr_t real_climit_; // Actual C++ stack limit set for the VM.
uintptr_t climit_;
// jslimit_ and climit_ can be read without any lock.
// Writing requires the ExecutionAccess lock.
base::AtomicWord jslimit_;
base::AtomicWord climit_;
uintptr_t jslimit() {
return bit_cast<uintptr_t>(base::NoBarrier_Load(&jslimit_));
}
void set_jslimit(uintptr_t limit) {
return base::NoBarrier_Store(&jslimit_,
static_cast<base::AtomicWord>(limit));
}
uintptr_t climit() {
return bit_cast<uintptr_t>(base::NoBarrier_Load(&climit_));
}
void set_climit(uintptr_t limit) {
return base::NoBarrier_Store(&climit_,
static_cast<base::AtomicWord>(limit));
}
PostponeInterruptsScope* postpone_interrupts_;
int interrupt_flags_;