15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2009, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Sanjay Ghemawat 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Nabeel Mian 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements management of profile timers and the corresponding signal handler. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "profile-handler.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/time.h> 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <list> 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/dynamic_annotations.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/googleinit.h" 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/spinlock.h" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "maybe_threads.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::list; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This structure is used by ProfileHandlerRegisterCallback and 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ProfileHandlerUnregisterCallback as a handle to a registered callback. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ProfileHandlerToken { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets the callback and associated arg. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : callback(cb), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_arg(cb_arg) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback function to be invoked on receiving a profile timer interrupt. 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerCallback callback; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Argument for the callback function. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* callback_arg; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class manages profile timers and associated signal handler. This is a 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a singleton. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProfileHandler { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Registers the current thread with the profile handler. On systems which 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a separate interval timer for each thread, this function starts the 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timer for the current thread. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The function also attempts to determine whether or not timers are shared by 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // all threads in the process. (With LinuxThreads, and with NPTL on some 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Linux kernel versions, each thread has separate timers.) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Prior to determining whether timers are shared, this function will 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unconditionally start the timer. However, if this function determines 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that timers are shared, then it will stop the timer if no callbacks are 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // currently registered. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RegisterThread(); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Registers a callback routine to receive profile timer ticks. The returned 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // token is to be used when unregistering this callback and must not be 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deleted by the caller. Registration of the first callback enables the 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SIGPROF handler (or SIGALRM if using ITIMER_REAL). 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* callback_arg); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unregisters a previously registered callback. Expects the token returned 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // by the corresponding RegisterCallback routine. Unregistering the last 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL). 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void UnregisterCallback(ProfileHandlerToken* token) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NO_THREAD_SAFETY_ANALYSIS; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unregisters all the callbacks, stops the timer if shared, disables the 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Reset(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gets the current state of profile handler. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void GetState(ProfileHandlerState* state); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes and returns the ProfileHandler singleton. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static ProfileHandler* Instance(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandler(); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~ProfileHandler(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Largest allowed frequency. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int32 kMaxFrequency = 4000; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Default frequency. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int32 kDefaultFrequency = 100; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ProfileHandler singleton. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static ProfileHandler* instance_; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pthread_once_t for one time initialization of ProfileHandler singleton. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static pthread_once_t once_; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initializes the ProfileHandler singleton via GoogleOnceInit. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Init(); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 interrupts_ GUARDED_BY(signal_lock_); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SIGPROF/SIGALRM interrupt frequency, read-only after construction. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 frequency_; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int timer_type_; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Counts the number of callbacks registered. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 callback_count_ GUARDED_BY(control_lock_); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Is profiling allowed at all? 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool allowed_; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Whether or not the threading system provides interval timers that are 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // shared by all threads in a process. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No timer initialization attempted yet. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIMERS_UNTOUCHED, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First thread has registered and set timer. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIMERS_ONE_SET, 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Timers are shared by all threads. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIMERS_SHARED, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Timers are separate in each thread. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TIMERS_SEPARATE 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } timer_sharing_ GUARDED_BY(control_lock_); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This lock serializes the registration of threads and protects the 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callbacks_ list below. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Locking order: 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the context of a signal handler, acquire signal_lock_ to walk the 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // callback list. Otherwise, acquire control_lock_, disable the signal 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handler and then acquire signal_lock_. 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLock signal_lock_; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Holds the list of registered callbacks. We expect the list to be pretty 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // small. Currently, the cpu profiler (base/profiler) and thread module 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (base/thread.h) are the only two components registering callbacks. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Following are the locking requirements for callbacks_: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For read-write access outside the SIGPROF handler: 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - Acquire control_lock_ 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - Disable SIGPROF handler. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - Acquire signal_lock_ 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For read-only access in the context of SIGPROF handler 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (Read-write access is *not allowed* in the SIGPROF handler) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - Acquire signal_lock_ 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For read-only access outside SIGPROF handler: 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // - Acquire control_lock_ 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef list<ProfileHandlerToken*> CallbackList; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef CallbackList::iterator CallbackIterator; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CallbackList callbacks_ GUARDED_BY(signal_lock_); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Starts the interval timer. If the thread library shares timers between 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // threads, this function starts the shared timer. Otherwise, this will start 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the timer in the current thread. 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stops the interval timer. If the thread library shares timers between 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // threads, this fucntion stops the shared timer. Otherwise, this will stop 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the timer in the current thread. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if the profile interval timer is enabled in the current 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread. This actually checks the kernel's interval timer setting. (It is 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used to detect whether timers are shared or separate.) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets the timer interrupt signal handler. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Disables (ignores) the timer interrupt signal. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if the handler is not being used by something else. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This checks the kernel's signal handler table. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool IsSignalHandlerAvailable(); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ProfileHandler); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileHandler* ProfileHandler::instance_ = NULL; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int32 ProfileHandler::kMaxFrequency; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int32 ProfileHandler::kDefaultFrequency; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If we are LD_PRELOAD-ed against a non-pthreads app, then 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pthread_once won't be defined. We declare it here, for that 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// case (with weak linkage) which will cause the non-definition to 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resolve to NULL. We can then check for NULL or not in Instance. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int pthread_once(pthread_once_t *, void (*)(void)) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ATTRIBUTE_WEAK; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::Init() { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance_ = new ProfileHandler(); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileHandler* ProfileHandler::Instance() { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pthread_once) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pthread_once(&once_, Init); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (instance_ == NULL) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This will be true on systems that don't link in pthreads, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // including on FreeBSD where pthread_once has a non-zero address 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (but doesn't do anything) even when pthreads isn't linked in. 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(instance_ != NULL); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return instance_; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileHandler::ProfileHandler() 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : interrupts_(0), 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_count_(0), 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_(true), 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_sharing_(TIMERS_UNTOUCHED) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get frequency of interrupts (if specified) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char junk; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* fr = getenv("CPUPROFILE_FREQUENCY"); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (frequency_ > 0)) { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Limit to kMaxFrequency 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frequency_ = kDefaultFrequency; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If something else is using the signal handler, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // assume it has priority over us and stop. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsSignalHandlerAvailable()) { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allowed_ = false; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore signals until we decide to turn profiling on. (Paranoia; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should already be ignored.) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableHandler(); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileHandler::~ProfileHandler() { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Reset(); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::RegisterThread() { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We try to detect whether timers are being shared by setting a 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timer in the first call to this function, then checking whether 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it's set in the second call. 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that this detection method requires that the first two calls 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to RegisterThread must be made from different threads. (Subsequent 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calls will see timer_sharing_ set to either TIMERS_SEPARATE or 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TIMERS_SHARED, and won't try to detect the timer sharing type.) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Also note that if timer settings were inherited across new thread 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // creation but *not* shared, this approach wouldn't work. That's 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not an issue for any Linux threading implementation, and should 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not be a problem for a POSIX-compliant threads implementation. 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (timer_sharing_) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case TIMERS_UNTOUCHED: 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_sharing_ = TIMERS_ONE_SET; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case TIMERS_ONE_SET: 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the timer is running, that means that the main thread's 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timer setup is seen in this (second) thread -- and therefore 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that timers are shared. 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsTimerRunning()) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_sharing_ = TIMERS_SHARED; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If callback is already registered, we have to keep the timer 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // running. If not, we disable the timer here. 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_count_ == 0) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopTimer(); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_sharing_ = TIMERS_SEPARATE; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case TIMERS_SHARED: 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Nothing needed. 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case TIMERS_SEPARATE: 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProfileHandlerToken* ProfileHandler::RegisterCallback( 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerCallback callback, void* callback_arg) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableHandler(); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder sl(&signal_lock_); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callbacks_.push_back(token); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start the timer if timer is shared and this is a first callback. 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartTimer(); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++callback_count_; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableHandler(); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return token; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end(); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((*it) == token) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(callback_count_ > 0, "Invalid callback count"); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableHandler(); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder sl(&signal_lock_); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete *it; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callbacks_.erase(it); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --callback_count_; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_count_ > 0) { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableHandler(); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (timer_sharing_ == TIMERS_SHARED) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopTimer(); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unknown token. 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_LOG(FATAL, "Invalid token"); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::Reset() { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableHandler(); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder sl(&signal_lock_); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CallbackIterator it = callbacks_.begin(); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it != callbacks_.end()) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CallbackIterator tmp = it; 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete *tmp; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callbacks_.erase(tmp); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_count_ = 0; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (timer_sharing_ == TIMERS_SHARED) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopTimer(); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer_sharing_ = TIMERS_UNTOUCHED; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::GetState(ProfileHandlerState* state) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder cl(&control_lock_); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DisableHandler(); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder sl(&signal_lock_); // Protects interrupts_. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->interrupts = interrupts_; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (callback_count_ > 0) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableHandler(); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->frequency = frequency_; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->callback_count = callback_count_; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->allowed = allowed_; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::StartTimer() { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct itimerval timer; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer.it_interval.tv_sec = 0; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer.it_interval.tv_usec = 1000000 / frequency_; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timer.it_value = timer.it_interval; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setitimer(timer_type_, &timer, 0); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::StopTimer() { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct itimerval timer; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&timer, 0, sizeof timer); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setitimer(timer_type_, &timer, 0); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProfileHandler::IsTimerRunning() { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct itimerval current_timer; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer"); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (current_timer.it_value.tv_sec != 0 || 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_timer.it_value.tv_usec != 0); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::EnableHandler() { 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sigaction sa; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sa.sa_sigaction = SignalHandler; 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sa.sa_flags = SA_RESTART | SA_SIGINFO; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sigemptyset(&sa.sa_mask); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)"); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::DisableHandler() { 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!allowed_) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sigaction sa; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sa.sa_handler = SIG_IGN; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sa.sa_flags = SA_RESTART; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sigemptyset(&sa.sa_mask); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)"); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProfileHandler::IsSignalHandlerAvailable() { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct sigaction sa; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail"); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only take over the handler if the current one is unset. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It must be SIG_IGN or SIG_DFL, not some other function. 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SIG_IGN must be allowed because when profiling is allowed but 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not actively in use, this code keeps the handler set to SIG_IGN. 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // That setting will be inherited across fork+exec. In order for 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any child to be able to use profiling, SIG_IGN must be treated 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as available. 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int saved_errno = errno; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At this moment, instance_ must be initialized because the handler is 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // enabled in RegisterThread or RegisterCallback only after 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ProfileHandler::Instance runs. 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SpinLockHolder sl(&instance->signal_lock_); 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++instance->interrupts_; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (CallbackIterator it = instance->callbacks_.begin(); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != instance->callbacks_.end(); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) errno = saved_errno; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This module initializer registers the main thread, so it must be 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// executed in the context of the main thread. 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerRegisterThread() { 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandler::Instance()->RegisterThread(); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerCallback callback, void* callback_arg) { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandler::Instance()->UnregisterCallback(token); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerReset() { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ProfileHandler::Instance()->Reset(); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandler::Instance()->GetState(state); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else // OS_CYGWIN 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// work as well for profiling, and also interferes with alarm(). Because of 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// these issues, unless a specific need is identified, profiler support is 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disabled under Cygwin. 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerRegisterThread() { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileHandlerCallback callback, void* callback_arg) { 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerReset() { 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // OS_CYGWIN 556