Esempio n. 1
0
void
ThreadStackHelper::GetStack(HangStack& aStack, nsACString& aRunnableName, bool aStackWalk)
{
  aRunnableName.AssignLiteral("???");

  if (!PrepareStackBuffer(aStack)) {
    return;
  }

  Array<char, nsThread::kRunnableNameBufSize> runnableName;
  runnableName[0] = '\0';

  ScopedSetPtr<HangStack> _stackGuard(mStackToFill, &aStack);
  ScopedSetPtr<Array<char, nsThread::kRunnableNameBufSize>>
    _runnableGuard(mRunnableNameBuffer, &runnableName);

  // XXX: We don't need to pass in ProfilerFeature::StackWalk to trigger
  // stackwalking, as that is instead controlled by the last argument.
  profiler_suspend_and_sample_thread(
    mThreadId, ProfilerFeature::Privacy, *this, aStackWalk);

  // Copy the name buffer allocation into the output string. We explicitly set
  // the last byte to null in case we read in some corrupted data without a null
  // terminator.
  runnableName[nsThread::kRunnableNameBufSize - 1] = '\0';
  aRunnableName.AssignASCII(runnableName.cbegin());
}
void
ThreadStackHelper::GetStack(Stack& aStack)
{
  // Always run PrepareStackBuffer first to clear aStack
  if (!PrepareStackBuffer(aStack)) {
    // Skip and return empty aStack
    return;
  }

#if defined(XP_LINUX)
  if (profiler_is_active()) {
    // Profiler can interfere with our Linux signal handling
    return;
  }
  if (!sInitialized) {
    MOZ_ASSERT(false);
    return;
  }
  sCurrent = this;
  struct sigaction sigact = {};
  sigact.sa_sigaction = SigAction;
  sigemptyset(&sigact.sa_mask);
  sigact.sa_flags = SA_SIGINFO | SA_RESTART;
  if (::sigaction(SIGPROF, &sigact, &sOldSigAction)) {
    MOZ_ASSERT(false);
    return;
  }
  MOZ_ALWAYS_TRUE(!::syscall(SYS_tgkill, getpid(), mThreadID, SIGPROF));
  MOZ_ALWAYS_TRUE(!::sem_wait(&sSem));

#elif defined(XP_WIN)
  if (!mInitialized) {
    MOZ_ASSERT(false);
    return;
  }
  if (::SuspendThread(mThreadID) == DWORD(-1)) {
    MOZ_ASSERT(false);
    return;
  }
  FillStackBuffer();
  MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));

#elif defined(XP_MACOSX)
  if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
    MOZ_ASSERT(false);
    return;
  }
  FillStackBuffer();
  MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);

#endif
  aStack = Move(mStackBuffer);
}
Esempio n. 3
0
void
ThreadStackHelper::GetStack(Stack& aStack)
{
  // Always run PrepareStackBuffer first to clear aStack
  if (!PrepareStackBuffer(aStack)) {
    // Skip and return empty aStack
    return;
  }

  ScopedSetPtr<Stack> stackPtr(mStackToFill, &aStack);

#if defined(XP_LINUX)
  if (!sInitialized) {
    MOZ_ASSERT(false);
    return;
  }
  siginfo_t uinfo = {};
  uinfo.si_signo = sFillStackSignum;
  uinfo.si_code = SI_QUEUE;
  uinfo.si_pid = getpid();
  uinfo.si_uid = getuid();
  uinfo.si_value.sival_ptr = this;
  if (::syscall(SYS_rt_tgsigqueueinfo, uinfo.si_pid,
                mThreadID, sFillStackSignum, &uinfo)) {
    // rt_tgsigqueueinfo was added in Linux 2.6.31.
    // Could have failed because the syscall did not exist.
    return;
  }
  MOZ_ALWAYS_TRUE(!::sem_wait(&mSem));

#elif defined(XP_WIN)
  if (!mInitialized) {
    MOZ_ASSERT(false);
    return;
  }
  if (::SuspendThread(mThreadID) == DWORD(-1)) {
    MOZ_ASSERT(false);
    return;
  }

  FillStackBuffer();
  FillThreadContext();

  MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));

#elif defined(XP_MACOSX)
# if defined(MOZ_VALGRIND) && defined(RUNNING_ON_VALGRIND)
  if (RUNNING_ON_VALGRIND) {
    /* thread_suspend and thread_resume sometimes hang runs on Valgrind,
       for unknown reasons.  So, just avoid them.  See bug 1100911. */
    return;
  }
# endif

  if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
    MOZ_ASSERT(false);
    return;
  }

  FillStackBuffer();
  FillThreadContext();

  MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);

#endif
}