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() { |