Chromium Code Reviews| Index: runtime/vm/thread_interrupter_android.cc |
| diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc |
| index 82be148cbd07f3b85c7f594eaf585ef9b832ca6b..0cc1b2a71e4285f16b479aadb25c93051e5a7cc4 100644 |
| --- a/runtime/vm/thread_interrupter_android.cc |
| +++ b/runtime/vm/thread_interrupter_android.cc |
| @@ -21,29 +21,59 @@ namespace dart { |
| DECLARE_FLAG(bool, thread_interrupter); |
| DECLARE_FLAG(bool, trace_thread_interrupter); |
| -class ThreadInterrupterAndroid : public AllStatic { |
| - public: |
| - static void ThreadInterruptSignalHandler(int signal, siginfo_t* info, |
| - void* context_) { |
| - if (signal != SIGPROF) { |
| - return; |
| - } |
| - Thread* thread = Thread::Current(); |
| - if (thread == NULL) { |
| - return; |
| - } |
| - // Extract thread state. |
| - ucontext_t* context = reinterpret_cast<ucontext_t*>(context_); |
| - mcontext_t mcontext = context->uc_mcontext; |
| - InterruptedThreadState its; |
| - its.pc = SignalHandler::GetProgramCounter(mcontext); |
| - its.fp = SignalHandler::GetFramePointer(mcontext); |
| - its.csp = SignalHandler::GetCStackPointer(mcontext); |
| - its.dsp = SignalHandler::GetDartStackPointer(mcontext); |
| - its.lr = SignalHandler::GetLinkRegister(mcontext); |
| - Profiler::SampleThread(thread, its); |
| +static void ThreadInterruptSignalHandler(int signal, siginfo_t* info, |
| + void* context_) { |
| + if (signal != SIGPROF) { |
| + return; |
| } |
| -}; |
| + Thread* thread = Thread::Current(); |
| + if (thread == NULL) { |
| + return; |
| + } |
| + // Extract thread state. |
| + ucontext_t* context = reinterpret_cast<ucontext_t*>(context_); |
| + mcontext_t mcontext = context->uc_mcontext; |
| + InterruptedThreadState its; |
| + its.pc = SignalHandler::GetProgramCounter(mcontext); |
| + its.fp = SignalHandler::GetFramePointer(mcontext); |
| + its.csp = SignalHandler::GetCStackPointer(mcontext); |
| + its.dsp = SignalHandler::GetDartStackPointer(mcontext); |
| + its.lr = SignalHandler::GetLinkRegister(mcontext); |
| + Profiler::SampleThread(thread, its); |
| +} |
| + |
| + |
| +// Work around for a bug in old kernels (only fixed in 3.18 Android kernel): |
| +// kernel does not clear If-Then execution state bits when entering ARM signal |
| +// handler which violates requirements imposed by ARM architecture reference. |
| +// Some CPUs look at these bits even while in ARM mode which causes them |
| +// to skip some instructions in the prologue of the signal handler. |
| +// To work around the issue we insert enough NOPs in the prologue to ensure that |
| +// no actual instructions are skipped and then branch to the actual signal |
| +// handler. |
| +// For the kernel patch that fixes the issue see: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6ecf830e5029598732e04067e325d946097519cb |
| +// Note: this function is marked "naked" because we must guarantee that |
| +// our NOPs occur before any compiler generated prologue. |
| +static __attribute__((naked)) void SignalHandlerTrampoline(int signal, |
| + siginfo_t* info, |
| + void* context_) { |
| + // IT (If-Then) instruction makes up to four instructions that follow it |
| + // conditional. |
| + asm volatile("nop; nop; nop; nop" : : : "memory"); |
| + |
| + // Tail-call into the actual signal handler. |
| + // Note: this code is split into a separate inline assembly block because |
| + // any code that compiler generates to satisfy register constraints must |
| + // be generated after four NOPs. |
| + register int arg0 asm("r0") = signal; |
| + register siginfo_t* arg1 asm("r1") = info; |
| + register void* arg2 asm("r2") = context_; |
| + asm volatile("bx %3" |
|
Florian Schneider
2016/05/02 13:44:45
Need this only on ARM, not on Android ia32 for exa
|
| + : |
| + : "r"(arg0), "r"(arg1), "r"(arg2), |
| + "r"(&ThreadInterruptSignalHandler) |
| + : "memory"); |
| +} |
| void ThreadInterrupter::InterruptThread(OSThread* thread) { |
| @@ -57,8 +87,7 @@ void ThreadInterrupter::InterruptThread(OSThread* thread) { |
| void ThreadInterrupter::InstallSignalHandler() { |
| - SignalHandler::Install( |
| - ThreadInterrupterAndroid::ThreadInterruptSignalHandler); |
| + SignalHandler::Install(&SignalHandlerTrampoline); |
| } |