Ensure low-memory renderers retry failed loads correctly.
[chromium-blink-merge.git] / third_party / tcmalloc / vendor / src / profile-handler.cc
blob20e5cca90cfcba984248c93968bf83e9e2d26527
1 // Copyright (c) 2009, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 // ---
31 // Author: Sanjay Ghemawat
32 // Nabeel Mian
34 // Implements management of profile timers and the corresponding signal handler.
36 #include "config.h"
37 #include "profile-handler.h"
39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
41 #include <stdio.h>
42 #include <errno.h>
43 #include <sys/time.h>
45 #include <list>
46 #include <string>
48 #include "base/dynamic_annotations.h"
49 #include "base/googleinit.h"
50 #include "base/logging.h"
51 #include "base/spinlock.h"
52 #include "maybe_threads.h"
54 using std::list;
55 using std::string;
57 // This structure is used by ProfileHandlerRegisterCallback and
58 // ProfileHandlerUnregisterCallback as a handle to a registered callback.
59 struct ProfileHandlerToken {
60 // Sets the callback and associated arg.
61 ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg)
62 : callback(cb),
63 callback_arg(cb_arg) {
66 // Callback function to be invoked on receiving a profile timer interrupt.
67 ProfileHandlerCallback callback;
68 // Argument for the callback function.
69 void* callback_arg;
72 // This class manages profile timers and associated signal handler. This is a
73 // a singleton.
74 class ProfileHandler {
75 public:
76 // Registers the current thread with the profile handler. On systems which
77 // have a separate interval timer for each thread, this function starts the
78 // timer for the current thread.
80 // The function also attempts to determine whether or not timers are shared by
81 // all threads in the process. (With LinuxThreads, and with NPTL on some
82 // Linux kernel versions, each thread has separate timers.)
84 // Prior to determining whether timers are shared, this function will
85 // unconditionally start the timer. However, if this function determines
86 // that timers are shared, then it will stop the timer if no callbacks are
87 // currently registered.
88 void RegisterThread();
90 // Registers a callback routine to receive profile timer ticks. The returned
91 // token is to be used when unregistering this callback and must not be
92 // deleted by the caller. Registration of the first callback enables the
93 // SIGPROF handler (or SIGALRM if using ITIMER_REAL).
94 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
95 void* callback_arg);
97 // Unregisters a previously registered callback. Expects the token returned
98 // by the corresponding RegisterCallback routine. Unregistering the last
99 // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL).
100 void UnregisterCallback(ProfileHandlerToken* token)
101 NO_THREAD_SAFETY_ANALYSIS;
103 // Unregisters all the callbacks, stops the timer if shared, disables the
104 // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state.
105 void Reset();
107 // Gets the current state of profile handler.
108 void GetState(ProfileHandlerState* state);
110 // Initializes and returns the ProfileHandler singleton.
111 static ProfileHandler* Instance();
113 private:
114 ProfileHandler();
115 ~ProfileHandler();
117 // Largest allowed frequency.
118 static const int32 kMaxFrequency = 4000;
119 // Default frequency.
120 static const int32 kDefaultFrequency = 100;
122 // ProfileHandler singleton.
123 static ProfileHandler* instance_;
125 // pthread_once_t for one time initialization of ProfileHandler singleton.
126 static pthread_once_t once_;
128 // Initializes the ProfileHandler singleton via GoogleOnceInit.
129 static void Init();
131 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received.
132 int64 interrupts_ GUARDED_BY(signal_lock_);
134 // SIGPROF/SIGALRM interrupt frequency, read-only after construction.
135 int32 frequency_;
137 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM)
138 int timer_type_;
140 // Counts the number of callbacks registered.
141 int32 callback_count_ GUARDED_BY(control_lock_);
143 // Is profiling allowed at all?
144 bool allowed_;
146 // Whether or not the threading system provides interval timers that are
147 // shared by all threads in a process.
148 enum {
149 // No timer initialization attempted yet.
150 TIMERS_UNTOUCHED,
151 // First thread has registered and set timer.
152 TIMERS_ONE_SET,
153 // Timers are shared by all threads.
154 TIMERS_SHARED,
155 // Timers are separate in each thread.
156 TIMERS_SEPARATE
157 } timer_sharing_ GUARDED_BY(control_lock_);
159 // This lock serializes the registration of threads and protects the
160 // callbacks_ list below.
161 // Locking order:
162 // In the context of a signal handler, acquire signal_lock_ to walk the
163 // callback list. Otherwise, acquire control_lock_, disable the signal
164 // handler and then acquire signal_lock_.
165 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
166 SpinLock signal_lock_;
168 // Holds the list of registered callbacks. We expect the list to be pretty
169 // small. Currently, the cpu profiler (base/profiler) and thread module
170 // (base/thread.h) are the only two components registering callbacks.
171 // Following are the locking requirements for callbacks_:
172 // For read-write access outside the SIGPROF handler:
173 // - Acquire control_lock_
174 // - Disable SIGPROF handler.
175 // - Acquire signal_lock_
176 // For read-only access in the context of SIGPROF handler
177 // (Read-write access is *not allowed* in the SIGPROF handler)
178 // - Acquire signal_lock_
179 // For read-only access outside SIGPROF handler:
180 // - Acquire control_lock_
181 typedef list<ProfileHandlerToken*> CallbackList;
182 typedef CallbackList::iterator CallbackIterator;
183 CallbackList callbacks_ GUARDED_BY(signal_lock_);
185 // Starts the interval timer. If the thread library shares timers between
186 // threads, this function starts the shared timer. Otherwise, this will start
187 // the timer in the current thread.
188 void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
190 // Stops the interval timer. If the thread library shares timers between
191 // threads, this fucntion stops the shared timer. Otherwise, this will stop
192 // the timer in the current thread.
193 void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
195 // Returns true if the profile interval timer is enabled in the current
196 // thread. This actually checks the kernel's interval timer setting. (It is
197 // used to detect whether timers are shared or separate.)
198 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
200 // Sets the timer interrupt signal handler.
201 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
203 // Disables (ignores) the timer interrupt signal.
204 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
206 // Returns true if the handler is not being used by something else.
207 // This checks the kernel's signal handler table.
208 bool IsSignalHandlerAvailable();
210 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks.
211 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);
213 DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
216 ProfileHandler* ProfileHandler::instance_ = NULL;
217 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT;
219 const int32 ProfileHandler::kMaxFrequency;
220 const int32 ProfileHandler::kDefaultFrequency;
222 // If we are LD_PRELOAD-ed against a non-pthreads app, then
223 // pthread_once won't be defined. We declare it here, for that
224 // case (with weak linkage) which will cause the non-definition to
225 // resolve to NULL. We can then check for NULL or not in Instance.
226 extern "C" int pthread_once(pthread_once_t *, void (*)(void))
227 ATTRIBUTE_WEAK;
229 void ProfileHandler::Init() {
230 instance_ = new ProfileHandler();
233 ProfileHandler* ProfileHandler::Instance() {
234 if (pthread_once) {
235 pthread_once(&once_, Init);
237 if (instance_ == NULL) {
238 // This will be true on systems that don't link in pthreads,
239 // including on FreeBSD where pthread_once has a non-zero address
240 // (but doesn't do anything) even when pthreads isn't linked in.
241 Init();
242 assert(instance_ != NULL);
244 return instance_;
247 ProfileHandler::ProfileHandler()
248 : interrupts_(0),
249 callback_count_(0),
250 allowed_(true),
251 timer_sharing_(TIMERS_UNTOUCHED) {
252 SpinLockHolder cl(&control_lock_);
254 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
256 // Get frequency of interrupts (if specified)
257 char junk;
258 const char* fr = getenv("CPUPROFILE_FREQUENCY");
259 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
260 (frequency_ > 0)) {
261 // Limit to kMaxFrequency
262 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
263 } else {
264 frequency_ = kDefaultFrequency;
267 if (!allowed_) {
268 return;
271 // If something else is using the signal handler,
272 // assume it has priority over us and stop.
273 if (!IsSignalHandlerAvailable()) {
274 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.",
275 timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF");
276 allowed_ = false;
277 return;
280 // Ignore signals until we decide to turn profiling on. (Paranoia;
281 // should already be ignored.)
282 DisableHandler();
285 ProfileHandler::~ProfileHandler() {
286 Reset();
289 void ProfileHandler::RegisterThread() {
290 SpinLockHolder cl(&control_lock_);
292 if (!allowed_) {
293 return;
296 // We try to detect whether timers are being shared by setting a
297 // timer in the first call to this function, then checking whether
298 // it's set in the second call.
300 // Note that this detection method requires that the first two calls
301 // to RegisterThread must be made from different threads. (Subsequent
302 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or
303 // TIMERS_SHARED, and won't try to detect the timer sharing type.)
305 // Also note that if timer settings were inherited across new thread
306 // creation but *not* shared, this approach wouldn't work. That's
307 // not an issue for any Linux threading implementation, and should
308 // not be a problem for a POSIX-compliant threads implementation.
309 switch (timer_sharing_) {
310 case TIMERS_UNTOUCHED:
311 StartTimer();
312 timer_sharing_ = TIMERS_ONE_SET;
313 break;
314 case TIMERS_ONE_SET:
315 // If the timer is running, that means that the main thread's
316 // timer setup is seen in this (second) thread -- and therefore
317 // that timers are shared.
318 if (IsTimerRunning()) {
319 timer_sharing_ = TIMERS_SHARED;
320 // If callback is already registered, we have to keep the timer
321 // running. If not, we disable the timer here.
322 if (callback_count_ == 0) {
323 StopTimer();
325 } else {
326 timer_sharing_ = TIMERS_SEPARATE;
327 StartTimer();
329 break;
330 case TIMERS_SHARED:
331 // Nothing needed.
332 break;
333 case TIMERS_SEPARATE:
334 StartTimer();
335 break;
339 ProfileHandlerToken* ProfileHandler::RegisterCallback(
340 ProfileHandlerCallback callback, void* callback_arg) {
342 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
344 SpinLockHolder cl(&control_lock_);
345 DisableHandler();
347 SpinLockHolder sl(&signal_lock_);
348 callbacks_.push_back(token);
350 // Start the timer if timer is shared and this is a first callback.
351 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) {
352 StartTimer();
354 ++callback_count_;
355 EnableHandler();
356 return token;
359 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
360 SpinLockHolder cl(&control_lock_);
361 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end();
362 ++it) {
363 if ((*it) == token) {
364 RAW_CHECK(callback_count_ > 0, "Invalid callback count");
365 DisableHandler();
367 SpinLockHolder sl(&signal_lock_);
368 delete *it;
369 callbacks_.erase(it);
371 --callback_count_;
372 if (callback_count_ > 0) {
373 EnableHandler();
374 } else if (timer_sharing_ == TIMERS_SHARED) {
375 StopTimer();
377 return;
380 // Unknown token.
381 RAW_LOG(FATAL, "Invalid token");
384 void ProfileHandler::Reset() {
385 SpinLockHolder cl(&control_lock_);
386 DisableHandler();
388 SpinLockHolder sl(&signal_lock_);
389 CallbackIterator it = callbacks_.begin();
390 while (it != callbacks_.end()) {
391 CallbackIterator tmp = it;
392 ++it;
393 delete *tmp;
394 callbacks_.erase(tmp);
397 callback_count_ = 0;
398 if (timer_sharing_ == TIMERS_SHARED) {
399 StopTimer();
401 timer_sharing_ = TIMERS_UNTOUCHED;
404 void ProfileHandler::GetState(ProfileHandlerState* state) {
405 SpinLockHolder cl(&control_lock_);
406 DisableHandler();
408 SpinLockHolder sl(&signal_lock_); // Protects interrupts_.
409 state->interrupts = interrupts_;
411 if (callback_count_ > 0) {
412 EnableHandler();
414 state->frequency = frequency_;
415 state->callback_count = callback_count_;
416 state->allowed = allowed_;
419 void ProfileHandler::StartTimer() {
420 if (!allowed_) {
421 return;
423 struct itimerval timer;
424 timer.it_interval.tv_sec = 0;
425 timer.it_interval.tv_usec = 1000000 / frequency_;
426 timer.it_value = timer.it_interval;
427 setitimer(timer_type_, &timer, 0);
430 void ProfileHandler::StopTimer() {
431 if (!allowed_) {
432 return;
434 struct itimerval timer;
435 memset(&timer, 0, sizeof timer);
436 setitimer(timer_type_, &timer, 0);
439 bool ProfileHandler::IsTimerRunning() {
440 if (!allowed_) {
441 return false;
443 struct itimerval current_timer;
444 RAW_CHECK(0 == getitimer(timer_type_, &current_timer), "getitimer");
445 return (current_timer.it_value.tv_sec != 0 ||
446 current_timer.it_value.tv_usec != 0);
449 void ProfileHandler::EnableHandler() {
450 if (!allowed_) {
451 return;
453 struct sigaction sa;
454 sa.sa_sigaction = SignalHandler;
455 sa.sa_flags = SA_RESTART | SA_SIGINFO;
456 sigemptyset(&sa.sa_mask);
457 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
458 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)");
461 void ProfileHandler::DisableHandler() {
462 if (!allowed_) {
463 return;
465 struct sigaction sa;
466 sa.sa_handler = SIG_IGN;
467 sa.sa_flags = SA_RESTART;
468 sigemptyset(&sa.sa_mask);
469 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
470 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)");
473 bool ProfileHandler::IsSignalHandlerAvailable() {
474 struct sigaction sa;
475 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
476 RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail");
478 // We only take over the handler if the current one is unset.
479 // It must be SIG_IGN or SIG_DFL, not some other function.
480 // SIG_IGN must be allowed because when profiling is allowed but
481 // not actively in use, this code keeps the handler set to SIG_IGN.
482 // That setting will be inherited across fork+exec. In order for
483 // any child to be able to use profiling, SIG_IGN must be treated
484 // as available.
485 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
488 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
489 int saved_errno = errno;
490 // At this moment, instance_ must be initialized because the handler is
491 // enabled in RegisterThread or RegisterCallback only after
492 // ProfileHandler::Instance runs.
493 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_);
494 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized");
496 SpinLockHolder sl(&instance->signal_lock_);
497 ++instance->interrupts_;
498 for (CallbackIterator it = instance->callbacks_.begin();
499 it != instance->callbacks_.end();
500 ++it) {
501 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
504 errno = saved_errno;
507 // This module initializer registers the main thread, so it must be
508 // executed in the context of the main thread.
509 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());
511 extern "C" void ProfileHandlerRegisterThread() {
512 ProfileHandler::Instance()->RegisterThread();
515 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
516 ProfileHandlerCallback callback, void* callback_arg) {
517 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
520 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
521 ProfileHandler::Instance()->UnregisterCallback(token);
524 extern "C" void ProfileHandlerReset() {
525 return ProfileHandler::Instance()->Reset();
528 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
529 ProfileHandler::Instance()->GetState(state);
532 #else // OS_CYGWIN
534 // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
535 // work as well for profiling, and also interferes with alarm(). Because of
536 // these issues, unless a specific need is identified, profiler support is
537 // disabled under Cygwin.
538 extern "C" void ProfileHandlerRegisterThread() {
541 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
542 ProfileHandlerCallback callback, void* callback_arg) {
543 return NULL;
546 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
549 extern "C" void ProfileHandlerReset() {
552 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
555 #endif // OS_CYGWIN