diff options
author | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 17:11:15 +0000 |
---|---|---|
committer | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 17:11:15 +0000 |
commit | 9483034e46cf077d5c192e9c074a424e94afa179 (patch) | |
tree | b30f76c221fb66d199418e8f5355397691bf2825 /third_party | |
parent | 5e83e609de9acac8186bf24641367467cc55d0aa (diff) | |
download | chromium_src-9483034e46cf077d5c192e9c074a424e94afa179.zip chromium_src-9483034e46cf077d5c192e9c074a424e94afa179.tar.gz chromium_src-9483034e46cf077d5c192e9c074a424e94afa179.tar.bz2 |
Partially revert r173151 - Switch prefs::kExtensionInstallForceList to be a dictionary.
It accidentally included local tcmalloc changes not part of the CL.
BUG=None
TEST=Everything builds and passes tests.
TBR=mnissler@chromium.org
Review URL: https://codereview.chromium.org/11614031
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173746 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
6 files changed, 171 insertions, 157 deletions
diff --git a/third_party/tcmalloc/chromium/src/gperftools/profiler.h b/third_party/tcmalloc/chromium/src/gperftools/profiler.h index 72a74ba..07323e4 100644 --- a/third_party/tcmalloc/chromium/src/gperftools/profiler.h +++ b/third_party/tcmalloc/chromium/src/gperftools/profiler.h @@ -150,10 +150,6 @@ PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads(); */ PERFTOOLS_DLL_DECL void ProfilerRegisterThread(); -/* Routine for unregistering new threads with the profiler. - */ -PERFTOOLS_DLL_DECL void ProfilerUnregisterThread(); - /* Stores state about profiler's current status into "*state". */ struct ProfilerState { int enabled; /* Is profiling currently enabled? */ diff --git a/third_party/tcmalloc/chromium/src/profile-handler.cc b/third_party/tcmalloc/chromium/src/profile-handler.cc index 1abc922..20e5cca 100644 --- a/third_party/tcmalloc/chromium/src/profile-handler.cc +++ b/third_party/tcmalloc/chromium/src/profile-handler.cc @@ -38,12 +38,11 @@ #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) -#include <errno.h> #include <stdio.h> +#include <errno.h> #include <sys/time.h> #include <list> -#include <map> #include <string> #include "base/dynamic_annotations.h" @@ -53,7 +52,6 @@ #include "maybe_threads.h" using std::list; -using std::map; using std::string; // This structure is used by ProfileHandlerRegisterCallback and @@ -71,47 +69,39 @@ struct ProfileHandlerToken { void* callback_arg; }; -// Blocks a signal from being delivered to the current thread while the object -// is alive. Restores previous state upon destruction. -class ScopedSignalBlocker { - public: - ScopedSignalBlocker(int signo) { - sigemptyset(&sig_set_); - sigaddset(&sig_set_, signo); - RAW_CHECK(sigprocmask(SIG_BLOCK, &sig_set_, NULL) == 0, - "sigprocmask (block)"); - } - ~ScopedSignalBlocker() { - RAW_CHECK(sigprocmask(SIG_UNBLOCK, &sig_set_, NULL) == 0, - "sigprocmask (unblock)"); - } - - private: - sigset_t sig_set_; -}; - // This class manages profile timers and associated signal handler. This is a // a singleton. class ProfileHandler { public: - // Registers the current thread with the profile handler. + // Registers the current thread with the profile handler. On systems which + // have a separate interval timer for each thread, this function starts the + // timer for the current thread. + // + // The function also attempts to determine whether or not timers are shared by + // all threads in the process. (With LinuxThreads, and with NPTL on some + // Linux kernel versions, each thread has separate timers.) + // + // Prior to determining whether timers are shared, this function will + // unconditionally start the timer. However, if this function determines + // that timers are shared, then it will stop the timer if no callbacks are + // currently registered. void RegisterThread(); - // Unregisters the current thread with the profile handler. - void UnregisterThread(); - // Registers a callback routine to receive profile timer ticks. The returned // token is to be used when unregistering this callback and must not be - // deleted by the caller. + // deleted by the caller. Registration of the first callback enables the + // SIGPROF handler (or SIGALRM if using ITIMER_REAL). ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, void* callback_arg); // Unregisters a previously registered callback. Expects the token returned - // by the corresponding RegisterCallback routine. + // by the corresponding RegisterCallback routine. Unregistering the last + // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL). void UnregisterCallback(ProfileHandlerToken* token) NO_THREAD_SAFETY_ANALYSIS; - // Unregisters all the callbacks and stops the timer(s). + // Unregisters all the callbacks, stops the timer if shared, disables the + // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state. void Reset(); // Gets the current state of profile handler. @@ -135,12 +125,6 @@ class ProfileHandler { // pthread_once_t for one time initialization of ProfileHandler singleton. static pthread_once_t once_; -#if defined(HAVE_TLS) - // Timer state as configured previously. This bit is kept in - // |registered_threads_| if TLS is not available. - static __thread bool timer_running_; -#endif - // Initializes the ProfileHandler singleton via GoogleOnceInit. static void Init(); @@ -159,6 +143,19 @@ class ProfileHandler { // 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 { + // No timer initialization attempted yet. + TIMERS_UNTOUCHED, + // First thread has registered and set timer. + TIMERS_ONE_SET, + // Timers are shared by all threads. + TIMERS_SHARED, + // Timers are separate in each thread. + TIMERS_SEPARATE + } timer_sharing_ GUARDED_BY(control_lock_); + // This lock serializes the registration of threads and protects the // callbacks_ list below. // Locking order: @@ -168,13 +165,6 @@ class ProfileHandler { SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); SpinLock signal_lock_; - // Set of threads registered through RegisterThread. This is consulted - // whenever timers are switched on or off to post a signal to these threads - // so they can arm their timers. Locking rules as for |callbacks_| below. If - // TLS is not available, this map is also used to keep the thread's timer - // state. - map<pthread_t, bool> registered_threads_ GUARDED_BY(signal_lock_); - // Holds the list of registered callbacks. We expect the list to be pretty // small. Currently, the cpu profiler (base/profiler) and thread module // (base/thread.h) are the only two components registering callbacks. @@ -192,18 +182,26 @@ class ProfileHandler { typedef CallbackList::iterator CallbackIterator; CallbackList callbacks_ GUARDED_BY(signal_lock_); - // Returns the signal to be used with |timer_type_| (SIGPROF or SIGALARM). - int signal_number() { - return (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); - } + // Starts the interval timer. If the thread library shares timers between + // threads, this function starts the shared timer. Otherwise, this will start + // the timer in the current thread. + void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); + + // Stops the interval timer. If the thread library shares timers between + // threads, this fucntion stops the shared timer. Otherwise, this will stop + // the timer in the current thread. + void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); - // Starts or stops the interval timer(s). In case of non-shared timers, this - // will post a signal to all registered threads, causing them to arm their - // timers. - void UpdateTimers(bool enable) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_); + // Returns true if the profile interval timer is enabled in the current + // thread. This actually checks the kernel's interval timer setting. (It is + // used to detect whether timers are shared or separate.) + bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); - // Configures the timer. If |frequency| is 0, the timer will be disabled. - void SetupTimer(int32 frequency) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_); + // Sets the timer interrupt signal handler. + void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); + + // 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. @@ -218,21 +216,15 @@ class ProfileHandler { ProfileHandler* ProfileHandler::instance_ = NULL; pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; -#if defined(HAVE_TLS) -bool __thread ProfileHandler::timer_running_ = false; -#endif - const int32 ProfileHandler::kMaxFrequency; const int32 ProfileHandler::kDefaultFrequency; -// If we are LD_PRELOAD-ed against a non-pthreads app, then pthread_* functions -// won't be defined. We declare them here, for that case (with weak linkage) -// which will cause the non-definition to resolve to NULL. We can then check -// for NULL or not in Instance. +// If we are LD_PRELOAD-ed against a non-pthreads app, then +// pthread_once won't be defined. We declare it here, for that +// case (with weak linkage) which will cause the non-definition to +// resolve to NULL. We can then check for NULL or not in Instance. extern "C" int pthread_once(pthread_once_t *, void (*)(void)) ATTRIBUTE_WEAK; -extern "C" int pthread_kill(pthread_t thread_id, int signo) - ATTRIBUTE_WEAK; void ProfileHandler::Init() { instance_ = new ProfileHandler(); @@ -255,7 +247,8 @@ ProfileHandler* ProfileHandler::Instance() { ProfileHandler::ProfileHandler() : interrupts_(0), callback_count_(0), - allowed_(true) { + allowed_(true), + timer_sharing_(TIMERS_UNTOUCHED) { SpinLockHolder cl(&control_lock_); timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); @@ -279,17 +272,14 @@ ProfileHandler::ProfileHandler() // assume it has priority over us and stop. if (!IsSignalHandlerAvailable()) { RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", - signal_number()); + timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); allowed_ = false; return; } - // Install the signal handler. - struct sigaction sa; - sa.sa_sigaction = SignalHandler; - sa.sa_flags = SA_RESTART | SA_SIGINFO; - sigemptyset(&sa.sa_mask); - RAW_CHECK(sigaction(signal_number(), &sa, NULL) == 0, "sigprof (enable)"); + // Ignore signals until we decide to turn profiling on. (Paranoia; + // should already be ignored.) + DisableHandler(); } ProfileHandler::~ProfileHandler() { @@ -303,17 +293,47 @@ void ProfileHandler::RegisterThread() { return; } - // Record the thread identifier and start the timer if profiling is on. - ScopedSignalBlocker block(signal_number()); - SpinLockHolder sl(&signal_lock_); - registered_threads_[pthread_self()] = false; - SetupTimer(callback_count_ > 0 ? frequency_ : 0); -} - -void ProfileHandler::UnregisterThread() { - ScopedSignalBlocker block(signal_number()); - SpinLockHolder sl(&signal_lock_); - registered_threads_.erase(pthread_self()); + // 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. + // + // Note that this detection method requires that the first two calls + // to RegisterThread must be made from different threads. (Subsequent + // calls will see timer_sharing_ set to either TIMERS_SEPARATE or + // TIMERS_SHARED, and won't try to detect the timer sharing type.) + // + // Also note that if timer settings were inherited across new thread + // creation but *not* shared, this approach wouldn't work. That's + // not an issue for any Linux threading implementation, and should + // not be a problem for a POSIX-compliant threads implementation. + switch (timer_sharing_) { + case TIMERS_UNTOUCHED: + StartTimer(); + timer_sharing_ = TIMERS_ONE_SET; + break; + case TIMERS_ONE_SET: + // If the timer is running, that means that the main thread's + // timer setup is seen in this (second) thread -- and therefore + // that timers are shared. + if (IsTimerRunning()) { + timer_sharing_ = TIMERS_SHARED; + // If callback is already registered, we have to keep the timer + // running. If not, we disable the timer here. + if (callback_count_ == 0) { + StopTimer(); + } + } else { + timer_sharing_ = TIMERS_SEPARATE; + StartTimer(); + } + break; + case TIMERS_SHARED: + // Nothing needed. + break; + case TIMERS_SEPARATE: + StartTimer(); + break; + } } ProfileHandlerToken* ProfileHandler::RegisterCallback( @@ -322,13 +342,17 @@ ProfileHandlerToken* ProfileHandler::RegisterCallback( ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); SpinLockHolder cl(&control_lock_); + DisableHandler(); { - ScopedSignalBlocker block(signal_number()); SpinLockHolder sl(&signal_lock_); callbacks_.push_back(token); - ++callback_count_; - UpdateTimers(true); } + // Start the timer if timer is shared and this is a first callback. + if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { + StartTimer(); + } + ++callback_count_; + EnableHandler(); return token; } @@ -338,14 +362,17 @@ void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { ++it) { if ((*it) == token) { RAW_CHECK(callback_count_ > 0, "Invalid callback count"); + DisableHandler(); { - ScopedSignalBlocker block(signal_number()); SpinLockHolder sl(&signal_lock_); delete *it; callbacks_.erase(it); - --callback_count_; - if (callback_count_ == 0) - UpdateTimers(false); + } + --callback_count_; + if (callback_count_ > 0) { + EnableHandler(); + } else if (timer_sharing_ == TIMERS_SHARED) { + StopTimer(); } return; } @@ -356,8 +383,8 @@ void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { void ProfileHandler::Reset() { SpinLockHolder cl(&control_lock_); + DisableHandler(); { - ScopedSignalBlocker block(signal_number()); SpinLockHolder sl(&signal_lock_); CallbackIterator it = callbacks_.begin(); while (it != callbacks_.end()) { @@ -366,66 +393,87 @@ void ProfileHandler::Reset() { delete *tmp; callbacks_.erase(tmp); } - callback_count_ = 0; - UpdateTimers(false); } + callback_count_ = 0; + if (timer_sharing_ == TIMERS_SHARED) { + StopTimer(); + } + timer_sharing_ = TIMERS_UNTOUCHED; } void ProfileHandler::GetState(ProfileHandlerState* state) { SpinLockHolder cl(&control_lock_); + DisableHandler(); { - ScopedSignalBlocker block(signal_number()); SpinLockHolder sl(&signal_lock_); // Protects interrupts_. state->interrupts = interrupts_; } + if (callback_count_ > 0) { + EnableHandler(); + } state->frequency = frequency_; state->callback_count = callback_count_; state->allowed = allowed_; } -void ProfileHandler::UpdateTimers(bool enabled) { +void ProfileHandler::StartTimer() { if (!allowed_) { return; } - SetupTimer(enabled ? frequency_ : 0); - - // Tell other threads to start their timers. - for (map<pthread_t, bool>::const_iterator thread(registered_threads_.begin()); - thread != registered_threads_.end(); - ++thread) { - if (thread->first != pthread_self() && pthread_kill) { - int err = pthread_kill(thread->first, signal_number()); - if (err == ESRCH) { - // Thread exited. - registered_threads_.erase(thread->first); - } else { - RAW_CHECK(err == 0, "pthread_kill"); - } - } - } + struct itimerval timer; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 1000000 / frequency_; + timer.it_value = timer.it_interval; + setitimer(timer_type_, &timer, 0); } -void ProfileHandler::SetupTimer(int32 frequency) { - bool enable = (frequency > 0); -#if defined(HAVE_TLS) - bool& timer_running = timer_running_; -#else - bool& timer_running = registered_threads_[pthread_self()]; -#endif - if (enable == timer_running) +void ProfileHandler::StopTimer() { + if (!allowed_) { return; + } struct itimerval timer; - timer.it_interval.tv_sec = 0; - timer.it_interval.tv_usec = (enable ? (1000000 / frequency) : 0); - timer.it_value = timer.it_interval; + memset(&timer, 0, sizeof timer); setitimer(timer_type_, &timer, 0); - timer_running = enable; +} + +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 || + current_timer.it_value.tv_usec != 0); +} + +void ProfileHandler::EnableHandler() { + if (!allowed_) { + return; + } + struct sigaction sa; + sa.sa_sigaction = SignalHandler; + sa.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&sa.sa_mask); + const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); + RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); +} + +void ProfileHandler::DisableHandler() { + if (!allowed_) { + return; + } + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); + RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); } bool ProfileHandler::IsSignalHandlerAvailable() { struct sigaction sa; - RAW_CHECK(sigaction(signal_number(), NULL, &sa) == 0, - "is-signal-handler avail"); + 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. @@ -447,9 +495,6 @@ void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { { SpinLockHolder sl(&instance->signal_lock_); ++instance->interrupts_; - // Enable/Disable the timer if necessary. - instance->SetupTimer( - instance->callbacks_.empty() ? 0 : instance->frequency_); for (CallbackIterator it = instance->callbacks_.begin(); it != instance->callbacks_.end(); ++it) { @@ -467,10 +512,6 @@ extern "C" void ProfileHandlerRegisterThread() { ProfileHandler::Instance()->RegisterThread(); } -extern "C" void ProfileHandlerUnregisterThread() { - ProfileHandler::Instance()->UnregisterThread(); -} - extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( ProfileHandlerCallback callback, void* callback_arg) { return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); @@ -497,9 +538,6 @@ extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { extern "C" void ProfileHandlerRegisterThread() { } -extern "C" void ProfileHandlerUnregisterThread() { -} - extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( ProfileHandlerCallback callback, void* callback_arg) { return NULL; diff --git a/third_party/tcmalloc/chromium/src/profile-handler.h b/third_party/tcmalloc/chromium/src/profile-handler.h index cc50dbb..4b078ec 100644 --- a/third_party/tcmalloc/chromium/src/profile-handler.h +++ b/third_party/tcmalloc/chromium/src/profile-handler.h @@ -102,18 +102,6 @@ typedef void (*ProfileHandlerCallback)(int sig, siginfo_t* sig_info, void ProfileHandlerRegisterThread(); /* - * Unregisters a thread before exiting. This is not strictly necessary in most - * cases, because the pthread library will detect that previously-valid thread - * identifiers have become invalid. For dead-thread detection to work, pthread - * identifiers are accessed even after the thread has been destroyed, which may - * fail in some edge cases (thread ID recycling) and even crash in exotic cases - * (for example, when using user-allocated stacks with NPTL and unmapping the - * memory after the thread terminates). Thus, it is generally good practice to - * call ProfileHandlerUnregisterThread() just before exiting the thread. - */ -void ProfileHandlerUnregisterThread(); - -/* * Registers a callback routine. This callback function will be called in the * context of SIGPROF handler, so must be async-signal-safe. The returned token * is to be used when unregistering this callback via diff --git a/third_party/tcmalloc/chromium/src/profiler.cc b/third_party/tcmalloc/chromium/src/profiler.cc index 65879f6..dfb6aab 100644 --- a/third_party/tcmalloc/chromium/src/profiler.cc +++ b/third_party/tcmalloc/chromium/src/profiler.cc @@ -290,10 +290,6 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() { ProfileHandlerRegisterThread(); } -extern "C" PERFTOOLS_DLL_DECL void ProfilerUnregisterThread() { - ProfileHandlerUnregisterThread(); -} - extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() { CpuProfiler::instance_.FlushTable(); } @@ -327,7 +323,6 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState( // these issues, unless a specific need is identified, profiler support is // disabled under Cygwin. extern "C" void ProfilerRegisterThread() { } -extern "C" void ProfilerUnregisterThread() { } extern "C" void ProfilerFlush() { } extern "C" int ProfilingIsEnabledForAllThreads() { return 0; } extern "C" int ProfilerStart(const char* fname) { return 0; } diff --git a/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc b/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc index e46ab83..98cfe6d 100644 --- a/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc +++ b/third_party/tcmalloc/chromium/src/tests/profile-handler_unittest.cc @@ -58,7 +58,6 @@ class Thread { static void* DoRun(void* cls) { ProfileHandlerRegisterThread(); reinterpret_cast<Thread*>(cls)->Run(); - ProfileHandlerUnregisterThread(); return NULL; } pthread_t thread_; diff --git a/third_party/tcmalloc/chromium/src/tests/profiler_unittest.cc b/third_party/tcmalloc/chromium/src/tests/profiler_unittest.cc index 2afe209..399891b 100644 --- a/third_party/tcmalloc/chromium/src/tests/profiler_unittest.cc +++ b/third_party/tcmalloc/chromium/src/tests/profiler_unittest.cc @@ -63,8 +63,6 @@ static void test_other_thread() { } snprintf(b, sizeof(b), "other: %d", result); // get some libc action } - - ProfilerUnregisterThread(); #endif } |