1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2 // Copyright (c) 2009, Google Inc.
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // ---
32 // Author: Sanjay Ghemawat
33 //         Nabeel Mian
34 //
35 // Implements management of profile timers and the corresponding signal handler.
36 
37 #include "config.h"
38 #include "profile-handler.h"
39 
40 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
41 
42 #include <stdio.h>
43 #include <errno.h>
44 #include <sys/time.h>
45 
46 #include <list>
47 #include <string>
48 
49 #if HAVE_LINUX_SIGEV_THREAD_ID
50 // for timer_{create,settime} and associated typedefs & constants
51 #include <time.h>
52 // for sys_gettid
53 #include "base/linux_syscall_support.h"
54 // for perftools_pthread_key_create
55 #include "maybe_threads.h"
56 #endif
57 
58 #include "base/dynamic_annotations.h"
59 #include "base/googleinit.h"
60 #include "base/logging.h"
61 #include "base/spinlock.h"
62 #include "maybe_threads.h"
63 
64 using std::list;
65 using std::string;
66 
67 // This structure is used by ProfileHandlerRegisterCallback and
68 // ProfileHandlerUnregisterCallback as a handle to a registered callback.
69 struct ProfileHandlerToken {
70   // Sets the callback and associated arg.
ProfileHandlerTokenProfileHandlerToken71   ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg)
72       : callback(cb),
73         callback_arg(cb_arg) {
74   }
75 
76   // Callback function to be invoked on receiving a profile timer interrupt.
77   ProfileHandlerCallback callback;
78   // Argument for the callback function.
79   void* callback_arg;
80 };
81 
82 // Blocks a signal from being delivered to the current thread while the object
83 // is alive. Unblocks it upon destruction.
84 class ScopedSignalBlocker {
85  public:
ScopedSignalBlocker(int signo)86   ScopedSignalBlocker(int signo) {
87     sigemptyset(&sig_set_);
88     sigaddset(&sig_set_, signo);
89     RAW_CHECK(sigprocmask(SIG_BLOCK, &sig_set_, NULL) == 0,
90               "sigprocmask (block)");
91   }
~ScopedSignalBlocker()92   ~ScopedSignalBlocker() {
93     RAW_CHECK(sigprocmask(SIG_UNBLOCK, &sig_set_, NULL) == 0,
94               "sigprocmask (unblock)");
95   }
96 
97  private:
98   sigset_t sig_set_;
99 };
100 
101 // This class manages profile timers and associated signal handler. This is a
102 // a singleton.
103 class ProfileHandler {
104  public:
105   // Registers the current thread with the profile handler.
106   void RegisterThread();
107 
108   // Registers a callback routine to receive profile timer ticks. The returned
109   // token is to be used when unregistering this callback and must not be
110   // deleted by the caller.
111   ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
112                                         void* callback_arg);
113 
114   // Unregisters a previously registered callback. Expects the token returned
115   // by the corresponding RegisterCallback routine.
116   void UnregisterCallback(ProfileHandlerToken* token)
117       NO_THREAD_SAFETY_ANALYSIS;
118 
119   // Unregisters all the callbacks and stops the timer(s).
120   void Reset();
121 
122   // Gets the current state of profile handler.
123   void GetState(ProfileHandlerState* state);
124 
125   // Initializes and returns the ProfileHandler singleton.
126   static ProfileHandler* Instance();
127 
128  private:
129   ProfileHandler();
130   ~ProfileHandler();
131 
132   // Largest allowed frequency.
133   static const int32 kMaxFrequency = 4000;
134   // Default frequency.
135   static const int32 kDefaultFrequency = 100;
136 
137   // ProfileHandler singleton.
138   static ProfileHandler* instance_;
139 
140   // pthread_once_t for one time initialization of ProfileHandler singleton.
141   static pthread_once_t once_;
142 
143   // Initializes the ProfileHandler singleton via GoogleOnceInit.
144   static void Init();
145 
146   // Timer state as configured previously.
147   bool timer_running_;
148 
149   // The number of profiling signal interrupts received.
150   int64 interrupts_ GUARDED_BY(signal_lock_);
151 
152   // Profiling signal interrupt frequency, read-only after construction.
153   int32 frequency_;
154 
155   // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM).
156   // Translated into an equivalent choice of clock if per_thread_timer_enabled_
157   // is true.
158   int timer_type_;
159 
160   // Signal number for timer signal.
161   int signal_number_;
162 
163   // Counts the number of callbacks registered.
164   int32 callback_count_ GUARDED_BY(control_lock_);
165 
166   // Is profiling allowed at all?
167   bool allowed_;
168 
169   // Must be false if HAVE_LINUX_SIGEV_THREAD_ID is not defined.
170   bool per_thread_timer_enabled_;
171 
172 #ifdef HAVE_LINUX_SIGEV_THREAD_ID
173   // this is used to destroy per-thread profiling timers on thread
174   // termination
175   pthread_key_t thread_timer_key;
176 #endif
177 
178   // This lock serializes the registration of threads and protects the
179   // callbacks_ list below.
180   // Locking order:
181   // In the context of a signal handler, acquire signal_lock_ to walk the
182   // callback list. Otherwise, acquire control_lock_, disable the signal
183   // handler and then acquire signal_lock_.
184   SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
185   SpinLock signal_lock_;
186 
187   // Holds the list of registered callbacks. We expect the list to be pretty
188   // small. Currently, the cpu profiler (base/profiler) and thread module
189   // (base/thread.h) are the only two components registering callbacks.
190   // Following are the locking requirements for callbacks_:
191   // For read-write access outside the SIGPROF handler:
192   //  - Acquire control_lock_
193   //  - Disable SIGPROF handler.
194   //  - Acquire signal_lock_
195   // For read-only access in the context of SIGPROF handler
196   // (Read-write access is *not allowed* in the SIGPROF handler)
197   //  - Acquire signal_lock_
198   // For read-only access outside SIGPROF handler:
199   //  - Acquire control_lock_
200   typedef list<ProfileHandlerToken*> CallbackList;
201   typedef CallbackList::iterator CallbackIterator;
202   CallbackList callbacks_ GUARDED_BY(signal_lock_);
203 
204   // Starts or stops the interval timer.
205   // Will ignore any requests to enable or disable when
206   // per_thread_timer_enabled_ is true.
207   void UpdateTimer(bool enable) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_);
208 
209   // Returns true if the handler is not being used by something else.
210   // This checks the kernel's signal handler table.
211   bool IsSignalHandlerAvailable();
212 
213   // Signal handler. Iterates over and calls all the registered callbacks.
214   static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);
215 
216   DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
217 };
218 
219 ProfileHandler* ProfileHandler::instance_ = NULL;
220 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT;
221 
222 const int32 ProfileHandler::kMaxFrequency;
223 const int32 ProfileHandler::kDefaultFrequency;
224 
225 // If we are LD_PRELOAD-ed against a non-pthreads app, then these functions
226 // won't be defined.  We declare them here, for that case (with weak linkage)
227 // which will cause the non-definition to resolve to NULL.  We can then check
228 // for NULL or not in Instance.
229 extern "C" {
230 int pthread_once(pthread_once_t *, void (*)(void)) ATTRIBUTE_WEAK;
231 int pthread_kill(pthread_t thread_id, int signo) ATTRIBUTE_WEAK;
232 
233 #if HAVE_LINUX_SIGEV_THREAD_ID
234 int timer_create(clockid_t clockid, struct sigevent* evp,
235                  timer_t* timerid) ATTRIBUTE_WEAK;
236 int timer_delete(timer_t timerid) ATTRIBUTE_WEAK;
237 int timer_settime(timer_t timerid, int flags, const struct itimerspec* value,
238                   struct itimerspec* ovalue) ATTRIBUTE_WEAK;
239 #endif
240 }
241 
242 #if HAVE_LINUX_SIGEV_THREAD_ID
243 
244 struct timer_id_holder {
245   timer_t timerid;
timer_id_holdertimer_id_holder246   timer_id_holder(timer_t _timerid) : timerid(_timerid) {}
247 };
248 
249 extern "C" {
ThreadTimerDestructor(void * arg)250   static void ThreadTimerDestructor(void *arg) {
251     if (!arg) {
252       return;
253     }
254     timer_id_holder *holder = static_cast<timer_id_holder *>(arg);
255     timer_delete(holder->timerid);
256     delete holder;
257   }
258 }
259 
CreateThreadTimerKey(pthread_key_t * pkey)260 static void CreateThreadTimerKey(pthread_key_t *pkey) {
261   int rv = perftools_pthread_key_create(pkey, ThreadTimerDestructor);
262   if (rv) {
263     RAW_LOG(FATAL, "aborting due to pthread_key_create error: %s", strerror(rv));
264   }
265 }
266 
StartLinuxThreadTimer(int timer_type,int signal_number,int32 frequency,pthread_key_t timer_key)267 static void StartLinuxThreadTimer(int timer_type, int signal_number,
268                                   int32 frequency, pthread_key_t timer_key) {
269   int rv;
270   struct sigevent sevp;
271   timer_t timerid;
272   struct itimerspec its;
273   memset(&sevp, 0, sizeof(sevp));
274   sevp.sigev_notify = SIGEV_THREAD_ID;
275   sevp._sigev_un._tid = sys_gettid();
276   sevp.sigev_signo = signal_number;
277   clockid_t clock = CLOCK_THREAD_CPUTIME_ID;
278   if (timer_type == ITIMER_REAL) {
279     clock = CLOCK_MONOTONIC;
280   }
281   rv = timer_create(clock, &sevp, &timerid);
282   if (rv) {
283     RAW_LOG(FATAL, "aborting due to timer_create error: %s", strerror(errno));
284   }
285 
286   timer_id_holder *holder = new timer_id_holder(timerid);
287   rv = perftools_pthread_setspecific(timer_key, holder);
288   if (rv) {
289     RAW_LOG(FATAL, "aborting due to pthread_setspecific error: %s", strerror(rv));
290   }
291 
292   its.it_interval.tv_sec = 0;
293   its.it_interval.tv_nsec = 1000000000 / frequency;
294   its.it_value = its.it_interval;
295   rv = timer_settime(timerid, 0, &its, 0);
296   if (rv) {
297     RAW_LOG(FATAL, "aborting due to timer_settime error: %s", strerror(errno));
298   }
299 }
300 #endif
301 
Init()302 void ProfileHandler::Init() {
303   instance_ = new ProfileHandler();
304 }
305 
Instance()306 ProfileHandler* ProfileHandler::Instance() {
307   if (pthread_once) {
308     pthread_once(&once_, Init);
309   }
310   if (instance_ == NULL) {
311     // This will be true on systems that don't link in pthreads,
312     // including on FreeBSD where pthread_once has a non-zero address
313     // (but doesn't do anything) even when pthreads isn't linked in.
314     Init();
315     assert(instance_ != NULL);
316   }
317   return instance_;
318 }
319 
ProfileHandler()320 ProfileHandler::ProfileHandler()
321     : timer_running_(false),
322       interrupts_(0),
323       callback_count_(0),
324       allowed_(true),
325       per_thread_timer_enabled_(false) {
326   SpinLockHolder cl(&control_lock_);
327 
328   timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
329   signal_number_ = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
330 
331   // Get frequency of interrupts (if specified)
332   char junk;
333   const char* fr = getenv("CPUPROFILE_FREQUENCY");
334   if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
335       (frequency_ > 0)) {
336     // Limit to kMaxFrequency
337     frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
338   } else {
339     frequency_ = kDefaultFrequency;
340   }
341 
342   if (!allowed_) {
343     return;
344   }
345 
346 #if HAVE_LINUX_SIGEV_THREAD_ID
347   // Do this early because we might be overriding signal number.
348 
349   const char *per_thread = getenv("CPUPROFILE_PER_THREAD_TIMERS");
350   const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
351 
352   if (per_thread || signal_number) {
353     if (timer_create && pthread_once) {
354       CreateThreadTimerKey(&thread_timer_key);
355       per_thread_timer_enabled_ = true;
356       // Override signal number if requested.
357       if (signal_number) {
358         signal_number_ = strtol(signal_number, NULL, 0);
359       }
360     } else {
361       RAW_LOG(INFO,
362               "Ignoring CPUPROFILE_PER_THREAD_TIMERS and\n"
363               " CPUPROFILE_TIMER_SIGNAL due to lack of timer_create().\n"
364               " Preload or link to librt.so for this to work");
365     }
366   }
367 #endif
368 
369   // If something else is using the signal handler,
370   // assume it has priority over us and stop.
371   if (!IsSignalHandlerAvailable()) {
372     RAW_LOG(INFO, "Disabling profiler because signal %d handler is already in use.",
373             signal_number_);
374     allowed_ = false;
375     return;
376   }
377 
378   // Install the signal handler.
379   struct sigaction sa;
380   sa.sa_sigaction = SignalHandler;
381   sa.sa_flags = SA_RESTART | SA_SIGINFO;
382   sigemptyset(&sa.sa_mask);
383   RAW_CHECK(sigaction(signal_number_, &sa, NULL) == 0, "sigprof (enable)");
384 }
385 
~ProfileHandler()386 ProfileHandler::~ProfileHandler() {
387   Reset();
388 #ifdef HAVE_LINUX_SIGEV_THREAD_ID
389   if (per_thread_timer_enabled_) {
390     perftools_pthread_key_delete(thread_timer_key);
391   }
392 #endif
393 }
394 
RegisterThread()395 void ProfileHandler::RegisterThread() {
396   SpinLockHolder cl(&control_lock_);
397 
398   if (!allowed_) {
399     return;
400   }
401 
402   // Record the thread identifier and start the timer if profiling is on.
403   ScopedSignalBlocker block(signal_number_);
404   SpinLockHolder sl(&signal_lock_);
405 #if HAVE_LINUX_SIGEV_THREAD_ID
406   if (per_thread_timer_enabled_) {
407     StartLinuxThreadTimer(timer_type_, signal_number_, frequency_,
408                           thread_timer_key);
409     return;
410   }
411 #endif
412   UpdateTimer(callback_count_ > 0);
413 }
414 
RegisterCallback(ProfileHandlerCallback callback,void * callback_arg)415 ProfileHandlerToken* ProfileHandler::RegisterCallback(
416     ProfileHandlerCallback callback, void* callback_arg) {
417 
418   ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
419 
420   SpinLockHolder cl(&control_lock_);
421   {
422     ScopedSignalBlocker block(signal_number_);
423     SpinLockHolder sl(&signal_lock_);
424     callbacks_.push_back(token);
425     ++callback_count_;
426     UpdateTimer(true);
427   }
428   return token;
429 }
430 
UnregisterCallback(ProfileHandlerToken * token)431 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
432   SpinLockHolder cl(&control_lock_);
433   for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end();
434        ++it) {
435     if ((*it) == token) {
436       RAW_CHECK(callback_count_ > 0, "Invalid callback count");
437       {
438         ScopedSignalBlocker block(signal_number_);
439         SpinLockHolder sl(&signal_lock_);
440         delete *it;
441         callbacks_.erase(it);
442         --callback_count_;
443         if (callback_count_ == 0)
444           UpdateTimer(false);
445       }
446       return;
447     }
448   }
449   // Unknown token.
450   RAW_LOG(FATAL, "Invalid token");
451 }
452 
Reset()453 void ProfileHandler::Reset() {
454   SpinLockHolder cl(&control_lock_);
455   {
456     ScopedSignalBlocker block(signal_number_);
457     SpinLockHolder sl(&signal_lock_);
458     CallbackIterator it = callbacks_.begin();
459     while (it != callbacks_.end()) {
460       CallbackIterator tmp = it;
461       ++it;
462       delete *tmp;
463       callbacks_.erase(tmp);
464     }
465     callback_count_ = 0;
466     UpdateTimer(false);
467   }
468 }
469 
GetState(ProfileHandlerState * state)470 void ProfileHandler::GetState(ProfileHandlerState* state) {
471   SpinLockHolder cl(&control_lock_);
472   {
473     ScopedSignalBlocker block(signal_number_);
474     SpinLockHolder sl(&signal_lock_);  // Protects interrupts_.
475     state->interrupts = interrupts_;
476   }
477   state->frequency = frequency_;
478   state->callback_count = callback_count_;
479   state->allowed = allowed_;
480 }
481 
UpdateTimer(bool enable)482 void ProfileHandler::UpdateTimer(bool enable) {
483   if (per_thread_timer_enabled_) {
484     // Ignore any attempts to disable it because that's not supported, and it's
485     // always enabled so enabling is always a NOP.
486     return;
487   }
488 
489   if (enable == timer_running_) {
490     return;
491   }
492   timer_running_ = enable;
493 
494   struct itimerval timer;
495   static const int kMillion = 1000000;
496   int interval_usec = enable ? kMillion / frequency_ : 0;
497   timer.it_interval.tv_sec = interval_usec / kMillion;
498   timer.it_interval.tv_usec = interval_usec % kMillion;
499   timer.it_value = timer.it_interval;
500   setitimer(timer_type_, &timer, 0);
501 }
502 
IsSignalHandlerAvailable()503 bool ProfileHandler::IsSignalHandlerAvailable() {
504   struct sigaction sa;
505   RAW_CHECK(sigaction(signal_number_, NULL, &sa) == 0, "is-signal-handler avail");
506 
507   // We only take over the handler if the current one is unset.
508   // It must be SIG_IGN or SIG_DFL, not some other function.
509   // SIG_IGN must be allowed because when profiling is allowed but
510   // not actively in use, this code keeps the handler set to SIG_IGN.
511   // That setting will be inherited across fork+exec.  In order for
512   // any child to be able to use profiling, SIG_IGN must be treated
513   // as available.
514   return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
515 }
516 
SignalHandler(int sig,siginfo_t * sinfo,void * ucontext)517 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
518   int saved_errno = errno;
519   // At this moment, instance_ must be initialized because the handler is
520   // enabled in RegisterThread or RegisterCallback only after
521   // ProfileHandler::Instance runs.
522   ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_);
523   RAW_CHECK(instance != NULL, "ProfileHandler is not initialized");
524   {
525     SpinLockHolder sl(&instance->signal_lock_);
526     ++instance->interrupts_;
527     for (CallbackIterator it = instance->callbacks_.begin();
528          it != instance->callbacks_.end();
529          ++it) {
530       (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
531     }
532   }
533   errno = saved_errno;
534 }
535 
536 // This module initializer registers the main thread, so it must be
537 // executed in the context of the main thread.
538 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());
539 
ProfileHandlerRegisterThread()540 void ProfileHandlerRegisterThread() {
541   ProfileHandler::Instance()->RegisterThread();
542 }
543 
ProfileHandlerRegisterCallback(ProfileHandlerCallback callback,void * callback_arg)544 ProfileHandlerToken* ProfileHandlerRegisterCallback(
545     ProfileHandlerCallback callback, void* callback_arg) {
546   return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
547 }
548 
ProfileHandlerUnregisterCallback(ProfileHandlerToken * token)549 void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
550   ProfileHandler::Instance()->UnregisterCallback(token);
551 }
552 
ProfileHandlerReset()553 void ProfileHandlerReset() {
554   return ProfileHandler::Instance()->Reset();
555 }
556 
ProfileHandlerGetState(ProfileHandlerState * state)557 void ProfileHandlerGetState(ProfileHandlerState* state) {
558   ProfileHandler::Instance()->GetState(state);
559 }
560 
561 #else  // OS_CYGWIN
562 
563 // ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
564 // work as well for profiling, and also interferes with alarm().  Because of
565 // these issues, unless a specific need is identified, profiler support is
566 // disabled under Cygwin.
ProfileHandlerRegisterThread()567 void ProfileHandlerRegisterThread() {
568 }
569 
ProfileHandlerRegisterCallback(ProfileHandlerCallback callback,void * callback_arg)570 ProfileHandlerToken* ProfileHandlerRegisterCallback(
571     ProfileHandlerCallback callback, void* callback_arg) {
572   return NULL;
573 }
574 
ProfileHandlerUnregisterCallback(ProfileHandlerToken * token)575 void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
576 }
577 
ProfileHandlerReset()578 void ProfileHandlerReset() {
579 }
580 
ProfileHandlerGetState(ProfileHandlerState * state)581 void ProfileHandlerGetState(ProfileHandlerState* state) {
582 }
583 
584 #endif  // OS_CYGWIN
585