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