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); }
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 }