blob: 66c9d74e4a03c504f0c7bafe200ed76af5d18dd2 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- 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
64using std::list;
65using std::string;
66
67// This structure is used by ProfileHandlerRegisterCallback and
68// ProfileHandlerUnregisterCallback as a handle to a registered callback.
69struct ProfileHandlerToken {
70 // Sets the callback and associated arg.
71 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// This class manages profile timers and associated signal handler. This is a
83// a singleton.
84class ProfileHandler {
85 public:
86 // Registers the current thread with the profile handler. On systems which
87 // have a separate interval timer for each thread, this function starts the
88 // timer for the current thread.
89 //
90 // The function also attempts to determine whether or not timers are shared by
91 // all threads in the process. (With LinuxThreads, and with NPTL on some
92 // Linux kernel versions, each thread has separate timers.)
93 //
94 // Prior to determining whether timers are shared, this function will
95 // unconditionally start the timer. However, if this function determines
96 // that timers are shared, then it will stop the timer if no callbacks are
97 // currently registered.
98 void RegisterThread();
99
100 // Registers a callback routine to receive profile timer ticks. The returned
101 // token is to be used when unregistering this callback and must not be
102 // deleted by the caller. Registration of the first callback enables the
103 // SIGPROF handler (or SIGALRM if using ITIMER_REAL).
104 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
105 void* callback_arg);
106
107 // Unregisters a previously registered callback. Expects the token returned
108 // by the corresponding RegisterCallback routine. Unregistering the last
109 // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL).
110 void UnregisterCallback(ProfileHandlerToken* token)
111 NO_THREAD_SAFETY_ANALYSIS;
112
113 // Unregisters all the callbacks, stops the timer if shared, disables the
114 // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state.
115 void Reset();
116
117 // Gets the current state of profile handler.
118 void GetState(ProfileHandlerState* state);
119
120 // Initializes and returns the ProfileHandler singleton.
121 static ProfileHandler* Instance();
122
123 private:
124 ProfileHandler();
125 ~ProfileHandler();
126
127 // Largest allowed frequency.
128 static const int32 kMaxFrequency = 4000;
129 // Default frequency.
130 static const int32 kDefaultFrequency = 100;
131
132 // ProfileHandler singleton.
133 static ProfileHandler* instance_;
134
135 // pthread_once_t for one time initialization of ProfileHandler singleton.
136 static pthread_once_t once_;
137
138 // Initializes the ProfileHandler singleton via GoogleOnceInit.
139 static void Init();
140
141 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received.
142 int64 interrupts_ GUARDED_BY(signal_lock_);
143
144 // SIGPROF/SIGALRM interrupt frequency, read-only after construction.
145 int32 frequency_;
146
147 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM)
148 int timer_type_;
149
150 // Signal number for timer signal.
151 int signal_number_;
152
153 // Counts the number of callbacks registered.
154 int32 callback_count_ GUARDED_BY(control_lock_);
155
156 // Is profiling allowed at all?
157 bool allowed_;
158
159 bool per_thread_timer_enabled_;
160
161#ifdef HAVE_LINUX_SIGEV_THREAD_ID
162 // this is used to destroy per-thread profiling timers on thread
163 // termination
164 pthread_key_t thread_timer_key;
165#endif
166
167 // Whether or not the threading system provides interval timers that are
168 // shared by all threads in a process.
169 enum {
170 // No timer initialization attempted yet.
171 TIMERS_UNTOUCHED,
172 // First thread has registered and set timer.
173 TIMERS_ONE_SET,
174 // Timers are shared by all threads.
175 TIMERS_SHARED,
176 // Timers are separate in each thread.
177 TIMERS_SEPARATE
178 } timer_sharing_ GUARDED_BY(control_lock_);
179
180 // This lock serializes the registration of threads and protects the
181 // callbacks_ list below.
182 // Locking order:
183 // In the context of a signal handler, acquire signal_lock_ to walk the
184 // callback list. Otherwise, acquire control_lock_, disable the signal
185 // handler and then acquire signal_lock_.
186 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
187 SpinLock signal_lock_;
188
189 // Holds the list of registered callbacks. We expect the list to be pretty
190 // small. Currently, the cpu profiler (base/profiler) and thread module
191 // (base/thread.h) are the only two components registering callbacks.
192 // Following are the locking requirements for callbacks_:
193 // For read-write access outside the SIGPROF handler:
194 // - Acquire control_lock_
195 // - Disable SIGPROF handler.
196 // - Acquire signal_lock_
197 // For read-only access in the context of SIGPROF handler
198 // (Read-write access is *not allowed* in the SIGPROF handler)
199 // - Acquire signal_lock_
200 // For read-only access outside SIGPROF handler:
201 // - Acquire control_lock_
202 typedef list<ProfileHandlerToken*> CallbackList;
203 typedef CallbackList::iterator CallbackIterator;
204 CallbackList callbacks_ GUARDED_BY(signal_lock_);
205
206 // Starts the interval timer. If the thread library shares timers between
207 // threads, this function starts the shared timer. Otherwise, this will start
208 // the timer in the current thread.
209 void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
210
211 // Stops the interval timer. If the thread library shares timers between
212 // threads, this fucntion stops the shared timer. Otherwise, this will stop
213 // the timer in the current thread.
214 void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
215
216 // Returns true if the profile interval timer is enabled in the current
217 // thread. This actually checks the kernel's interval timer setting. (It is
218 // used to detect whether timers are shared or separate.)
219 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
220
221 // Sets the timer interrupt signal handler.
222 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
223
224 // Disables (ignores) the timer interrupt signal.
225 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
226
227 // Returns true if the handler is not being used by something else.
228 // This checks the kernel's signal handler table.
229 bool IsSignalHandlerAvailable();
230
231 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks.
232 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);
233
234 DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
235};
236
237ProfileHandler* ProfileHandler::instance_ = NULL;
238pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT;
239
240const int32 ProfileHandler::kMaxFrequency;
241const int32 ProfileHandler::kDefaultFrequency;
242
243// If we are LD_PRELOAD-ed against a non-pthreads app, then
244// pthread_once won't be defined. We declare it here, for that
245// case (with weak linkage) which will cause the non-definition to
246// resolve to NULL. We can then check for NULL or not in Instance.
247extern "C" int pthread_once(pthread_once_t *, void (*)(void))
248 ATTRIBUTE_WEAK;
249
250#if HAVE_LINUX_SIGEV_THREAD_ID
251
252// We use weak alias to timer_create to avoid runtime dependency on
253// -lrt and in turn -lpthread.
254//
255// At runtime we detect if timer_create is available and if so we
256// can enable linux-sigev-thread mode of profiling
257extern "C" {
258 int timer_create(clockid_t clockid, struct sigevent *evp,
259 timer_t *timerid)
260 ATTRIBUTE_WEAK;
261 int timer_delete(timer_t timerid)
262 ATTRIBUTE_WEAK;
263 int timer_settime(timer_t timerid, int flags,
264 const struct itimerspec *value,
265 struct itimerspec *ovalue)
266 ATTRIBUTE_WEAK;
267}
268
269struct timer_id_holder {
270 timer_t timerid;
271 timer_id_holder(timer_t _timerid) : timerid(_timerid) {}
272};
273
274extern "C" {
275 static void ThreadTimerDestructor(void *arg) {
276 if (!arg) {
277 return;
278 }
279 timer_id_holder *holder = static_cast<timer_id_holder *>(arg);
280 timer_delete(holder->timerid);
281 delete holder;
282 }
283}
284
285static void CreateThreadTimerKey(pthread_key_t *pkey) {
286 int rv = perftools_pthread_key_create(pkey, ThreadTimerDestructor);
287 if (rv) {
288 RAW_LOG(FATAL, "aborting due to pthread_key_create error: %s", strerror(rv));
289 }
290}
291
292static void StartLinuxThreadTimer(int timer_type, int signal_number,
293 int32 frequency, pthread_key_t timer_key) {
294 int rv;
295 struct sigevent sevp;
296 timer_t timerid;
297 struct itimerspec its;
298 memset(&sevp, 0, sizeof(sevp));
299 sevp.sigev_notify = SIGEV_THREAD_ID;
300 sevp._sigev_un._tid = sys_gettid();
301 sevp.sigev_signo = signal_number;
302 clockid_t clock = CLOCK_THREAD_CPUTIME_ID;
303 if (timer_type == ITIMER_REAL) {
304 clock = CLOCK_MONOTONIC;
305 }
306 rv = timer_create(clock, &sevp, &timerid);
307 if (rv) {
308 RAW_LOG(FATAL, "aborting due to timer_create error: %s", strerror(errno));
309 }
310
311 timer_id_holder *holder = new timer_id_holder(timerid);
312 rv = perftools_pthread_setspecific(timer_key, holder);
313 if (rv) {
314 RAW_LOG(FATAL, "aborting due to pthread_setspecific error: %s", strerror(rv));
315 }
316
317 its.it_interval.tv_sec = 0;
318 its.it_interval.tv_nsec = 1000000000 / frequency;
319 its.it_value = its.it_interval;
320 rv = timer_settime(timerid, 0, &its, 0);
321 if (rv) {
322 RAW_LOG(FATAL, "aborting due to timer_settime error: %s", strerror(errno));
323 }
324}
325#endif
326
327void ProfileHandler::Init() {
328 instance_ = new ProfileHandler();
329}
330
331ProfileHandler* ProfileHandler::Instance() {
332 if (pthread_once) {
333 pthread_once(&once_, Init);
334 }
335 if (instance_ == NULL) {
336 // This will be true on systems that don't link in pthreads,
337 // including on FreeBSD where pthread_once has a non-zero address
338 // (but doesn't do anything) even when pthreads isn't linked in.
339 Init();
340 assert(instance_ != NULL);
341 }
342 return instance_;
343}
344
345ProfileHandler::ProfileHandler()
346 : interrupts_(0),
347 callback_count_(0),
348 allowed_(true),
349 per_thread_timer_enabled_(false),
350 timer_sharing_(TIMERS_UNTOUCHED) {
351 SpinLockHolder cl(&control_lock_);
352
353 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
354 signal_number_ = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
355
356 // Get frequency of interrupts (if specified)
357 char junk;
358 const char* fr = getenv("CPUPROFILE_FREQUENCY");
359 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
360 (frequency_ > 0)) {
361 // Limit to kMaxFrequency
362 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
363 } else {
364 frequency_ = kDefaultFrequency;
365 }
366
367 if (!allowed_) {
368 return;
369 }
370
371#if HAVE_LINUX_SIGEV_THREAD_ID
372 // Do this early because we might be overriding signal number.
373
374 const char *per_thread = getenv("CPUPROFILE_PER_THREAD_TIMERS");
375 const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
376
377 if (per_thread || signal_number) {
378 if (timer_create && pthread_once) {
379 timer_sharing_ = TIMERS_SEPARATE;
380 CreateThreadTimerKey(&thread_timer_key);
381 per_thread_timer_enabled_ = true;
382 // Override signal number if requested.
383 if (signal_number) {
384 signal_number_ = strtol(signal_number, NULL, 0);
385 }
386 } else {
387 RAW_LOG(INFO,
388 "Ignoring CPUPROFILE_PER_THREAD_TIMERS and\n"
389 " CPUPROFILE_TIMER_SIGNAL due to lack of timer_create().\n"
390 " Preload or link to librt.so for this to work");
391 }
392 }
393#endif
394
395 // If something else is using the signal handler,
396 // assume it has priority over us and stop.
397 if (!IsSignalHandlerAvailable()) {
398 RAW_LOG(INFO, "Disabling profiler because signal %d handler is already in use.",
399 signal_number_);
400 allowed_ = false;
401 return;
402 }
403
404 // Ignore signals until we decide to turn profiling on. (Paranoia;
405 // should already be ignored.)
406 DisableHandler();
407
408}
409
410ProfileHandler::~ProfileHandler() {
411 Reset();
412#ifdef HAVE_LINUX_SIGEV_THREAD_ID
413 if (per_thread_timer_enabled_) {
414 perftools_pthread_key_delete(thread_timer_key);
415 }
416#endif
417}
418
419void ProfileHandler::RegisterThread() {
420 SpinLockHolder cl(&control_lock_);
421
422 if (!allowed_) {
423 return;
424 }
425
426 // We try to detect whether timers are being shared by setting a
427 // timer in the first call to this function, then checking whether
428 // it's set in the second call.
429 //
430 // Note that this detection method requires that the first two calls
431 // to RegisterThread must be made from different threads. (Subsequent
432 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or
433 // TIMERS_SHARED, and won't try to detect the timer sharing type.)
434 //
435 // Also note that if timer settings were inherited across new thread
436 // creation but *not* shared, this approach wouldn't work. That's
437 // not an issue for any Linux threading implementation, and should
438 // not be a problem for a POSIX-compliant threads implementation.
439 switch (timer_sharing_) {
440 case TIMERS_UNTOUCHED:
441 StartTimer();
442 timer_sharing_ = TIMERS_ONE_SET;
443 break;
444 case TIMERS_ONE_SET:
445 // If the timer is running, that means that the main thread's
446 // timer setup is seen in this (second) thread -- and therefore
447 // that timers are shared.
448 if (IsTimerRunning()) {
449 timer_sharing_ = TIMERS_SHARED;
450 // If callback is already registered, we have to keep the timer
451 // running. If not, we disable the timer here.
452 if (callback_count_ == 0) {
453 StopTimer();
454 }
455 } else {
456 timer_sharing_ = TIMERS_SEPARATE;
457 StartTimer();
458 }
459 break;
460 case TIMERS_SHARED:
461 // Nothing needed.
462 break;
463 case TIMERS_SEPARATE:
464 StartTimer();
465 break;
466 }
467}
468
469ProfileHandlerToken* ProfileHandler::RegisterCallback(
470 ProfileHandlerCallback callback, void* callback_arg) {
471
472 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
473
474 SpinLockHolder cl(&control_lock_);
475 DisableHandler();
476 {
477 SpinLockHolder sl(&signal_lock_);
478 callbacks_.push_back(token);
479 }
480 // Start the timer if timer is shared and this is a first callback.
481 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) {
482 StartTimer();
483 }
484 ++callback_count_;
485 EnableHandler();
486 return token;
487}
488
489void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
490 SpinLockHolder cl(&control_lock_);
491 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end();
492 ++it) {
493 if ((*it) == token) {
494 RAW_CHECK(callback_count_ > 0, "Invalid callback count");
495 DisableHandler();
496 {
497 SpinLockHolder sl(&signal_lock_);
498 delete *it;
499 callbacks_.erase(it);
500 }
501 --callback_count_;
502 if (callback_count_ > 0) {
503 EnableHandler();
504 } else if (timer_sharing_ == TIMERS_SHARED) {
505 StopTimer();
506 }
507 return;
508 }
509 }
510 // Unknown token.
511 RAW_LOG(FATAL, "Invalid token");
512}
513
514void ProfileHandler::Reset() {
515 SpinLockHolder cl(&control_lock_);
516 DisableHandler();
517 {
518 SpinLockHolder sl(&signal_lock_);
519 CallbackIterator it = callbacks_.begin();
520 while (it != callbacks_.end()) {
521 CallbackIterator tmp = it;
522 ++it;
523 delete *tmp;
524 callbacks_.erase(tmp);
525 }
526 }
527 callback_count_ = 0;
528 if (timer_sharing_ == TIMERS_SHARED) {
529 StopTimer();
530 }
531 timer_sharing_ = TIMERS_UNTOUCHED;
532}
533
534void ProfileHandler::GetState(ProfileHandlerState* state) {
535 SpinLockHolder cl(&control_lock_);
536 DisableHandler();
537 {
538 SpinLockHolder sl(&signal_lock_); // Protects interrupts_.
539 state->interrupts = interrupts_;
540 }
541 if (callback_count_ > 0) {
542 EnableHandler();
543 }
544 state->frequency = frequency_;
545 state->callback_count = callback_count_;
546 state->allowed = allowed_;
547}
548
549void ProfileHandler::StartTimer() {
550 if (!allowed_) {
551 return;
552 }
553
554#if HAVE_LINUX_SIGEV_THREAD_ID
555 if (per_thread_timer_enabled_) {
556 StartLinuxThreadTimer(timer_type_, signal_number_, frequency_, thread_timer_key);
557 return;
558 }
559#endif
560
561 struct itimerval timer;
562 timer.it_interval.tv_sec = 0;
563 timer.it_interval.tv_usec = 1000000 / frequency_;
564 timer.it_value = timer.it_interval;
565 setitimer(timer_type_, &timer, 0);
566}
567
568void ProfileHandler::StopTimer() {
569 if (!allowed_) {
570 return;
571 }
572 if (per_thread_timer_enabled_) {
573 RAW_LOG(FATAL, "StopTimer cannot be called in linux-per-thread-timers mode");
574 }
575
576 struct itimerval timer;
577 memset(&timer, 0, sizeof timer);
578 setitimer(timer_type_, &timer, 0);
579}
580
581bool ProfileHandler::IsTimerRunning() {
582 if (!allowed_) {
583 return false;
584 }
585 if (per_thread_timer_enabled_) {
586 return false;
587 }
588 struct itimerval current_timer;
589 RAW_CHECK(0 == getitimer(timer_type_, &current_timer), "getitimer");
590 return (current_timer.it_value.tv_sec != 0 ||
591 current_timer.it_value.tv_usec != 0);
592}
593
594void ProfileHandler::EnableHandler() {
595 if (!allowed_) {
596 return;
597 }
598 struct sigaction sa;
599 sa.sa_sigaction = SignalHandler;
600 sa.sa_flags = SA_RESTART | SA_SIGINFO;
601 sigemptyset(&sa.sa_mask);
602 RAW_CHECK(sigaction(signal_number_, &sa, NULL) == 0, "sigprof (enable)");
603}
604
605void ProfileHandler::DisableHandler() {
606 if (!allowed_) {
607 return;
608 }
609 struct sigaction sa;
610 sa.sa_handler = SIG_IGN;
611 sa.sa_flags = SA_RESTART;
612 sigemptyset(&sa.sa_mask);
613 RAW_CHECK(sigaction(signal_number_, &sa, NULL) == 0, "sigprof (disable)");
614}
615
616bool ProfileHandler::IsSignalHandlerAvailable() {
617 struct sigaction sa;
618 RAW_CHECK(sigaction(signal_number_, NULL, &sa) == 0, "is-signal-handler avail");
619
620 // We only take over the handler if the current one is unset.
621 // It must be SIG_IGN or SIG_DFL, not some other function.
622 // SIG_IGN must be allowed because when profiling is allowed but
623 // not actively in use, this code keeps the handler set to SIG_IGN.
624 // That setting will be inherited across fork+exec. In order for
625 // any child to be able to use profiling, SIG_IGN must be treated
626 // as available.
627 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
628}
629
630void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
631 int saved_errno = errno;
632 // At this moment, instance_ must be initialized because the handler is
633 // enabled in RegisterThread or RegisterCallback only after
634 // ProfileHandler::Instance runs.
635 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_);
636 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized");
637 {
638 SpinLockHolder sl(&instance->signal_lock_);
639 ++instance->interrupts_;
640 for (CallbackIterator it = instance->callbacks_.begin();
641 it != instance->callbacks_.end();
642 ++it) {
643 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
644 }
645 }
646 errno = saved_errno;
647}
648
649// This module initializer registers the main thread, so it must be
650// executed in the context of the main thread.
651REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());
652
653extern "C" void ProfileHandlerRegisterThread() {
654 ProfileHandler::Instance()->RegisterThread();
655}
656
657extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
658 ProfileHandlerCallback callback, void* callback_arg) {
659 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
660}
661
662extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
663 ProfileHandler::Instance()->UnregisterCallback(token);
664}
665
666extern "C" void ProfileHandlerReset() {
667 return ProfileHandler::Instance()->Reset();
668}
669
670extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
671 ProfileHandler::Instance()->GetState(state);
672}
673
674#else // OS_CYGWIN
675
676// ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
677// work as well for profiling, and also interferes with alarm(). Because of
678// these issues, unless a specific need is identified, profiler support is
679// disabled under Cygwin.
680extern "C" void ProfileHandlerRegisterThread() {
681}
682
683extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
684 ProfileHandlerCallback callback, void* callback_arg) {
685 return NULL;
686}
687
688extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
689}
690
691extern "C" void ProfileHandlerReset() {
692}
693
694extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
695}
696
697#endif // OS_CYGWIN