OLD | NEW |
1 // Copyright (c) 2009, Google Inc. | 1 // Copyright (c) 2009, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 28 matching lines...) Expand all Loading... |
39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) | 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) |
40 | 40 |
41 #include <stdio.h> | 41 #include <stdio.h> |
42 #include <errno.h> | 42 #include <errno.h> |
43 #include <sys/time.h> | 43 #include <sys/time.h> |
44 | 44 |
45 #include <list> | 45 #include <list> |
46 #include <string> | 46 #include <string> |
47 | 47 |
48 #include "base/dynamic_annotations.h" | 48 #include "base/dynamic_annotations.h" |
49 #include "base/googleinit.h" | |
50 #include "base/logging.h" | 49 #include "base/logging.h" |
51 #include "base/spinlock.h" | 50 #include "base/spinlock.h" |
52 #include "maybe_threads.h" | 51 #include "maybe_threads.h" |
53 | 52 |
54 using std::list; | 53 using std::list; |
55 using std::string; | 54 using std::string; |
56 | 55 |
57 // This structure is used by ProfileHandlerRegisterCallback and | 56 // This structure is used by ProfileHandlerRegisterCallback and |
58 // ProfileHandlerUnregisterCallback as a handle to a registered callback. | 57 // ProfileHandlerUnregisterCallback as a handle to a registered callback. |
59 struct ProfileHandlerToken { | 58 struct ProfileHandlerToken { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 | 132 |
134 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. | 133 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. |
135 int32 frequency_; | 134 int32 frequency_; |
136 | 135 |
137 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) | 136 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) |
138 int timer_type_; | 137 int timer_type_; |
139 | 138 |
140 // Counts the number of callbacks registered. | 139 // Counts the number of callbacks registered. |
141 int32 callback_count_ GUARDED_BY(control_lock_); | 140 int32 callback_count_ GUARDED_BY(control_lock_); |
142 | 141 |
143 // Is profiling allowed at all? | |
144 bool allowed_; | |
145 | |
146 // Whether or not the threading system provides interval timers that are | 142 // Whether or not the threading system provides interval timers that are |
147 // shared by all threads in a process. | 143 // shared by all threads in a process. |
148 enum { | 144 enum { |
149 // No timer initialization attempted yet. | 145 // No timer initialization attempted yet. |
150 TIMERS_UNTOUCHED, | 146 TIMERS_UNTOUCHED, |
151 // First thread has registered and set timer. | 147 // First thread has registered and set timer. |
152 TIMERS_ONE_SET, | 148 TIMERS_ONE_SET, |
153 // Timers are shared by all threads. | 149 // Timers are shared by all threads. |
154 TIMERS_SHARED, | 150 TIMERS_SHARED, |
155 // Timers are separate in each thread. | 151 // Timers are separate in each thread. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 // thread. This actually checks the kernel's interval timer setting. (It is | 192 // thread. This actually checks the kernel's interval timer setting. (It is |
197 // used to detect whether timers are shared or separate.) | 193 // used to detect whether timers are shared or separate.) |
198 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 194 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
199 | 195 |
200 // Sets the timer interrupt signal handler. | 196 // Sets the timer interrupt signal handler. |
201 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 197 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
202 | 198 |
203 // Disables (ignores) the timer interrupt signal. | 199 // Disables (ignores) the timer interrupt signal. |
204 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 200 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); |
205 | 201 |
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(); | |
209 | |
210 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. | 202 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. |
211 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); | 203 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); |
212 | 204 |
213 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); | 205 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); |
214 }; | 206 }; |
215 | 207 |
216 ProfileHandler* ProfileHandler::instance_ = NULL; | 208 ProfileHandler* ProfileHandler::instance_ = NULL; |
217 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; | 209 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; |
218 | 210 |
219 const int32 ProfileHandler::kMaxFrequency; | 211 const int32 ProfileHandler::kMaxFrequency; |
(...skipping 20 matching lines...) Expand all Loading... |
240 // (but doesn't do anything) even when pthreads isn't linked in. | 232 // (but doesn't do anything) even when pthreads isn't linked in. |
241 Init(); | 233 Init(); |
242 assert(instance_ != NULL); | 234 assert(instance_ != NULL); |
243 } | 235 } |
244 return instance_; | 236 return instance_; |
245 } | 237 } |
246 | 238 |
247 ProfileHandler::ProfileHandler() | 239 ProfileHandler::ProfileHandler() |
248 : interrupts_(0), | 240 : interrupts_(0), |
249 callback_count_(0), | 241 callback_count_(0), |
250 allowed_(true), | |
251 timer_sharing_(TIMERS_UNTOUCHED) { | 242 timer_sharing_(TIMERS_UNTOUCHED) { |
252 SpinLockHolder cl(&control_lock_); | 243 SpinLockHolder cl(&control_lock_); |
253 | 244 |
254 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); | 245 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); |
255 | 246 |
256 // Get frequency of interrupts (if specified) | 247 // Get frequency of interrupts (if specified) |
257 char junk; | 248 char junk; |
258 const char* fr = getenv("CPUPROFILE_FREQUENCY"); | 249 const char* fr = getenv("CPUPROFILE_FREQUENCY"); |
259 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && | 250 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && |
260 (frequency_ > 0)) { | 251 (frequency_ > 0)) { |
261 // Limit to kMaxFrequency | 252 // Limit to kMaxFrequency |
262 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; | 253 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; |
263 } else { | 254 } else { |
264 frequency_ = kDefaultFrequency; | 255 frequency_ = kDefaultFrequency; |
265 } | 256 } |
266 | 257 |
267 if (!allowed_) { | |
268 return; | |
269 } | |
270 | |
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; | |
278 } | |
279 | |
280 // Ignore signals until we decide to turn profiling on. (Paranoia; | 258 // Ignore signals until we decide to turn profiling on. (Paranoia; |
281 // should already be ignored.) | 259 // should already be ignored.) |
282 DisableHandler(); | 260 DisableHandler(); |
283 } | 261 } |
284 | 262 |
285 ProfileHandler::~ProfileHandler() { | 263 ProfileHandler::~ProfileHandler() { |
286 Reset(); | 264 Reset(); |
287 } | 265 } |
288 | 266 |
289 void ProfileHandler::RegisterThread() { | 267 void ProfileHandler::RegisterThread() { |
290 SpinLockHolder cl(&control_lock_); | 268 SpinLockHolder cl(&control_lock_); |
291 | 269 |
292 if (!allowed_) { | |
293 return; | |
294 } | |
295 | |
296 // We try to detect whether timers are being shared by setting a | 270 // We try to detect whether timers are being shared by setting a |
297 // timer in the first call to this function, then checking whether | 271 // timer in the first call to this function, then checking whether |
298 // it's set in the second call. | 272 // it's set in the second call. |
299 // | 273 // |
300 // Note that this detection method requires that the first two calls | 274 // Note that this detection method requires that the first two calls |
301 // to RegisterThread must be made from different threads. (Subsequent | 275 // to RegisterThread must be made from different threads. (Subsequent |
302 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or | 276 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or |
303 // TIMERS_SHARED, and won't try to detect the timer sharing type.) | 277 // TIMERS_SHARED, and won't try to detect the timer sharing type.) |
304 // | 278 // |
305 // Also note that if timer settings were inherited across new thread | 279 // Also note that if timer settings were inherited across new thread |
(...skipping 25 matching lines...) Expand all Loading... |
331 // Nothing needed. | 305 // Nothing needed. |
332 break; | 306 break; |
333 case TIMERS_SEPARATE: | 307 case TIMERS_SEPARATE: |
334 StartTimer(); | 308 StartTimer(); |
335 break; | 309 break; |
336 } | 310 } |
337 } | 311 } |
338 | 312 |
339 ProfileHandlerToken* ProfileHandler::RegisterCallback( | 313 ProfileHandlerToken* ProfileHandler::RegisterCallback( |
340 ProfileHandlerCallback callback, void* callback_arg) { | 314 ProfileHandlerCallback callback, void* callback_arg) { |
341 | |
342 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); | 315 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); |
343 | 316 |
344 SpinLockHolder cl(&control_lock_); | 317 SpinLockHolder cl(&control_lock_); |
345 DisableHandler(); | 318 DisableHandler(); |
346 { | 319 { |
347 SpinLockHolder sl(&signal_lock_); | 320 SpinLockHolder sl(&signal_lock_); |
348 callbacks_.push_back(token); | 321 callbacks_.push_back(token); |
349 } | 322 } |
350 // Start the timer if timer is shared and this is a first callback. | 323 // Start the timer if timer is shared and this is a first callback. |
351 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { | 324 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 DisableHandler(); | 379 DisableHandler(); |
407 { | 380 { |
408 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. | 381 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. |
409 state->interrupts = interrupts_; | 382 state->interrupts = interrupts_; |
410 } | 383 } |
411 if (callback_count_ > 0) { | 384 if (callback_count_ > 0) { |
412 EnableHandler(); | 385 EnableHandler(); |
413 } | 386 } |
414 state->frequency = frequency_; | 387 state->frequency = frequency_; |
415 state->callback_count = callback_count_; | 388 state->callback_count = callback_count_; |
416 state->allowed = allowed_; | |
417 } | 389 } |
418 | 390 |
419 void ProfileHandler::StartTimer() { | 391 void ProfileHandler::StartTimer() { |
420 if (!allowed_) { | |
421 return; | |
422 } | |
423 struct itimerval timer; | 392 struct itimerval timer; |
424 timer.it_interval.tv_sec = 0; | 393 timer.it_interval.tv_sec = 0; |
425 timer.it_interval.tv_usec = 1000000 / frequency_; | 394 timer.it_interval.tv_usec = 1000000 / frequency_; |
426 timer.it_value = timer.it_interval; | 395 timer.it_value = timer.it_interval; |
427 setitimer(timer_type_, &timer, 0); | 396 setitimer(timer_type_, &timer, 0); |
428 } | 397 } |
429 | 398 |
430 void ProfileHandler::StopTimer() { | 399 void ProfileHandler::StopTimer() { |
431 if (!allowed_) { | |
432 return; | |
433 } | |
434 struct itimerval timer; | 400 struct itimerval timer; |
435 memset(&timer, 0, sizeof timer); | 401 memset(&timer, 0, sizeof timer); |
436 setitimer(timer_type_, &timer, 0); | 402 setitimer(timer_type_, &timer, 0); |
437 } | 403 } |
438 | 404 |
439 bool ProfileHandler::IsTimerRunning() { | 405 bool ProfileHandler::IsTimerRunning() { |
440 if (!allowed_) { | |
441 return false; | |
442 } | |
443 struct itimerval current_timer; | 406 struct itimerval current_timer; |
444 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); | 407 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); |
445 return (current_timer.it_value.tv_sec != 0 || | 408 return (current_timer.it_value.tv_sec != 0 || |
446 current_timer.it_value.tv_usec != 0); | 409 current_timer.it_value.tv_usec != 0); |
447 } | 410 } |
448 | 411 |
449 void ProfileHandler::EnableHandler() { | 412 void ProfileHandler::EnableHandler() { |
450 if (!allowed_) { | |
451 return; | |
452 } | |
453 struct sigaction sa; | 413 struct sigaction sa; |
454 sa.sa_sigaction = SignalHandler; | 414 sa.sa_sigaction = SignalHandler; |
455 sa.sa_flags = SA_RESTART | SA_SIGINFO; | 415 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
456 sigemptyset(&sa.sa_mask); | 416 sigemptyset(&sa.sa_mask); |
457 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | 417 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
458 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); | 418 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); |
459 } | 419 } |
460 | 420 |
461 void ProfileHandler::DisableHandler() { | 421 void ProfileHandler::DisableHandler() { |
462 if (!allowed_) { | |
463 return; | |
464 } | |
465 struct sigaction sa; | 422 struct sigaction sa; |
466 sa.sa_handler = SIG_IGN; | 423 sa.sa_handler = SIG_IGN; |
467 sa.sa_flags = SA_RESTART; | 424 sa.sa_flags = SA_RESTART; |
468 sigemptyset(&sa.sa_mask); | 425 sigemptyset(&sa.sa_mask); |
469 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | 426 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
470 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); | 427 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); |
471 } | 428 } |
472 | 429 |
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")
; | |
477 | |
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; | |
486 } | |
487 | |
488 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { | 430 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
489 int saved_errno = errno; | 431 int saved_errno = errno; |
490 // At this moment, instance_ must be initialized because the handler is | 432 RAW_CHECK(instance_ != NULL, "ProfileHandler is not initialized"); |
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"); | |
495 { | 433 { |
496 SpinLockHolder sl(&instance->signal_lock_); | 434 SpinLockHolder sl(&instance_->signal_lock_); |
497 ++instance->interrupts_; | 435 ++instance_->interrupts_; |
498 for (CallbackIterator it = instance->callbacks_.begin(); | 436 for (CallbackIterator it = instance_->callbacks_.begin(); |
499 it != instance->callbacks_.end(); | 437 it != instance_->callbacks_.end(); |
500 ++it) { | 438 ++it) { |
501 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); | 439 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); |
502 } | 440 } |
503 } | 441 } |
504 errno = saved_errno; | 442 errno = saved_errno; |
505 } | 443 } |
506 | 444 |
507 // This module initializer registers the main thread, so it must be | 445 // The sole purpose of this class is to initialize the ProfileHandler singleton |
508 // executed in the context of the main thread. | 446 // when the global static objects are created. Note that the main thread will |
509 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); | 447 // be registered at this time. |
| 448 class ProfileHandlerInitializer { |
| 449 public: |
| 450 ProfileHandlerInitializer() { |
| 451 ProfileHandler::Instance()->RegisterThread(); |
| 452 } |
| 453 |
| 454 private: |
| 455 DISALLOW_COPY_AND_ASSIGN(ProfileHandlerInitializer); |
| 456 }; |
| 457 // ProfileHandlerInitializer singleton |
| 458 static ProfileHandlerInitializer profile_handler_initializer; |
510 | 459 |
511 extern "C" void ProfileHandlerRegisterThread() { | 460 extern "C" void ProfileHandlerRegisterThread() { |
512 ProfileHandler::Instance()->RegisterThread(); | 461 ProfileHandler::Instance()->RegisterThread(); |
513 } | 462 } |
514 | 463 |
515 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( | 464 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( |
516 ProfileHandlerCallback callback, void* callback_arg) { | 465 ProfileHandlerCallback callback, void* callback_arg) { |
517 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); | 466 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); |
518 } | 467 } |
519 | 468 |
(...skipping 26 matching lines...) Expand all Loading... |
546 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { | 495 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { |
547 } | 496 } |
548 | 497 |
549 extern "C" void ProfileHandlerReset() { | 498 extern "C" void ProfileHandlerReset() { |
550 } | 499 } |
551 | 500 |
552 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { | 501 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { |
553 } | 502 } |
554 | 503 |
555 #endif // OS_CYGWIN | 504 #endif // OS_CYGWIN |
OLD | NEW |