Index: third_party/tcmalloc/chromium/src/profile-handler.cc |
diff --git a/third_party/tcmalloc/chromium/src/profile-handler.cc b/third_party/tcmalloc/chromium/src/profile-handler.cc |
index 1946f7c5819cde4b7e196cbe304e96e22d1be1cc..20e5cca90cfcba984248c93968bf83e9e2d26527 100644 |
--- a/third_party/tcmalloc/chromium/src/profile-handler.cc |
+++ b/third_party/tcmalloc/chromium/src/profile-handler.cc |
@@ -46,6 +46,7 @@ |
#include <string> |
#include "base/dynamic_annotations.h" |
+#include "base/googleinit.h" |
#include "base/logging.h" |
#include "base/spinlock.h" |
#include "maybe_threads.h" |
@@ -139,6 +140,9 @@ class ProfileHandler { |
// Counts the number of callbacks registered. |
int32 callback_count_ GUARDED_BY(control_lock_); |
+ // Is profiling allowed at all? |
+ bool allowed_; |
+ |
// Whether or not the threading system provides interval timers that are |
// shared by all threads in a process. |
enum { |
@@ -199,6 +203,10 @@ class ProfileHandler { |
// Disables (ignores) the timer interrupt signal. |
void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
+ // Returns true if the handler is not being used by something else. |
+ // This checks the kernel's signal handler table. |
+ bool IsSignalHandlerAvailable(); |
+ |
// SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks. |
static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); |
@@ -239,6 +247,7 @@ ProfileHandler* ProfileHandler::Instance() { |
ProfileHandler::ProfileHandler() |
: interrupts_(0), |
callback_count_(0), |
+ allowed_(true), |
timer_sharing_(TIMERS_UNTOUCHED) { |
SpinLockHolder cl(&control_lock_); |
@@ -255,6 +264,19 @@ ProfileHandler::ProfileHandler() |
frequency_ = kDefaultFrequency; |
} |
+ if (!allowed_) { |
+ return; |
+ } |
+ |
+ // If something else is using the signal handler, |
+ // assume it has priority over us and stop. |
+ if (!IsSignalHandlerAvailable()) { |
+ RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", |
+ timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); |
+ allowed_ = false; |
+ return; |
+ } |
+ |
// Ignore signals until we decide to turn profiling on. (Paranoia; |
// should already be ignored.) |
DisableHandler(); |
@@ -267,6 +289,10 @@ ProfileHandler::~ProfileHandler() { |
void ProfileHandler::RegisterThread() { |
SpinLockHolder cl(&control_lock_); |
+ if (!allowed_) { |
+ return; |
+ } |
+ |
// We try to detect whether timers are being shared by setting a |
// timer in the first call to this function, then checking whether |
// it's set in the second call. |
@@ -312,6 +338,7 @@ void ProfileHandler::RegisterThread() { |
ProfileHandlerToken* ProfileHandler::RegisterCallback( |
ProfileHandlerCallback callback, void* callback_arg) { |
+ |
ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); |
SpinLockHolder cl(&control_lock_); |
@@ -386,9 +413,13 @@ void ProfileHandler::GetState(ProfileHandlerState* state) { |
} |
state->frequency = frequency_; |
state->callback_count = callback_count_; |
+ state->allowed = allowed_; |
} |
void ProfileHandler::StartTimer() { |
+ if (!allowed_) { |
+ return; |
+ } |
struct itimerval timer; |
timer.it_interval.tv_sec = 0; |
timer.it_interval.tv_usec = 1000000 / frequency_; |
@@ -397,12 +428,18 @@ void ProfileHandler::StartTimer() { |
} |
void ProfileHandler::StopTimer() { |
+ if (!allowed_) { |
+ return; |
+ } |
struct itimerval timer; |
memset(&timer, 0, sizeof timer); |
setitimer(timer_type_, &timer, 0); |
} |
bool ProfileHandler::IsTimerRunning() { |
+ if (!allowed_) { |
+ return false; |
+ } |
struct itimerval current_timer; |
RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); |
return (current_timer.it_value.tv_sec != 0 || |
@@ -410,6 +447,9 @@ bool ProfileHandler::IsTimerRunning() { |
} |
void ProfileHandler::EnableHandler() { |
+ if (!allowed_) { |
+ return; |
+ } |
struct sigaction sa; |
sa.sa_sigaction = SignalHandler; |
sa.sa_flags = SA_RESTART | SA_SIGINFO; |
@@ -419,6 +459,9 @@ void ProfileHandler::EnableHandler() { |
} |
void ProfileHandler::DisableHandler() { |
+ if (!allowed_) { |
+ return; |
+ } |
struct sigaction sa; |
sa.sa_handler = SIG_IGN; |
sa.sa_flags = SA_RESTART; |
@@ -427,14 +470,33 @@ void ProfileHandler::DisableHandler() { |
RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); |
} |
+bool ProfileHandler::IsSignalHandlerAvailable() { |
+ struct sigaction sa; |
+ const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
+ RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail"); |
+ |
+ // We only take over the handler if the current one is unset. |
+ // It must be SIG_IGN or SIG_DFL, not some other function. |
+ // SIG_IGN must be allowed because when profiling is allowed but |
+ // not actively in use, this code keeps the handler set to SIG_IGN. |
+ // That setting will be inherited across fork+exec. In order for |
+ // any child to be able to use profiling, SIG_IGN must be treated |
+ // as available. |
+ return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; |
+} |
+ |
void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
int saved_errno = errno; |
- RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); |
+ // At this moment, instance_ must be initialized because the handler is |
+ // enabled in RegisterThread or RegisterCallback only after |
+ // ProfileHandler::Instance runs. |
+ ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); |
+ RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); |
{ |
- SpinLockHolder sl(&instance_->signal_lock_); |
- ++instance_->interrupts_; |
- for (CallbackIterator it = instance_->callbacks_.begin(); |
- it != instance_->callbacks_.end(); |
+ SpinLockHolder sl(&instance->signal_lock_); |
+ ++instance->interrupts_; |
+ for (CallbackIterator it = instance->callbacks_.begin(); |
+ it != instance->callbacks_.end(); |
++it) { |
(*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); |
} |
@@ -442,20 +504,9 @@ void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
errno = saved_errno; |
} |
-// The sole purpose of this class is to initialize the ProfileHandler singleton |
-// when the global static objects are created. Note that the main thread will |
-// be registered at this time. |
-class ProfileHandlerInitializer { |
- public: |
- ProfileHandlerInitializer() { |
- ProfileHandler::Instance()->RegisterThread(); |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(ProfileHandlerInitializer); |
-}; |
-// ProfileHandlerInitializer singleton |
-static ProfileHandlerInitializer profile_handler_initializer; |
+// This module initializer registers the main thread, so it must be |
+// executed in the context of the main thread. |
+REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); |
extern "C" void ProfileHandlerRegisterThread() { |
ProfileHandler::Instance()->RegisterThread(); |