summaryrefslogtreecommitdiffstats
path: root/tools/profiler/core/platform-linux.cc
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-05-24 14:06:04 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-05-24 14:06:04 +0200
commitac25827a87d86f1cf9e48aab6605f77a2c89041a (patch)
treec3533a008e606f4f6393e838b4305cf6d07f47d2 /tools/profiler/core/platform-linux.cc
parentc8b38a18031f6ae0fca8b2bef73daa86f6f96ae8 (diff)
downloadUXP-ac25827a87d86f1cf9e48aab6605f77a2c89041a.tar
UXP-ac25827a87d86f1cf9e48aab6605f77a2c89041a.tar.gz
UXP-ac25827a87d86f1cf9e48aab6605f77a2c89041a.tar.lz
UXP-ac25827a87d86f1cf9e48aab6605f77a2c89041a.tar.xz
UXP-ac25827a87d86f1cf9e48aab6605f77a2c89041a.zip
Remove SPS profiler.
- Conditionals and code blocks. (MOZ_ENABLE_PROFILER_SPS) - Stub out several profiler-only functions.
Diffstat (limited to 'tools/profiler/core/platform-linux.cc')
-rw-r--r--tools/profiler/core/platform-linux.cc715
1 files changed, 0 insertions, 715 deletions
diff --git a/tools/profiler/core/platform-linux.cc b/tools/profiler/core/platform-linux.cc
deleted file mode 100644
index 160873c9d..000000000
--- a/tools/profiler/core/platform-linux.cc
+++ /dev/null
@@ -1,715 +0,0 @@
-// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in
-// the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google, Inc. nor the names of its contributors
-// may be used to endorse or promote products derived from this
-// software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
-
-/*
-# vim: sw=2
-*/
-#include <stdio.h>
-#include <math.h>
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/prctl.h> // set name
-#include <stdlib.h>
-#include <sched.h>
-#ifdef ANDROID
-#include <android/log.h>
-#else
-#define __android_log_print(a, ...)
-#endif
-#include <ucontext.h>
-// Ubuntu Dapper requires memory pages to be marked as
-// executable. Otherwise, OS raises an exception when executing code
-// in that page.
-#include <sys/types.h> // mmap & munmap
-#include <sys/mman.h> // mmap & munmap
-#include <sys/stat.h> // open
-#include <fcntl.h> // open
-#include <unistd.h> // sysconf
-#include <semaphore.h>
-#ifdef __GLIBC__
-#include <execinfo.h> // backtrace, backtrace_symbols
-#endif // def __GLIBC__
-#include <strings.h> // index
-#include <errno.h>
-#include <stdarg.h>
-#include "prenv.h"
-#include "platform.h"
-#include "GeckoProfiler.h"
-#include "mozilla/Mutex.h"
-#include "mozilla/Atomics.h"
-#include "mozilla/LinuxSignal.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/DebugOnly.h"
-#include "ProfileEntry.h"
-#include "nsThreadUtils.h"
-#include "GeckoSampler.h"
-#include "ThreadResponsiveness.h"
-
-#if defined(__ARM_EABI__) && defined(ANDROID)
- // Should also work on other Android and ARM Linux, but not tested there yet.
-# define USE_EHABI_STACKWALK
-# include "EHABIStackWalk.h"
-#elif defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_x86_linux)
-# define USE_LUL_STACKWALK
-# include "lul/LulMain.h"
-# include "lul/platform-linux-lul.h"
-#endif
-
-// Memory profile
-#include "nsMemoryReporterManager.h"
-
-#include <string.h>
-#include <list>
-
-#define SIGNAL_SAVE_PROFILE SIGUSR2
-
-using namespace mozilla;
-
-#if defined(USE_LUL_STACKWALK)
-// A singleton instance of the library. It is initialised at first
-// use. Currently only the main thread can call Sampler::Start, so
-// there is no need for a mechanism to ensure that it is only
-// created once in a multi-thread-use situation.
-lul::LUL* sLUL = nullptr;
-
-// This is the sLUL initialization routine.
-static void sLUL_initialization_routine(void)
-{
- MOZ_ASSERT(!sLUL);
- MOZ_ASSERT(gettid() == getpid()); /* "this is the main thread" */
- sLUL = new lul::LUL(logging_sink_for_LUL);
- // Read all the unwind info currently available.
- read_procmaps(sLUL);
-}
-#endif
-
-/* static */ Thread::tid_t
-Thread::GetCurrentId()
-{
- return gettid();
-}
-
-#if !defined(ANDROID)
-// Keep track of when any of our threads calls fork(), so we can
-// temporarily disable signal delivery during the fork() call. Not
-// doing so appears to cause a kind of race, in which signals keep
-// getting delivered to the thread doing fork(), which keeps causing
-// it to fail and be restarted; hence forward progress is delayed a
-// great deal. A side effect of this is to permanently disable
-// sampling in the child process. See bug 837390.
-
-// Unfortunately this is only doable on non-Android, since Bionic
-// doesn't have pthread_atfork.
-
-// This records the current state at the time we paused it.
-static bool was_paused = false;
-
-// In the parent, just before the fork, record the pausedness state,
-// and then pause.
-static void paf_prepare(void) {
- if (Sampler::GetActiveSampler()) {
- was_paused = Sampler::GetActiveSampler()->IsPaused();
- Sampler::GetActiveSampler()->SetPaused(true);
- } else {
- was_paused = false;
- }
-}
-
-// In the parent, just after the fork, return pausedness to the
-// pre-fork state.
-static void paf_parent(void) {
- if (Sampler::GetActiveSampler())
- Sampler::GetActiveSampler()->SetPaused(was_paused);
-}
-
-// Set up the fork handlers.
-static void* setup_atfork() {
- pthread_atfork(paf_prepare, paf_parent, NULL);
- return NULL;
-}
-#endif /* !defined(ANDROID) */
-
-struct SamplerRegistry {
- static void AddActiveSampler(Sampler *sampler) {
- ASSERT(!SamplerRegistry::sampler);
- SamplerRegistry::sampler = sampler;
- }
- static void RemoveActiveSampler(Sampler *sampler) {
- SamplerRegistry::sampler = NULL;
- }
- static Sampler *sampler;
-};
-
-Sampler *SamplerRegistry::sampler = NULL;
-
-static mozilla::Atomic<ThreadProfile*> sCurrentThreadProfile;
-static sem_t sSignalHandlingDone;
-
-static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context) {
- Sampler::GetActiveSampler()->RequestSave();
-}
-
-static void SetSampleContext(TickSample* sample, void* context)
-{
- // Extracting the sample from the context is extremely machine dependent.
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
- mcontext_t& mcontext = ucontext->uc_mcontext;
-#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
-// An undefined macro evaluates to 0, so this applies to Android's Bionic also.
-#if !defined(ANDROID) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
- sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
- sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
- sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
-#ifdef ENABLE_ARM_LR_SAVING
- sample->lr = reinterpret_cast<Address>(mcontext.gregs[R14]);
-#endif
-#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);
-#ifdef ENABLE_ARM_LR_SAVING
- sample->lr = reinterpret_cast<Address>(mcontext.arm_lr);
-#endif
-#endif
-#elif V8_HOST_ARCH_MIPS
- // Implement this on MIPS.
- UNIMPLEMENTED();
-#endif
-}
-
-#ifdef ANDROID
-#define V8_HOST_ARCH_ARM 1
-#define SYS_gettid __NR_gettid
-#define SYS_tgkill __NR_tgkill
-#else
-#define V8_HOST_ARCH_X64 1
-#endif
-
-namespace {
-
-void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
- // Avoid TSan warning about clobbering errno.
- int savedErrno = errno;
-
- if (!Sampler::GetActiveSampler()) {
- sem_post(&sSignalHandlingDone);
- errno = savedErrno;
- return;
- }
-
- TickSample sample_obj;
- TickSample* sample = &sample_obj;
- sample->context = context;
-
- // If profiling, we extract the current pc and sp.
- if (Sampler::GetActiveSampler()->IsProfiling()) {
- SetSampleContext(sample, context);
- }
- sample->threadProfile = sCurrentThreadProfile;
- sample->timestamp = mozilla::TimeStamp::Now();
- sample->rssMemory = sample->threadProfile->mRssMemory;
- sample->ussMemory = sample->threadProfile->mUssMemory;
-
- Sampler::GetActiveSampler()->Tick(sample);
-
- sCurrentThreadProfile = NULL;
- sem_post(&sSignalHandlingDone);
- errno = savedErrno;
-}
-
-} // namespace
-
-static void ProfilerSignalThread(ThreadProfile *profile,
- bool isFirstProfiledThread)
-{
- if (isFirstProfiledThread && Sampler::GetActiveSampler()->ProfileMemory()) {
- profile->mRssMemory = nsMemoryReporterManager::ResidentFast();
- profile->mUssMemory = nsMemoryReporterManager::ResidentUnique();
- } else {
- profile->mRssMemory = 0;
- profile->mUssMemory = 0;
- }
-}
-
-int tgkill(pid_t tgid, pid_t tid, int signalno) {
- return syscall(SYS_tgkill, tgid, tid, signalno);
-}
-
-class PlatformData {
- public:
- PlatformData()
- {
- MOZ_COUNT_CTOR(PlatformData);
- }
-
- ~PlatformData()
- {
- MOZ_COUNT_DTOR(PlatformData);
- }
-};
-
-/* static */ PlatformData*
-Sampler::AllocPlatformData(int aThreadId)
-{
- return new PlatformData;
-}
-
-/* static */ void
-Sampler::FreePlatformData(PlatformData* aData)
-{
- delete aData;
-}
-
-static void* SignalSender(void* arg) {
- // Taken from platform_thread_posix.cc
- prctl(PR_SET_NAME, "SamplerThread", 0, 0, 0);
-
- int vm_tgid_ = getpid();
- DebugOnly<int> my_tid = gettid();
-
- unsigned int nSignalsSent = 0;
-
- TimeDuration lastSleepOverhead = 0;
- TimeStamp sampleStart = TimeStamp::Now();
- while (SamplerRegistry::sampler->IsActive()) {
-
- SamplerRegistry::sampler->HandleSaveRequest();
- SamplerRegistry::sampler->DeleteExpiredMarkers();
-
- if (!SamplerRegistry::sampler->IsPaused()) {
- ::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
- std::vector<ThreadInfo*> threads =
- SamplerRegistry::sampler->GetRegisteredThreads();
-
- bool isFirstProfiledThread = true;
- for (uint32_t i = 0; i < threads.size(); i++) {
- ThreadInfo* info = threads[i];
-
- // This will be null if we're not interested in profiling this thread.
- if (!info->Profile() || info->IsPendingDelete())
- continue;
-
- PseudoStack::SleepState sleeping = info->Stack()->observeSleeping();
- if (sleeping == PseudoStack::SLEEPING_AGAIN) {
- info->Profile()->DuplicateLastSample();
- continue;
- }
-
- info->Profile()->GetThreadResponsiveness()->Update();
-
- // We use sCurrentThreadProfile the ThreadProfile for the
- // thread we're profiling to the signal handler
- sCurrentThreadProfile = info->Profile();
-
- int threadId = info->ThreadId();
- MOZ_ASSERT(threadId != my_tid);
-
- // Profile from the signal sender for information which is not signal
- // safe, and will have low variation between the emission of the signal
- // and the signal handler catch.
- ProfilerSignalThread(sCurrentThreadProfile, isFirstProfiledThread);
-
- // Profile from the signal handler for information which is signal safe
- // and needs to be precise too, such as the stack of the interrupted
- // thread.
- if (tgkill(vm_tgid_, threadId, SIGPROF) != 0) {
- printf_stderr("profiler failed to signal tid=%d\n", threadId);
-#ifdef DEBUG
- abort();
-#else
- continue;
-#endif
- }
-
- // Wait for the signal handler to run before moving on to the next one
- sem_wait(&sSignalHandlingDone);
- isFirstProfiledThread = false;
-
- // The LUL unwind object accumulates frame statistics.
- // Periodically we should poke it to give it a chance to print
- // those statistics. This involves doing I/O (fprintf,
- // __android_log_print, etc) and so can't safely be done from
- // the unwinder threads, which is why it is done here.
- if ((++nSignalsSent & 0xF) == 0) {
-# if defined(USE_LUL_STACKWALK)
- sLUL->MaybeShowStats();
-# endif
- }
- }
- }
-
- TimeStamp targetSleepEndTime = sampleStart + TimeDuration::FromMicroseconds(SamplerRegistry::sampler->interval() * 1000);
- TimeStamp beforeSleep = TimeStamp::Now();
- TimeDuration targetSleepDuration = targetSleepEndTime - beforeSleep;
- double sleepTime = std::max(0.0, (targetSleepDuration - lastSleepOverhead).ToMicroseconds());
- OS::SleepMicro(sleepTime);
- sampleStart = TimeStamp::Now();
- lastSleepOverhead = sampleStart - (beforeSleep + TimeDuration::FromMicroseconds(sleepTime));
- }
- return 0;
-}
-
-Sampler::Sampler(double interval, bool profiling, int entrySize)
- : interval_(interval),
- profiling_(profiling),
- paused_(false),
- active_(false),
- entrySize_(entrySize) {
- MOZ_COUNT_CTOR(Sampler);
-}
-
-Sampler::~Sampler() {
- MOZ_COUNT_DTOR(Sampler);
- ASSERT(!signal_sender_launched_);
-}
-
-
-void Sampler::Start() {
- LOG("Sampler started");
-
-#if defined(USE_EHABI_STACKWALK)
- mozilla::EHABIStackWalkInit();
-#elif defined(USE_LUL_STACKWALK)
- // NOTE: this isn't thread-safe. But we expect Sampler::Start to be
- // called only from the main thread, so this is OK in general.
- if (!sLUL) {
- sLUL_initialization_routine();
- }
-#endif
-
- SamplerRegistry::AddActiveSampler(this);
-
- // Initialize signal handler communication
- sCurrentThreadProfile = NULL;
- if (sem_init(&sSignalHandlingDone, /* pshared: */ 0, /* value: */ 0) != 0) {
- LOG("Error initializing semaphore");
- return;
- }
-
- // Request profiling signals.
- LOG("Request signal");
- struct sigaction sa;
- sa.sa_sigaction = MOZ_SIGNAL_TRAMPOLINE(ProfilerSignalHandler);
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- if (sigaction(SIGPROF, &sa, &old_sigprof_signal_handler_) != 0) {
- LOG("Error installing signal");
- return;
- }
-
- // Request save profile signals
- struct sigaction sa2;
- sa2.sa_sigaction = ProfilerSaveSignalHandler;
- sigemptyset(&sa2.sa_mask);
- sa2.sa_flags = SA_RESTART | SA_SIGINFO;
- if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &old_sigsave_signal_handler_) != 0) {
- LOG("Error installing start signal");
- return;
- }
- LOG("Signal installed");
- signal_handler_installed_ = true;
-
-#if defined(USE_LUL_STACKWALK)
- // Switch into unwind mode. After this point, we can't add or
- // remove any unwind info to/from this LUL instance. The only thing
- // we can do with it is Unwind() calls.
- sLUL->EnableUnwinding();
-
- // Has a test been requested?
- if (PR_GetEnv("MOZ_PROFILER_LUL_TEST")) {
- int nTests = 0, nTestsPassed = 0;
- RunLulUnitTests(&nTests, &nTestsPassed, sLUL);
- }
-#endif
-
- // Start a thread that sends SIGPROF signal to VM thread.
- // Sending the signal ourselves instead of relying on itimer provides
- // much better accuracy.
- SetActive(true);
- if (pthread_create(
- &signal_sender_thread_, NULL, SignalSender, NULL) == 0) {
- signal_sender_launched_ = true;
- }
- LOG("Profiler thread started");
-}
-
-
-void Sampler::Stop() {
- SetActive(false);
-
- // Wait for signal sender termination (it will exit after setting
- // active_ to false).
- if (signal_sender_launched_) {
- pthread_join(signal_sender_thread_, NULL);
- signal_sender_launched_ = false;
- }
-
- SamplerRegistry::RemoveActiveSampler(this);
-
- // Restore old signal handler
- if (signal_handler_installed_) {
- sigaction(SIGNAL_SAVE_PROFILE, &old_sigsave_signal_handler_, 0);
- sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);
- signal_handler_installed_ = false;
- }
-}
-
-bool Sampler::RegisterCurrentThread(const char* aName,
- PseudoStack* aPseudoStack,
- bool aIsMainThread, void* stackTop)
-{
- if (!Sampler::sRegisteredThreadsMutex)
- return false;
-
- ::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
- int id = gettid();
- for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
- ThreadInfo* info = sRegisteredThreads->at(i);
- if (info->ThreadId() == id && !info->IsPendingDelete()) {
- // Thread already registered. This means the first unregister will be
- // too early.
- ASSERT(false);
- return false;
- }
- }
-
- set_tls_stack_top(stackTop);
-
- ThreadInfo* info = new StackOwningThreadInfo(aName, id,
- aIsMainThread, aPseudoStack, stackTop);
-
- if (sActiveSampler) {
- sActiveSampler->RegisterThread(info);
- }
-
- sRegisteredThreads->push_back(info);
-
- return true;
-}
-
-void Sampler::UnregisterCurrentThread()
-{
- if (!Sampler::sRegisteredThreadsMutex)
- return;
-
- tlsStackTop.set(nullptr);
-
- ::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
-
- int id = gettid();
-
- for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
- ThreadInfo* info = sRegisteredThreads->at(i);
- if (info->ThreadId() == id && !info->IsPendingDelete()) {
- if (profiler_is_active()) {
- // We still want to show the results of this thread if you
- // save the profile shortly after a thread is terminated.
- // For now we will defer the delete to profile stop.
- info->SetPendingDelete();
- break;
- } else {
- delete info;
- sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
- break;
- }
- }
- }
-}
-
-#ifdef ANDROID
-static struct sigaction old_sigstart_signal_handler;
-const int SIGSTART = SIGUSR2;
-
-static void freeArray(const char** array, int size) {
- for (int i = 0; i < size; i++) {
- free((void*) array[i]);
- }
-}
-
-static uint32_t readCSVArray(char* csvList, const char** buffer) {
- uint32_t count;
- char* savePtr;
- int newlinePos = strlen(csvList) - 1;
- if (csvList[newlinePos] == '\n') {
- csvList[newlinePos] = '\0';
- }
-
- char* item = strtok_r(csvList, ",", &savePtr);
- for (count = 0; item; item = strtok_r(NULL, ",", &savePtr)) {
- int length = strlen(item) + 1; // Include \0
- char* newBuf = (char*) malloc(sizeof(char) * length);
- buffer[count] = newBuf;
- strncpy(newBuf, item, length);
- count++;
- }
-
- return count;
-}
-
-// Currently support only the env variables
-// reported in read_profiler_env
-static void ReadProfilerVars(const char* fileName, const char** features,
- uint32_t* featureCount, const char** threadNames, uint32_t* threadCount) {
- FILE* file = fopen(fileName, "r");
- const int bufferSize = 1024;
- char line[bufferSize];
- char* feature;
- char* value;
- char* savePtr;
-
- if (file) {
- while (fgets(line, bufferSize, file) != NULL) {
- feature = strtok_r(line, "=", &savePtr);
- value = strtok_r(NULL, "", &savePtr);
-
- if (strncmp(feature, PROFILER_INTERVAL, bufferSize) == 0) {
- set_profiler_interval(value);
- } else if (strncmp(feature, PROFILER_ENTRIES, bufferSize) == 0) {
- set_profiler_entries(value);
- } else if (strncmp(feature, PROFILER_STACK, bufferSize) == 0) {
- set_profiler_scan(value);
- } else if (strncmp(feature, PROFILER_FEATURES, bufferSize) == 0) {
- *featureCount = readCSVArray(value, features);
- } else if (strncmp(feature, "threads", bufferSize) == 0) {
- *threadCount = readCSVArray(value, threadNames);
- }
- }
-
- fclose(file);
- }
-}
-
-static void DoStartTask() {
- uint32_t featureCount = 0;
- uint32_t threadCount = 0;
-
- // Just allocate 10 features for now
- // FIXME: these don't really point to const chars*
- // So we free them later, but we don't want to change the const char**
- // declaration in profiler_start. Annoying but ok for now.
- const char* threadNames[10];
- const char* features[10];
- const char* profilerConfigFile = "/data/local/tmp/profiler.options";
-
- ReadProfilerVars(profilerConfigFile, features, &featureCount, threadNames, &threadCount);
- MOZ_ASSERT(featureCount < 10);
- MOZ_ASSERT(threadCount < 10);
-
- profiler_start(PROFILE_DEFAULT_ENTRY, 1,
- features, featureCount,
- threadNames, threadCount);
-
- freeArray(threadNames, threadCount);
- freeArray(features, featureCount);
-}
-
-static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
- class StartTask : public Runnable {
- public:
- NS_IMETHOD Run() override {
- DoStartTask();
- return NS_OK;
- }
- };
- // XXX: technically NS_DispatchToMainThread is NOT async signal safe. We risk
- // nasty things like deadlocks, but the probability is very low and we
- // typically only do this once so it tends to be ok. See bug 909403.
- NS_DispatchToMainThread(new StartTask());
-}
-
-void OS::Startup()
-{
- LOG("Registering start signal");
- struct sigaction sa;
- sa.sa_sigaction = StartSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- if (sigaction(SIGSTART, &sa, &old_sigstart_signal_handler) != 0) {
- LOG("Error installing signal");
- }
-}
-
-#else
-
-void OS::Startup() {
- // Set up the fork handlers.
- setup_atfork();
-}
-
-#endif
-
-
-
-void TickSample::PopulateContext(void* aContext)
-{
- MOZ_ASSERT(aContext);
- ucontext_t* pContext = reinterpret_cast<ucontext_t*>(aContext);
- if (!getcontext(pContext)) {
- context = pContext;
- SetSampleContext(this, aContext);
- }
-}
-
-void OS::SleepMicro(int microseconds)
-{
- if (MOZ_UNLIKELY(microseconds >= 1000000)) {
- // Use usleep for larger intervals, because the nanosleep
- // code below only supports intervals < 1 second.
- MOZ_ALWAYS_TRUE(!::usleep(microseconds));
- return;
- }
-
- struct timespec ts;
- ts.tv_sec = 0;
- ts.tv_nsec = microseconds * 1000UL;
-
- int rv = ::nanosleep(&ts, &ts);
-
- while (rv != 0 && errno == EINTR) {
- // Keep waiting in case of interrupt.
- // nanosleep puts the remaining time back into ts.
- rv = ::nanosleep(&ts, &ts);
- }
-
- MOZ_ASSERT(!rv, "nanosleep call failed");
-}