| Index: src/platform-linux.cc
|
| diff --git a/src/platform-linux.cc b/src/platform-linux.cc
|
| index ec48d6305e3de2ea4b51f0571a1c7a83bb0ae619..aebcd083af55a0373970ee387ef6ffa57a34ba45 100644
|
| --- a/src/platform-linux.cc
|
| +++ b/src/platform-linux.cc
|
| @@ -1022,62 +1022,6 @@ static int GetThreadID() {
|
| }
|
|
|
|
|
| -static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
| - USE(info);
|
| - if (signal != SIGPROF) return;
|
| - Isolate* isolate = Isolate::UncheckedCurrent();
|
| - if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
|
| - // We require a fully initialized and entered isolate.
|
| - return;
|
| - }
|
| - if (v8::Locker::IsActive() &&
|
| - !isolate->thread_manager()->IsLockedByCurrentThread()) {
|
| - return;
|
| - }
|
| -
|
| - Sampler* sampler = isolate->logger()->sampler();
|
| - if (sampler == NULL || !sampler->IsActive()) return;
|
| -
|
| - TickSample sample_obj;
|
| - TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
|
| - if (sample == NULL) sample = &sample_obj;
|
| -
|
| - // Extracting the sample from the context is extremely machine dependent.
|
| - ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
| - mcontext_t& mcontext = ucontext->uc_mcontext;
|
| - sample->state = isolate->current_vm_state();
|
| -#if V8_HOST_ARCH_IA32
|
| - sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
|
| - sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
|
| - sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
|
| -#elif V8_HOST_ARCH_X64
|
| - sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
|
| - sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
|
| - sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
|
| -#elif V8_HOST_ARCH_ARM
|
| -#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
|
| - (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
|
| - // Old GLibc ARM versions used a gregs[] array to access the register
|
| - // values from mcontext_t.
|
| - sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
|
| - sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
|
| - sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
|
| -#else
|
| - sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
|
| - sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
|
| - sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
|
| -#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
|
| - // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
|
| -#elif V8_HOST_ARCH_MIPS
|
| - sample->pc = reinterpret_cast<Address>(mcontext.pc);
|
| - sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
|
| - sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
|
| -#endif // V8_HOST_ARCH_*
|
| - sampler->SampleStack(sample);
|
| - sampler->Tick(sample);
|
| -}
|
| -
|
| -
|
| class Sampler::PlatformData : public Malloced {
|
| public:
|
| PlatformData() : vm_tid_(GetThreadID()) {}
|
| @@ -1089,6 +1033,9 @@ class Sampler::PlatformData : public Malloced {
|
| };
|
|
|
|
|
| +static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context);
|
| +
|
| +
|
| class SignalSender : public Thread {
|
| public:
|
| enum SleepInterval {
|
| @@ -1110,6 +1057,10 @@ class SignalSender : public Thread {
|
| struct sigaction sa;
|
| sa.sa_sigaction = ProfilerSignalHandler;
|
| sigemptyset(&sa.sa_mask);
|
| + sigset_t signals_to_unblock;
|
| + sigemptyset(&signals_to_unblock);
|
| + sigaddset(&signals_to_unblock, SIGPROF);
|
| + sigprocmask(SIG_UNBLOCK, &signals_to_unblock, &old_signal_mask_);
|
| sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
| signal_handler_installed_ =
|
| (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
|
| @@ -1118,10 +1069,33 @@ class SignalSender : public Thread {
|
| static void RestoreSignalHandler() {
|
| if (signal_handler_installed_) {
|
| sigaction(SIGPROF, &old_signal_handler_, 0);
|
| + sigprocmask(SIG_SETMASK, &old_signal_mask_, NULL);
|
| signal_handler_installed_ = false;
|
| }
|
| }
|
|
|
| + static void CallOldSignalHandler(int signal, siginfo_t* info, void* context) {
|
| + // Only invoke the old signal handler if it did not have SIGPROF masked.
|
| + if (sigismember(&old_signal_mask_, SIGPROF))
|
| + return;
|
| + if (!(old_signal_handler_.sa_flags & SA_SIGINFO)) {
|
| + // If the old signal disposition was SIG_IGN, then it is safe to ignore
|
| + // the old signal handler. If it is SIG_DFL, then that is pretty strong
|
| + // evidence that nobody other than us is using the profiling
|
| + // infrastructure. It is probably reasonable to assume that in this case
|
| + // we don't need to chain to the old behavior, as that would merely result
|
| + // in the application getting terminated.
|
| + if (old_signal_handler_.sa_handler == SIG_IGN ||
|
| + old_signal_handler_.sa_handler == SIG_DFL) {
|
| + return;
|
| + }
|
| + // Sorry, we only support other 3-arg signal handlers (sigaction). Crash
|
| + // loudly if someone tries to use a different signal handler.
|
| + *(reinterpret_cast<volatile char*>(NULL) + 74) = 0x34;
|
| + }
|
| + old_signal_handler_.sa_sigaction(signal, info, context);
|
| + }
|
| +
|
| static void AddActiveSampler(Sampler* sampler) {
|
| ScopedLock lock(mutex_);
|
| SamplerRegistry::AddActiveSampler(sampler);
|
| @@ -1243,6 +1217,7 @@ class SignalSender : public Thread {
|
| static SignalSender* instance_;
|
| static bool signal_handler_installed_;
|
| static struct sigaction old_signal_handler_;
|
| + static sigset_t old_signal_mask_;
|
|
|
| private:
|
| DISALLOW_COPY_AND_ASSIGN(SignalSender);
|
| @@ -1253,6 +1228,72 @@ Mutex* SignalSender::mutex_ = NULL;
|
| SignalSender* SignalSender::instance_ = NULL;
|
| struct sigaction SignalSender::old_signal_handler_;
|
| bool SignalSender::signal_handler_installed_ = false;
|
| +sigset_t SignalSender::old_signal_mask_;
|
| +
|
| +
|
| +static void ProfilerSignalHandlerInternal(
|
| + int signal, siginfo_t* info, void* context) {
|
| + USE(info);
|
| + if (signal != SIGPROF) return;
|
| + SignalSender::CallOldSignalHandler(signal, info, context);
|
| + Isolate* isolate = Isolate::UncheckedCurrent();
|
| + if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
|
| + // We require a fully initialized and entered isolate.
|
| + return;
|
| + }
|
| + if (v8::Locker::IsActive() &&
|
| + !isolate->thread_manager()->IsLockedByCurrentThread()) {
|
| + return;
|
| + }
|
| +
|
| + Sampler* sampler = isolate->logger()->sampler();
|
| + if (sampler == NULL || !sampler->IsActive()) return;
|
| +
|
| + TickSample sample_obj;
|
| + TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
|
| + if (sample == NULL) sample = &sample_obj;
|
| +
|
| + // Extracting the sample from the context is extremely machine dependent.
|
| + ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
| + mcontext_t& mcontext = ucontext->uc_mcontext;
|
| + sample->state = isolate->current_vm_state();
|
| +#if V8_HOST_ARCH_IA32
|
| + sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
|
| +#elif V8_HOST_ARCH_X64
|
| + sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
|
| +#elif V8_HOST_ARCH_ARM
|
| +#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
|
| + (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
|
| + // Old GLibc ARM versions used a gregs[] array to access the register
|
| + // values from mcontext_t.
|
| + sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
|
| +#else
|
| + sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
|
| +#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
|
| + // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
|
| +#elif V8_HOST_ARCH_MIPS
|
| + sample->pc = reinterpret_cast<Address>(mcontext.pc);
|
| + sample->sp = reinterpret_cast<Address>(mcontext.gregs[29]);
|
| + sample->fp = reinterpret_cast<Address>(mcontext.gregs[30]);
|
| +#endif // V8_HOST_ARCH_*
|
| + sampler->SampleStack(sample);
|
| + sampler->Tick(sample);
|
| +}
|
| +
|
| +
|
| +static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
| + int curr_errno = errno;
|
| + ProfilerSignalHandlerInternal(signal, info, context);
|
| + errno = curr_errno;
|
| +}
|
|
|
|
|
| void OS::SetUp() {
|
|
|