Release execution lock before dispatching interrupt handling.
R=yurys@chromium.org Review URL: https://codereview.chromium.org/309533009 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21605 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
f1357a21d2
commit
97e550985e
@ -2541,6 +2541,8 @@ MaybeHandle<Object> Debug::MakeJSObject(const char* constructor_name,
|
|||||||
isolate_, isolate_->global_object(), constructor_name).ToHandleChecked();
|
isolate_, isolate_->global_object(), constructor_name).ToHandleChecked();
|
||||||
ASSERT(constructor->IsJSFunction());
|
ASSERT(constructor->IsJSFunction());
|
||||||
if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
|
if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
|
||||||
|
// We do not handle interrupts here. In particular, termination interrupts.
|
||||||
|
PostponeInterruptsScope no_interrupts(isolate_);
|
||||||
return Execution::TryCall(Handle<JSFunction>::cast(constructor),
|
return Execution::TryCall(Handle<JSFunction>::cast(constructor),
|
||||||
Handle<JSObject>(debug_context()->global_object()),
|
Handle<JSObject>(debug_context()->global_object()),
|
||||||
argc,
|
argc,
|
||||||
@ -2852,6 +2854,9 @@ void Debug::NotifyMessageHandler(v8::DebugEvent event,
|
|||||||
Handle<JSObject> exec_state,
|
Handle<JSObject> exec_state,
|
||||||
Handle<JSObject> event_data,
|
Handle<JSObject> event_data,
|
||||||
bool auto_continue) {
|
bool auto_continue) {
|
||||||
|
// Prevent other interrupts from triggering, for example API callbacks,
|
||||||
|
// while dispatching message handler callbacks.
|
||||||
|
PostponeInterruptsScope no_interrupts(isolate_);
|
||||||
ASSERT(is_active_);
|
ASSERT(is_active_);
|
||||||
HandleScope scope(isolate_);
|
HandleScope scope(isolate_);
|
||||||
// Process the individual events.
|
// Process the individual events.
|
||||||
|
@ -366,13 +366,13 @@ void StackGuard::ClearInterrupt(int flagbit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag,
|
bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
|
||||||
const ExecutionAccess& lock) {
|
ExecutionAccess access(isolate_);
|
||||||
int flagbit = 1 << flag;
|
int flagbit = 1 << flag;
|
||||||
bool result = (thread_local_.interrupt_flags_ & flagbit);
|
bool result = (thread_local_.interrupt_flags_ & flagbit);
|
||||||
thread_local_.interrupt_flags_ &= ~flagbit;
|
thread_local_.interrupt_flags_ &= ~flagbit;
|
||||||
if (!should_postpone_interrupts(lock) && !has_pending_interrupts(lock)) {
|
if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
|
||||||
reset_limits(lock);
|
reset_limits(access);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -655,46 +655,43 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
|
|||||||
|
|
||||||
|
|
||||||
Object* StackGuard::HandleInterrupts() {
|
Object* StackGuard::HandleInterrupts() {
|
||||||
bool has_api_interrupt = false;
|
|
||||||
{
|
{
|
||||||
ExecutionAccess access(isolate_);
|
ExecutionAccess access(isolate_);
|
||||||
if (should_postpone_interrupts(access)) {
|
if (should_postpone_interrupts(access)) {
|
||||||
return isolate_->heap()->undefined_value();
|
return isolate_->heap()->undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckAndClearInterrupt(GC_REQUEST, access)) {
|
|
||||||
isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckDebugBreak() || CheckDebugCommand()) {
|
|
||||||
isolate_->debug()->DebugBreakHelper();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) {
|
|
||||||
return isolate_->TerminateExecution();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) {
|
|
||||||
isolate_->heap()->DeoptMarkedAllocationSites();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CheckAndClearInterrupt(INSTALL_CODE, access)) {
|
|
||||||
ASSERT(isolate_->concurrent_recompilation_enabled());
|
|
||||||
isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
|
|
||||||
}
|
|
||||||
|
|
||||||
has_api_interrupt = CheckAndClearInterrupt(API_INTERRUPT, access);
|
|
||||||
|
|
||||||
isolate_->counters()->stack_interrupts()->Increment();
|
|
||||||
isolate_->counters()->runtime_profiler_ticks()->Increment();
|
|
||||||
isolate_->runtime_profiler()->OptimizeNow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_api_interrupt) {
|
if (CheckAndClearInterrupt(GC_REQUEST)) {
|
||||||
|
isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckDebugBreak() || CheckDebugCommand()) {
|
||||||
|
isolate_->debug()->DebugBreakHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
|
||||||
|
return isolate_->TerminateExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
|
||||||
|
isolate_->heap()->DeoptMarkedAllocationSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckAndClearInterrupt(INSTALL_CODE)) {
|
||||||
|
ASSERT(isolate_->concurrent_recompilation_enabled());
|
||||||
|
isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckAndClearInterrupt(API_INTERRUPT)) {
|
||||||
// Callback must be invoked outside of ExecusionAccess lock.
|
// Callback must be invoked outside of ExecusionAccess lock.
|
||||||
isolate_->InvokeApiInterruptCallback();
|
isolate_->InvokeApiInterruptCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isolate_->counters()->stack_interrupts()->Increment();
|
||||||
|
isolate_->counters()->runtime_profiler_ticks()->Increment();
|
||||||
|
isolate_->runtime_profiler()->OptimizeNow();
|
||||||
|
|
||||||
return isolate_->heap()->undefined_value();
|
return isolate_->heap()->undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ enum InterruptFlag {
|
|||||||
bool CheckInterrupt(int flagbit);
|
bool CheckInterrupt(int flagbit);
|
||||||
void RequestInterrupt(int flagbit);
|
void RequestInterrupt(int flagbit);
|
||||||
void ClearInterrupt(int flagbit);
|
void ClearInterrupt(int flagbit);
|
||||||
bool CheckAndClearInterrupt(InterruptFlag flag, const ExecutionAccess& lock);
|
bool CheckAndClearInterrupt(InterruptFlag flag);
|
||||||
|
|
||||||
// You should hold the ExecutionAccess lock when calling this method.
|
// You should hold the ExecutionAccess lock when calling this method.
|
||||||
bool has_pending_interrupts(const ExecutionAccess& lock) {
|
bool has_pending_interrupts(const ExecutionAccess& lock) {
|
||||||
|
@ -7425,3 +7425,49 @@ TEST(DebugBreakStackTrace) {
|
|||||||
" }"
|
" }"
|
||||||
"})()");
|
"})()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
v8::internal::Semaphore terminate_requested_semaphore(0);
|
||||||
|
v8::internal::Semaphore terminate_fired_semaphore(0);
|
||||||
|
bool terminate_already_fired = false;
|
||||||
|
|
||||||
|
|
||||||
|
static void DebugBreakTriggerTerminate(
|
||||||
|
const v8::Debug::EventDetails& event_details) {
|
||||||
|
if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
|
||||||
|
terminate_requested_semaphore.Signal();
|
||||||
|
// Wait for at most 2 seconds for the terminate request.
|
||||||
|
CHECK(terminate_fired_semaphore.WaitFor(i::TimeDelta::FromSeconds(2)));
|
||||||
|
terminate_already_fired = true;
|
||||||
|
v8::internal::Isolate* isolate =
|
||||||
|
v8::Utils::OpenHandle(*event_details.GetEventContext())->GetIsolate();
|
||||||
|
CHECK(isolate->stack_guard()->CheckTerminateExecution());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TerminationThread : public v8::internal::Thread {
|
||||||
|
public:
|
||||||
|
explicit TerminationThread(v8::Isolate* isolate) : Thread("terminator"),
|
||||||
|
isolate_(isolate) { }
|
||||||
|
|
||||||
|
virtual void Run() {
|
||||||
|
terminate_requested_semaphore.Wait();
|
||||||
|
v8::V8::TerminateExecution(isolate_);
|
||||||
|
terminate_fired_semaphore.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
v8::Isolate* isolate_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST(DebugBreakOffThreadTerminate) {
|
||||||
|
DebugLocalContext env;
|
||||||
|
v8::Isolate* isolate = env->GetIsolate();
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
v8::Debug::SetDebugEventListener(DebugBreakTriggerTerminate);
|
||||||
|
TerminationThread terminator(isolate);
|
||||||
|
terminator.Start();
|
||||||
|
v8::Debug::DebugBreak(isolate);
|
||||||
|
CompileRun("while (true);");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user