| 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 20 matching lines...) Expand all Loading... |
| 31 // Author: Sanjay Ghemawat | 31 // Author: Sanjay Ghemawat |
| 32 // Nabeel Mian | 32 // Nabeel Mian |
| 33 // | 33 // |
| 34 // Implements management of profile timers and the corresponding signal handler. | 34 // Implements management of profile timers and the corresponding signal handler. |
| 35 | 35 |
| 36 #include "config.h" | 36 #include "config.h" |
| 37 #include "profile-handler.h" | 37 #include "profile-handler.h" |
| 38 | 38 |
| 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) | 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) |
| 40 | 40 |
| 41 #include <errno.h> |
| 41 #include <stdio.h> | 42 #include <stdio.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 <map> |
| 46 #include <string> | 47 #include <string> |
| 47 | 48 |
| 48 #include "base/dynamic_annotations.h" | 49 #include "base/dynamic_annotations.h" |
| 49 #include "base/googleinit.h" | 50 #include "base/googleinit.h" |
| 50 #include "base/logging.h" | 51 #include "base/logging.h" |
| 51 #include "base/spinlock.h" | 52 #include "base/spinlock.h" |
| 52 #include "maybe_threads.h" | 53 #include "maybe_threads.h" |
| 53 | 54 |
| 54 using std::list; | 55 using std::list; |
| 56 using std::map; |
| 55 using std::string; | 57 using std::string; |
| 56 | 58 |
| 57 // This structure is used by ProfileHandlerRegisterCallback and | 59 // This structure is used by ProfileHandlerRegisterCallback and |
| 58 // ProfileHandlerUnregisterCallback as a handle to a registered callback. | 60 // ProfileHandlerUnregisterCallback as a handle to a registered callback. |
| 59 struct ProfileHandlerToken { | 61 struct ProfileHandlerToken { |
| 60 // Sets the callback and associated arg. | 62 // Sets the callback and associated arg. |
| 61 ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg) | 63 ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg) |
| 62 : callback(cb), | 64 : callback(cb), |
| 63 callback_arg(cb_arg) { | 65 callback_arg(cb_arg) { |
| 64 } | 66 } |
| 65 | 67 |
| 66 // Callback function to be invoked on receiving a profile timer interrupt. | 68 // Callback function to be invoked on receiving a profile timer interrupt. |
| 67 ProfileHandlerCallback callback; | 69 ProfileHandlerCallback callback; |
| 68 // Argument for the callback function. | 70 // Argument for the callback function. |
| 69 void* callback_arg; | 71 void* callback_arg; |
| 70 }; | 72 }; |
| 71 | 73 |
| 74 // Blocks a signal from being delivered to the current thread while the object |
| 75 // is alive. Restores previous state upon destruction. |
| 76 class ScopedSignalBlocker { |
| 77 public: |
| 78 ScopedSignalBlocker(int signo) { |
| 79 sigemptyset(&sig_set_); |
| 80 sigaddset(&sig_set_, signo); |
| 81 RAW_CHECK(sigprocmask(SIG_BLOCK, &sig_set_, NULL) == 0, |
| 82 "sigprocmask (block)"); |
| 83 } |
| 84 ~ScopedSignalBlocker() { |
| 85 RAW_CHECK(sigprocmask(SIG_UNBLOCK, &sig_set_, NULL) == 0, |
| 86 "sigprocmask (unblock)"); |
| 87 } |
| 88 |
| 89 private: |
| 90 sigset_t sig_set_; |
| 91 }; |
| 92 |
| 72 // This class manages profile timers and associated signal handler. This is a | 93 // This class manages profile timers and associated signal handler. This is a |
| 73 // a singleton. | 94 // a singleton. |
| 74 class ProfileHandler { | 95 class ProfileHandler { |
| 75 public: | 96 public: |
| 76 // Registers the current thread with the profile handler. On systems which | 97 // Registers the current thread with the profile handler. |
| 77 // have a separate interval timer for each thread, this function starts the | |
| 78 // timer for the current thread. | |
| 79 // | |
| 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.) | |
| 83 // | |
| 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(); | 98 void RegisterThread(); |
| 89 | 99 |
| 100 // Unregisters the current thread with the profile handler. |
| 101 void UnregisterThread(); |
| 102 |
| 90 // Registers a callback routine to receive profile timer ticks. The returned | 103 // 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 | 104 // 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 | 105 // deleted by the caller. |
| 93 // SIGPROF handler (or SIGALRM if using ITIMER_REAL). | |
| 94 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, | 106 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, |
| 95 void* callback_arg); | 107 void* callback_arg); |
| 96 | 108 |
| 97 // Unregisters a previously registered callback. Expects the token returned | 109 // Unregisters a previously registered callback. Expects the token returned |
| 98 // by the corresponding RegisterCallback routine. Unregistering the last | 110 // by the corresponding RegisterCallback routine. |
| 99 // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL). | |
| 100 void UnregisterCallback(ProfileHandlerToken* token) | 111 void UnregisterCallback(ProfileHandlerToken* token) |
| 101 NO_THREAD_SAFETY_ANALYSIS; | 112 NO_THREAD_SAFETY_ANALYSIS; |
| 102 | 113 |
| 103 // Unregisters all the callbacks, stops the timer if shared, disables the | 114 // Unregisters all the callbacks and stops the timer(s). |
| 104 // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state. | |
| 105 void Reset(); | 115 void Reset(); |
| 106 | 116 |
| 107 // Gets the current state of profile handler. | 117 // Gets the current state of profile handler. |
| 108 void GetState(ProfileHandlerState* state); | 118 void GetState(ProfileHandlerState* state); |
| 109 | 119 |
| 110 // Initializes and returns the ProfileHandler singleton. | 120 // Initializes and returns the ProfileHandler singleton. |
| 111 static ProfileHandler* Instance(); | 121 static ProfileHandler* Instance(); |
| 112 | 122 |
| 113 private: | 123 private: |
| 114 ProfileHandler(); | 124 ProfileHandler(); |
| 115 ~ProfileHandler(); | 125 ~ProfileHandler(); |
| 116 | 126 |
| 117 // Largest allowed frequency. | 127 // Largest allowed frequency. |
| 118 static const int32 kMaxFrequency = 4000; | 128 static const int32 kMaxFrequency = 4000; |
| 119 // Default frequency. | 129 // Default frequency. |
| 120 static const int32 kDefaultFrequency = 100; | 130 static const int32 kDefaultFrequency = 100; |
| 121 | 131 |
| 122 // ProfileHandler singleton. | 132 // ProfileHandler singleton. |
| 123 static ProfileHandler* instance_; | 133 static ProfileHandler* instance_; |
| 124 | 134 |
| 125 // pthread_once_t for one time initialization of ProfileHandler singleton. | 135 // pthread_once_t for one time initialization of ProfileHandler singleton. |
| 126 static pthread_once_t once_; | 136 static pthread_once_t once_; |
| 127 | 137 |
| 138 #if defined(HAVE_TLS) |
| 139 // Timer state as configured previously. This bit is kept in |
| 140 // |registered_threads_| if TLS is not available. |
| 141 static __thread bool timer_running_; |
| 142 #endif |
| 143 |
| 128 // Initializes the ProfileHandler singleton via GoogleOnceInit. | 144 // Initializes the ProfileHandler singleton via GoogleOnceInit. |
| 129 static void Init(); | 145 static void Init(); |
| 130 | 146 |
| 131 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. | 147 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. |
| 132 int64 interrupts_ GUARDED_BY(signal_lock_); | 148 int64 interrupts_ GUARDED_BY(signal_lock_); |
| 133 | 149 |
| 134 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. | 150 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. |
| 135 int32 frequency_; | 151 int32 frequency_; |
| 136 | 152 |
| 137 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) | 153 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) |
| 138 int timer_type_; | 154 int timer_type_; |
| 139 | 155 |
| 140 // Counts the number of callbacks registered. | 156 // Counts the number of callbacks registered. |
| 141 int32 callback_count_ GUARDED_BY(control_lock_); | 157 int32 callback_count_ GUARDED_BY(control_lock_); |
| 142 | 158 |
| 143 // Is profiling allowed at all? | 159 // Is profiling allowed at all? |
| 144 bool allowed_; | 160 bool allowed_; |
| 145 | 161 |
| 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_); | |
| 158 | |
| 159 // This lock serializes the registration of threads and protects the | 162 // This lock serializes the registration of threads and protects the |
| 160 // callbacks_ list below. | 163 // callbacks_ list below. |
| 161 // Locking order: | 164 // Locking order: |
| 162 // In the context of a signal handler, acquire signal_lock_ to walk the | 165 // In the context of a signal handler, acquire signal_lock_ to walk the |
| 163 // callback list. Otherwise, acquire control_lock_, disable the signal | 166 // callback list. Otherwise, acquire control_lock_, disable the signal |
| 164 // handler and then acquire signal_lock_. | 167 // handler and then acquire signal_lock_. |
| 165 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); | 168 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); |
| 166 SpinLock signal_lock_; | 169 SpinLock signal_lock_; |
| 167 | 170 |
| 171 // Set of threads registered through RegisterThread. This is consulted |
| 172 // whenever timers are switched on or off to post a signal to these threads |
| 173 // so they can arm their timers. Locking rules as for |callbacks_| below. If |
| 174 // TLS is not available, this map is also used to keep the thread's timer |
| 175 // state. |
| 176 map<pthread_t, bool> registered_threads_ GUARDED_BY(signal_lock_); |
| 177 |
| 168 // Holds the list of registered callbacks. We expect the list to be pretty | 178 // Holds the list of registered callbacks. We expect the list to be pretty |
| 169 // small. Currently, the cpu profiler (base/profiler) and thread module | 179 // small. Currently, the cpu profiler (base/profiler) and thread module |
| 170 // (base/thread.h) are the only two components registering callbacks. | 180 // (base/thread.h) are the only two components registering callbacks. |
| 171 // Following are the locking requirements for callbacks_: | 181 // Following are the locking requirements for callbacks_: |
| 172 // For read-write access outside the SIGPROF handler: | 182 // For read-write access outside the SIGPROF handler: |
| 173 // - Acquire control_lock_ | 183 // - Acquire control_lock_ |
| 174 // - Disable SIGPROF handler. | 184 // - Disable SIGPROF handler. |
| 175 // - Acquire signal_lock_ | 185 // - Acquire signal_lock_ |
| 176 // For read-only access in the context of SIGPROF handler | 186 // For read-only access in the context of SIGPROF handler |
| 177 // (Read-write access is *not allowed* in the SIGPROF handler) | 187 // (Read-write access is *not allowed* in the SIGPROF handler) |
| 178 // - Acquire signal_lock_ | 188 // - Acquire signal_lock_ |
| 179 // For read-only access outside SIGPROF handler: | 189 // For read-only access outside SIGPROF handler: |
| 180 // - Acquire control_lock_ | 190 // - Acquire control_lock_ |
| 181 typedef list<ProfileHandlerToken*> CallbackList; | 191 typedef list<ProfileHandlerToken*> CallbackList; |
| 182 typedef CallbackList::iterator CallbackIterator; | 192 typedef CallbackList::iterator CallbackIterator; |
| 183 CallbackList callbacks_ GUARDED_BY(signal_lock_); | 193 CallbackList callbacks_ GUARDED_BY(signal_lock_); |
| 184 | 194 |
| 185 // Starts the interval timer. If the thread library shares timers between | 195 // Returns the signal to be used with |timer_type_| (SIGPROF or SIGALARM). |
| 186 // threads, this function starts the shared timer. Otherwise, this will start | 196 int signal_number() { |
| 187 // the timer in the current thread. | 197 return (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); |
| 188 void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 198 } |
| 189 | 199 |
| 190 // Stops the interval timer. If the thread library shares timers between | 200 // Starts or stops the interval timer(s). In case of non-shared timers, this |
| 191 // threads, this fucntion stops the shared timer. Otherwise, this will stop | 201 // will post a signal to all registered threads, causing them to arm their |
| 192 // the timer in the current thread. | 202 // timers. |
| 193 void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | 203 void UpdateTimers(bool enable) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_); |
| 194 | 204 |
| 195 // Returns true if the profile interval timer is enabled in the current | 205 // Configures the timer. If |frequency| is 0, the timer will be disabled. |
| 196 // thread. This actually checks the kernel's interval timer setting. (It is | 206 void SetupTimer(int32 frequency) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_); |
| 197 // used to detect whether timers are shared or separate.) | |
| 198 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | |
| 199 | |
| 200 // Sets the timer interrupt signal handler. | |
| 201 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | |
| 202 | |
| 203 // Disables (ignores) the timer interrupt signal. | |
| 204 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); | |
| 205 | 207 |
| 206 // Returns true if the handler is not being used by something else. | 208 // Returns true if the handler is not being used by something else. |
| 207 // This checks the kernel's signal handler table. | 209 // This checks the kernel's signal handler table. |
| 208 bool IsSignalHandlerAvailable(); | 210 bool IsSignalHandlerAvailable(); |
| 209 | 211 |
| 210 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. | 212 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks
. |
| 211 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); | 213 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); |
| 212 | 214 |
| 213 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); | 215 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); |
| 214 }; | 216 }; |
| 215 | 217 |
| 216 ProfileHandler* ProfileHandler::instance_ = NULL; | 218 ProfileHandler* ProfileHandler::instance_ = NULL; |
| 217 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; | 219 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; |
| 218 | 220 |
| 221 #if defined(HAVE_TLS) |
| 222 bool __thread ProfileHandler::timer_running_ = false; |
| 223 #endif |
| 224 |
| 219 const int32 ProfileHandler::kMaxFrequency; | 225 const int32 ProfileHandler::kMaxFrequency; |
| 220 const int32 ProfileHandler::kDefaultFrequency; | 226 const int32 ProfileHandler::kDefaultFrequency; |
| 221 | 227 |
| 222 // If we are LD_PRELOAD-ed against a non-pthreads app, then | 228 // If we are LD_PRELOAD-ed against a non-pthreads app, then pthread_* functions |
| 223 // pthread_once won't be defined. We declare it here, for that | 229 // won't be defined. We declare them here, for that case (with weak linkage) |
| 224 // case (with weak linkage) which will cause the non-definition to | 230 // which will cause the non-definition to resolve to NULL. We can then check |
| 225 // resolve to NULL. We can then check for NULL or not in Instance. | 231 // for NULL or not in Instance. |
| 226 extern "C" int pthread_once(pthread_once_t *, void (*)(void)) | 232 extern "C" int pthread_once(pthread_once_t *, void (*)(void)) |
| 227 ATTRIBUTE_WEAK; | 233 ATTRIBUTE_WEAK; |
| 234 extern "C" int pthread_kill(pthread_t thread_id, int signo) |
| 235 ATTRIBUTE_WEAK; |
| 228 | 236 |
| 229 void ProfileHandler::Init() { | 237 void ProfileHandler::Init() { |
| 230 instance_ = new ProfileHandler(); | 238 instance_ = new ProfileHandler(); |
| 231 } | 239 } |
| 232 | 240 |
| 233 ProfileHandler* ProfileHandler::Instance() { | 241 ProfileHandler* ProfileHandler::Instance() { |
| 234 if (pthread_once) { | 242 if (pthread_once) { |
| 235 pthread_once(&once_, Init); | 243 pthread_once(&once_, Init); |
| 236 } | 244 } |
| 237 if (instance_ == NULL) { | 245 if (instance_ == NULL) { |
| 238 // This will be true on systems that don't link in pthreads, | 246 // This will be true on systems that don't link in pthreads, |
| 239 // including on FreeBSD where pthread_once has a non-zero address | 247 // including on FreeBSD where pthread_once has a non-zero address |
| 240 // (but doesn't do anything) even when pthreads isn't linked in. | 248 // (but doesn't do anything) even when pthreads isn't linked in. |
| 241 Init(); | 249 Init(); |
| 242 assert(instance_ != NULL); | 250 assert(instance_ != NULL); |
| 243 } | 251 } |
| 244 return instance_; | 252 return instance_; |
| 245 } | 253 } |
| 246 | 254 |
| 247 ProfileHandler::ProfileHandler() | 255 ProfileHandler::ProfileHandler() |
| 248 : interrupts_(0), | 256 : interrupts_(0), |
| 249 callback_count_(0), | 257 callback_count_(0), |
| 250 allowed_(true), | 258 allowed_(true) { |
| 251 timer_sharing_(TIMERS_UNTOUCHED) { | |
| 252 SpinLockHolder cl(&control_lock_); | 259 SpinLockHolder cl(&control_lock_); |
| 253 | 260 |
| 254 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); | 261 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); |
| 255 | 262 |
| 256 // Get frequency of interrupts (if specified) | 263 // Get frequency of interrupts (if specified) |
| 257 char junk; | 264 char junk; |
| 258 const char* fr = getenv("CPUPROFILE_FREQUENCY"); | 265 const char* fr = getenv("CPUPROFILE_FREQUENCY"); |
| 259 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && | 266 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && |
| 260 (frequency_ > 0)) { | 267 (frequency_ > 0)) { |
| 261 // Limit to kMaxFrequency | 268 // Limit to kMaxFrequency |
| 262 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; | 269 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; |
| 263 } else { | 270 } else { |
| 264 frequency_ = kDefaultFrequency; | 271 frequency_ = kDefaultFrequency; |
| 265 } | 272 } |
| 266 | 273 |
| 267 if (!allowed_) { | 274 if (!allowed_) { |
| 268 return; | 275 return; |
| 269 } | 276 } |
| 270 | 277 |
| 271 // If something else is using the signal handler, | 278 // If something else is using the signal handler, |
| 272 // assume it has priority over us and stop. | 279 // assume it has priority over us and stop. |
| 273 if (!IsSignalHandlerAvailable()) { | 280 if (!IsSignalHandlerAvailable()) { |
| 274 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", | 281 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", |
| 275 timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); | 282 signal_number()); |
| 276 allowed_ = false; | 283 allowed_ = false; |
| 277 return; | 284 return; |
| 278 } | 285 } |
| 279 | 286 |
| 280 // Ignore signals until we decide to turn profiling on. (Paranoia; | 287 // Install the signal handler. |
| 281 // should already be ignored.) | 288 struct sigaction sa; |
| 282 DisableHandler(); | 289 sa.sa_sigaction = SignalHandler; |
| 290 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 291 sigemptyset(&sa.sa_mask); |
| 292 RAW_CHECK(sigaction(signal_number(), &sa, NULL) == 0, "sigprof (enable)"); |
| 283 } | 293 } |
| 284 | 294 |
| 285 ProfileHandler::~ProfileHandler() { | 295 ProfileHandler::~ProfileHandler() { |
| 286 Reset(); | 296 Reset(); |
| 287 } | 297 } |
| 288 | 298 |
| 289 void ProfileHandler::RegisterThread() { | 299 void ProfileHandler::RegisterThread() { |
| 290 SpinLockHolder cl(&control_lock_); | 300 SpinLockHolder cl(&control_lock_); |
| 291 | 301 |
| 292 if (!allowed_) { | 302 if (!allowed_) { |
| 293 return; | 303 return; |
| 294 } | 304 } |
| 295 | 305 |
| 296 // We try to detect whether timers are being shared by setting a | 306 // Record the thread identifier and start the timer if profiling is on. |
| 297 // timer in the first call to this function, then checking whether | 307 ScopedSignalBlocker block(signal_number()); |
| 298 // it's set in the second call. | 308 SpinLockHolder sl(&signal_lock_); |
| 299 // | 309 registered_threads_[pthread_self()] = false; |
| 300 // Note that this detection method requires that the first two calls | 310 SetupTimer(callback_count_ > 0 ? frequency_ : 0); |
| 301 // to RegisterThread must be made from different threads. (Subsequent | 311 } |
| 302 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or | 312 |
| 303 // TIMERS_SHARED, and won't try to detect the timer sharing type.) | 313 void ProfileHandler::UnregisterThread() { |
| 304 // | 314 ScopedSignalBlocker block(signal_number()); |
| 305 // Also note that if timer settings were inherited across new thread | 315 SpinLockHolder sl(&signal_lock_); |
| 306 // creation but *not* shared, this approach wouldn't work. That's | 316 registered_threads_.erase(pthread_self()); |
| 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(); | |
| 324 } | |
| 325 } else { | |
| 326 timer_sharing_ = TIMERS_SEPARATE; | |
| 327 StartTimer(); | |
| 328 } | |
| 329 break; | |
| 330 case TIMERS_SHARED: | |
| 331 // Nothing needed. | |
| 332 break; | |
| 333 case TIMERS_SEPARATE: | |
| 334 StartTimer(); | |
| 335 break; | |
| 336 } | |
| 337 } | 317 } |
| 338 | 318 |
| 339 ProfileHandlerToken* ProfileHandler::RegisterCallback( | 319 ProfileHandlerToken* ProfileHandler::RegisterCallback( |
| 340 ProfileHandlerCallback callback, void* callback_arg) { | 320 ProfileHandlerCallback callback, void* callback_arg) { |
| 341 | 321 |
| 342 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); | 322 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); |
| 343 | 323 |
| 344 SpinLockHolder cl(&control_lock_); | 324 SpinLockHolder cl(&control_lock_); |
| 345 DisableHandler(); | |
| 346 { | 325 { |
| 326 ScopedSignalBlocker block(signal_number()); |
| 347 SpinLockHolder sl(&signal_lock_); | 327 SpinLockHolder sl(&signal_lock_); |
| 348 callbacks_.push_back(token); | 328 callbacks_.push_back(token); |
| 329 ++callback_count_; |
| 330 UpdateTimers(true); |
| 349 } | 331 } |
| 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(); | |
| 353 } | |
| 354 ++callback_count_; | |
| 355 EnableHandler(); | |
| 356 return token; | 332 return token; |
| 357 } | 333 } |
| 358 | 334 |
| 359 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { | 335 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { |
| 360 SpinLockHolder cl(&control_lock_); | 336 SpinLockHolder cl(&control_lock_); |
| 361 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end(); | 337 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end(); |
| 362 ++it) { | 338 ++it) { |
| 363 if ((*it) == token) { | 339 if ((*it) == token) { |
| 364 RAW_CHECK(callback_count_ > 0, "Invalid callback count"); | 340 RAW_CHECK(callback_count_ > 0, "Invalid callback count"); |
| 365 DisableHandler(); | |
| 366 { | 341 { |
| 342 ScopedSignalBlocker block(signal_number()); |
| 367 SpinLockHolder sl(&signal_lock_); | 343 SpinLockHolder sl(&signal_lock_); |
| 368 delete *it; | 344 delete *it; |
| 369 callbacks_.erase(it); | 345 callbacks_.erase(it); |
| 370 } | 346 --callback_count_; |
| 371 --callback_count_; | 347 if (callback_count_ == 0) |
| 372 if (callback_count_ > 0) { | 348 UpdateTimers(false); |
| 373 EnableHandler(); | |
| 374 } else if (timer_sharing_ == TIMERS_SHARED) { | |
| 375 StopTimer(); | |
| 376 } | 349 } |
| 377 return; | 350 return; |
| 378 } | 351 } |
| 379 } | 352 } |
| 380 // Unknown token. | 353 // Unknown token. |
| 381 RAW_LOG(FATAL, "Invalid token"); | 354 RAW_LOG(FATAL, "Invalid token"); |
| 382 } | 355 } |
| 383 | 356 |
| 384 void ProfileHandler::Reset() { | 357 void ProfileHandler::Reset() { |
| 385 SpinLockHolder cl(&control_lock_); | 358 SpinLockHolder cl(&control_lock_); |
| 386 DisableHandler(); | |
| 387 { | 359 { |
| 360 ScopedSignalBlocker block(signal_number()); |
| 388 SpinLockHolder sl(&signal_lock_); | 361 SpinLockHolder sl(&signal_lock_); |
| 389 CallbackIterator it = callbacks_.begin(); | 362 CallbackIterator it = callbacks_.begin(); |
| 390 while (it != callbacks_.end()) { | 363 while (it != callbacks_.end()) { |
| 391 CallbackIterator tmp = it; | 364 CallbackIterator tmp = it; |
| 392 ++it; | 365 ++it; |
| 393 delete *tmp; | 366 delete *tmp; |
| 394 callbacks_.erase(tmp); | 367 callbacks_.erase(tmp); |
| 395 } | 368 } |
| 369 callback_count_ = 0; |
| 370 UpdateTimers(false); |
| 396 } | 371 } |
| 397 callback_count_ = 0; | |
| 398 if (timer_sharing_ == TIMERS_SHARED) { | |
| 399 StopTimer(); | |
| 400 } | |
| 401 timer_sharing_ = TIMERS_UNTOUCHED; | |
| 402 } | 372 } |
| 403 | 373 |
| 404 void ProfileHandler::GetState(ProfileHandlerState* state) { | 374 void ProfileHandler::GetState(ProfileHandlerState* state) { |
| 405 SpinLockHolder cl(&control_lock_); | 375 SpinLockHolder cl(&control_lock_); |
| 406 DisableHandler(); | |
| 407 { | 376 { |
| 377 ScopedSignalBlocker block(signal_number()); |
| 408 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. | 378 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. |
| 409 state->interrupts = interrupts_; | 379 state->interrupts = interrupts_; |
| 410 } | 380 } |
| 411 if (callback_count_ > 0) { | |
| 412 EnableHandler(); | |
| 413 } | |
| 414 state->frequency = frequency_; | 381 state->frequency = frequency_; |
| 415 state->callback_count = callback_count_; | 382 state->callback_count = callback_count_; |
| 416 state->allowed = allowed_; | 383 state->allowed = allowed_; |
| 417 } | 384 } |
| 418 | 385 |
| 419 void ProfileHandler::StartTimer() { | 386 void ProfileHandler::UpdateTimers(bool enabled) { |
| 420 if (!allowed_) { | 387 if (!allowed_) { |
| 421 return; | 388 return; |
| 422 } | 389 } |
| 390 SetupTimer(enabled ? frequency_ : 0); |
| 391 |
| 392 // Tell other threads to start their timers. |
| 393 for (map<pthread_t, bool>::const_iterator thread(registered_threads_.begin()); |
| 394 thread != registered_threads_.end(); |
| 395 ++thread) { |
| 396 if (thread->first != pthread_self() && pthread_kill) { |
| 397 int err = pthread_kill(thread->first, signal_number()); |
| 398 if (err == ESRCH) { |
| 399 // Thread exited. |
| 400 registered_threads_.erase(thread->first); |
| 401 } else { |
| 402 RAW_CHECK(err == 0, "pthread_kill"); |
| 403 } |
| 404 } |
| 405 } |
| 406 } |
| 407 |
| 408 void ProfileHandler::SetupTimer(int32 frequency) { |
| 409 bool enable = (frequency > 0); |
| 410 #if defined(HAVE_TLS) |
| 411 bool& timer_running = timer_running_; |
| 412 #else |
| 413 bool& timer_running = registered_threads_[pthread_self()]; |
| 414 #endif |
| 415 if (enable == timer_running) |
| 416 return; |
| 423 struct itimerval timer; | 417 struct itimerval timer; |
| 424 timer.it_interval.tv_sec = 0; | 418 timer.it_interval.tv_sec = 0; |
| 425 timer.it_interval.tv_usec = 1000000 / frequency_; | 419 timer.it_interval.tv_usec = (enable ? (1000000 / frequency) : 0); |
| 426 timer.it_value = timer.it_interval; | 420 timer.it_value = timer.it_interval; |
| 427 setitimer(timer_type_, &timer, 0); | 421 setitimer(timer_type_, &timer, 0); |
| 428 } | 422 timer_running = enable; |
| 429 | |
| 430 void ProfileHandler::StopTimer() { | |
| 431 if (!allowed_) { | |
| 432 return; | |
| 433 } | |
| 434 struct itimerval timer; | |
| 435 memset(&timer, 0, sizeof timer); | |
| 436 setitimer(timer_type_, &timer, 0); | |
| 437 } | |
| 438 | |
| 439 bool ProfileHandler::IsTimerRunning() { | |
| 440 if (!allowed_) { | |
| 441 return false; | |
| 442 } | |
| 443 struct itimerval current_timer; | |
| 444 RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); | |
| 445 return (current_timer.it_value.tv_sec != 0 || | |
| 446 current_timer.it_value.tv_usec != 0); | |
| 447 } | |
| 448 | |
| 449 void ProfileHandler::EnableHandler() { | |
| 450 if (!allowed_) { | |
| 451 return; | |
| 452 } | |
| 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)"); | |
| 459 } | |
| 460 | |
| 461 void ProfileHandler::DisableHandler() { | |
| 462 if (!allowed_) { | |
| 463 return; | |
| 464 } | |
| 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)"); | |
| 471 } | 423 } |
| 472 | 424 |
| 473 bool ProfileHandler::IsSignalHandlerAvailable() { | 425 bool ProfileHandler::IsSignalHandlerAvailable() { |
| 474 struct sigaction sa; | 426 struct sigaction sa; |
| 475 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); | 427 RAW_CHECK(sigaction(signal_number(), NULL, &sa) == 0, |
| 476 RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail")
; | 428 "is-signal-handler avail"); |
| 477 | 429 |
| 478 // We only take over the handler if the current one is unset. | 430 // 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. | 431 // It must be SIG_IGN or SIG_DFL, not some other function. |
| 480 // SIG_IGN must be allowed because when profiling is allowed but | 432 // 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. | 433 // 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 | 434 // 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 | 435 // any child to be able to use profiling, SIG_IGN must be treated |
| 484 // as available. | 436 // as available. |
| 485 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; | 437 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; |
| 486 } | 438 } |
| 487 | 439 |
| 488 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { | 440 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { |
| 489 int saved_errno = errno; | 441 int saved_errno = errno; |
| 490 // At this moment, instance_ must be initialized because the handler is | 442 // At this moment, instance_ must be initialized because the handler is |
| 491 // enabled in RegisterThread or RegisterCallback only after | 443 // enabled in RegisterThread or RegisterCallback only after |
| 492 // ProfileHandler::Instance runs. | 444 // ProfileHandler::Instance runs. |
| 493 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); | 445 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); |
| 494 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); | 446 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); |
| 495 { | 447 { |
| 496 SpinLockHolder sl(&instance->signal_lock_); | 448 SpinLockHolder sl(&instance->signal_lock_); |
| 497 ++instance->interrupts_; | 449 ++instance->interrupts_; |
| 450 // Enable/Disable the timer if necessary. |
| 451 instance->SetupTimer( |
| 452 instance->callbacks_.empty() ? 0 : instance->frequency_); |
| 498 for (CallbackIterator it = instance->callbacks_.begin(); | 453 for (CallbackIterator it = instance->callbacks_.begin(); |
| 499 it != instance->callbacks_.end(); | 454 it != instance->callbacks_.end(); |
| 500 ++it) { | 455 ++it) { |
| 501 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); | 456 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); |
| 502 } | 457 } |
| 503 } | 458 } |
| 504 errno = saved_errno; | 459 errno = saved_errno; |
| 505 } | 460 } |
| 506 | 461 |
| 507 // This module initializer registers the main thread, so it must be | 462 // This module initializer registers the main thread, so it must be |
| 508 // executed in the context of the main thread. | 463 // executed in the context of the main thread. |
| 509 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); | 464 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); |
| 510 | 465 |
| 511 extern "C" void ProfileHandlerRegisterThread() { | 466 extern "C" void ProfileHandlerRegisterThread() { |
| 512 ProfileHandler::Instance()->RegisterThread(); | 467 ProfileHandler::Instance()->RegisterThread(); |
| 513 } | 468 } |
| 514 | 469 |
| 470 extern "C" void ProfileHandlerUnregisterThread() { |
| 471 ProfileHandler::Instance()->UnregisterThread(); |
| 472 } |
| 473 |
| 515 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( | 474 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( |
| 516 ProfileHandlerCallback callback, void* callback_arg) { | 475 ProfileHandlerCallback callback, void* callback_arg) { |
| 517 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); | 476 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); |
| 518 } | 477 } |
| 519 | 478 |
| 520 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { | 479 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { |
| 521 ProfileHandler::Instance()->UnregisterCallback(token); | 480 ProfileHandler::Instance()->UnregisterCallback(token); |
| 522 } | 481 } |
| 523 | 482 |
| 524 extern "C" void ProfileHandlerReset() { | 483 extern "C" void ProfileHandlerReset() { |
| 525 return ProfileHandler::Instance()->Reset(); | 484 return ProfileHandler::Instance()->Reset(); |
| 526 } | 485 } |
| 527 | 486 |
| 528 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { | 487 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { |
| 529 ProfileHandler::Instance()->GetState(state); | 488 ProfileHandler::Instance()->GetState(state); |
| 530 } | 489 } |
| 531 | 490 |
| 532 #else // OS_CYGWIN | 491 #else // OS_CYGWIN |
| 533 | 492 |
| 534 // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't | 493 // 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 | 494 // work as well for profiling, and also interferes with alarm(). Because of |
| 536 // these issues, unless a specific need is identified, profiler support is | 495 // these issues, unless a specific need is identified, profiler support is |
| 537 // disabled under Cygwin. | 496 // disabled under Cygwin. |
| 538 extern "C" void ProfileHandlerRegisterThread() { | 497 extern "C" void ProfileHandlerRegisterThread() { |
| 539 } | 498 } |
| 540 | 499 |
| 500 extern "C" void ProfileHandlerUnregisterThread() { |
| 501 } |
| 502 |
| 541 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( | 503 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( |
| 542 ProfileHandlerCallback callback, void* callback_arg) { | 504 ProfileHandlerCallback callback, void* callback_arg) { |
| 543 return NULL; | 505 return NULL; |
| 544 } | 506 } |
| 545 | 507 |
| 546 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { | 508 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { |
| 547 } | 509 } |
| 548 | 510 |
| 549 extern "C" void ProfileHandlerReset() { | 511 extern "C" void ProfileHandlerReset() { |
| 550 } | 512 } |
| 551 | 513 |
| 552 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { | 514 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { |
| 553 } | 515 } |
| 554 | 516 |
| 555 #endif // OS_CYGWIN | 517 #endif // OS_CYGWIN |
| OLD | NEW |