http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock.cc ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock.cc b/third_party/gperftools/src/base/spinlock.cc deleted file mode 100644 index 2021fec..0000000 --- a/third_party/gperftools/src/base/spinlock.cc +++ /dev/null @@ -1,183 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2006, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Sanjay Ghemawat - */ - -#include <config.h> -#include "base/spinlock.h" -#include "base/synchronization_profiling.h" -#include "base/spinlock_internal.h" -#include "base/cycleclock.h" -#include "base/sysinfo.h" /* for NumCPUs() */ - -// NOTE on the Lock-state values: -// -// kSpinLockFree represents the unlocked state -// kSpinLockHeld represents the locked state with no waiters -// -// Values greater than kSpinLockHeld represent the locked state with waiters, -// where the value is the time the current lock holder had to -// wait before obtaining the lock. The kSpinLockSleeper state is a special -// "locked with waiters" state that indicates that a sleeper needs to -// be woken, but the thread that just released the lock didn't wait. - -static int adaptive_spin_count = 0; - -const base::LinkerInitialized SpinLock::LINKER_INITIALIZED = - base::LINKER_INITIALIZED; - -namespace { -struct SpinLock_InitHelper { - SpinLock_InitHelper() { - // On multi-cpu machines, spin for longer before yielding - // the processor or sleeping. Reduces idle time significantly. - if (NumCPUs() > 1) { - adaptive_spin_count = 1000; - } - } -}; - -// Hook into global constructor execution: -// We do not do adaptive spinning before that, -// but nothing lock-intensive should be going on at that time. -static SpinLock_InitHelper init_helper; - -} // unnamed namespace - -// Monitor the lock to see if its value changes within some time period -// (adaptive_spin_count loop iterations). A timestamp indicating -// when the thread initially started waiting for the lock is passed in via -// the initial_wait_timestamp value. The total wait time in cycles for the -// lock is returned in the wait_cycles parameter. The last value read -// from the lock is returned from the method. -Atomic32 SpinLock::SpinLoop(int64 initial_wait_timestamp, - Atomic32* wait_cycles) { - int c = adaptive_spin_count; - while (base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree && --c > 0) { - } - Atomic32 spin_loop_wait_cycles = CalculateWaitCycles(initial_wait_timestamp); - Atomic32 lock_value = - base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, - spin_loop_wait_cycles); - *wait_cycles = spin_loop_wait_cycles; - return lock_value; -} - -void SpinLock::SlowLock() { - // The lock was not obtained initially, so this thread needs to wait for - // it. Record the current timestamp in the local variable wait_start_time - // so the total wait time can be stored in the lockword once this thread - // obtains the lock. - int64 wait_start_time = CycleClock::Now(); - Atomic32 wait_cycles; - Atomic32 lock_value = SpinLoop(wait_start_time, &wait_cycles); - - int lock_wait_call_count = 0; - while (lock_value != kSpinLockFree) { - // If the lock is currently held, but not marked as having a sleeper, mark - // it as having a sleeper. - if (lock_value == kSpinLockHeld) { - // Here, just "mark" that the thread is going to sleep. Don't store the - // lock wait time in the lock as that will cause the current lock - // owner to think it experienced contention. - lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_, - kSpinLockHeld, - kSpinLockSleeper); - if (lock_value == kSpinLockHeld) { - // Successfully transitioned to kSpinLockSleeper. Pass - // kSpinLockSleeper to the SpinLockWait routine to properly indicate - // the last lock_value observed. - lock_value = kSpinLockSleeper; - } else if (lock_value == kSpinLockFree) { - // Lock is free again, so try and acquire it before sleeping. The - // new lock state will be the number of cycles this thread waited if - // this thread obtains the lock. - lock_value = base::subtle::Acquire_CompareAndSwap(&lockword_, - kSpinLockFree, - wait_cycles); - continue; // skip the delay at the end of the loop - } - } - - // Wait for an OS specific delay. - base::internal::SpinLockDelay(&lockword_, lock_value, - ++lock_wait_call_count); - // Spin again after returning from the wait routine to give this thread - // some chance of obtaining the lock. - lock_value = SpinLoop(wait_start_time, &wait_cycles); - } -} - -// The wait time for contentionz lock profiling must fit into 32 bits. -// However, the lower 32-bits of the cycle counter wrap around too quickly -// with high frequency processors, so a right-shift by 7 is performed to -// quickly divide the cycles by 128. Using these 32 bits, reduces the -// granularity of time measurement to 128 cycles, and loses track -// of wait time for waits greater than 109 seconds on a 5 GHz machine -// [(2^32 cycles/5 Ghz)*128 = 109.95 seconds]. Waits this long should be -// very rare and the reduced granularity should not be an issue given -// processors in the Google fleet operate at a minimum of one billion -// cycles/sec. -enum { PROFILE_TIMESTAMP_SHIFT = 7 }; - -void SpinLock::SlowUnlock(uint64 wait_cycles) { - base::internal::SpinLockWake(&lockword_, false); // wake waiter if necessary - - // Collect contentionz profile info, expanding the wait_cycles back out to - // the full value. If wait_cycles is <= kSpinLockSleeper, then no wait - // was actually performed, so don't record the wait time. Note, that the - // CalculateWaitCycles method adds in kSpinLockSleeper cycles - // unconditionally to guarantee the wait time is not kSpinLockFree or - // kSpinLockHeld. The adding in of these small number of cycles may - // overestimate the contention by a slight amount 50% of the time. However, - // if this code tried to correct for that addition by subtracting out the - // kSpinLockSleeper amount that would underestimate the contention slightly - // 50% of the time. Both ways get the wrong answer, so the code - // overestimates to be more conservative. Overestimating also makes the code - // a little simpler. - // - if (wait_cycles > kSpinLockSleeper) { - base::SubmitSpinLockProfileData(this, - wait_cycles << PROFILE_TIMESTAMP_SHIFT); - } -} - -inline int32 SpinLock::CalculateWaitCycles(int64 wait_start_time) { - int32 wait_cycles = ((CycleClock::Now() - wait_start_time) >> - PROFILE_TIMESTAMP_SHIFT); - // The number of cycles waiting for the lock is used as both the - // wait_cycles and lock value, so it can't be kSpinLockFree or - // kSpinLockHeld. Make sure the value returned is at least - // kSpinLockSleeper. - wait_cycles |= kSpinLockSleeper; - return wait_cycles; -}
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock.h b/third_party/gperftools/src/base/spinlock.h deleted file mode 100644 index 033a75e..0000000 --- a/third_party/gperftools/src/base/spinlock.h +++ /dev/null @@ -1,146 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2006, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Sanjay Ghemawat - */ - -// SpinLock is async signal safe. -// If used within a signal handler, all lock holders -// should block the signal even outside the signal handler. - -#ifndef BASE_SPINLOCK_H_ -#define BASE_SPINLOCK_H_ - -#include <config.h> -#include "base/atomicops.h" -#include "base/basictypes.h" -#include "base/dynamic_annotations.h" -#include "base/thread_annotations.h" - -class LOCKABLE SpinLock { - public: - SpinLock() : lockword_(kSpinLockFree) { } - - // Special constructor for use with static SpinLock objects. E.g., - // - // static SpinLock lock(base::LINKER_INITIALIZED); - // - // When intialized using this constructor, we depend on the fact - // that the linker has already initialized the memory appropriately. - // A SpinLock constructed like this can be freely used from global - // initializers without worrying about the order in which global - // initializers run. - explicit SpinLock(base::LinkerInitialized /*x*/) { - // Does nothing; lockword_ is already initialized - } - - // Acquire this SpinLock. - // TODO(csilvers): uncomment the annotation when we figure out how to - // support this macro with 0 args (see thread_annotations.h) - inline void Lock() /*EXCLUSIVE_LOCK_FUNCTION()*/ { - if (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, - kSpinLockHeld) != kSpinLockFree) { - SlowLock(); - } - ANNOTATE_RWLOCK_ACQUIRED(this, 1); - } - - // Try to acquire this SpinLock without blocking and return true if the - // acquisition was successful. If the lock was not acquired, false is - // returned. If this SpinLock is free at the time of the call, TryLock - // will return true with high probability. - inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { - bool res = - (base::subtle::Acquire_CompareAndSwap(&lockword_, kSpinLockFree, - kSpinLockHeld) == kSpinLockFree); - if (res) { - ANNOTATE_RWLOCK_ACQUIRED(this, 1); - } - return res; - } - - // Release this SpinLock, which must be held by the calling thread. - // TODO(csilvers): uncomment the annotation when we figure out how to - // support this macro with 0 args (see thread_annotations.h) - inline void Unlock() /*UNLOCK_FUNCTION()*/ { - ANNOTATE_RWLOCK_RELEASED(this, 1); - uint64 wait_cycles = static_cast<uint64>( - base::subtle::Release_AtomicExchange(&lockword_, kSpinLockFree)); - if (wait_cycles != kSpinLockHeld) { - // Collect contentionz profile info, and speed the wakeup of any waiter. - // The wait_cycles value indicates how long this thread spent waiting - // for the lock. - SlowUnlock(wait_cycles); - } - } - - // Determine if the lock is held. When the lock is held by the invoking - // thread, true will always be returned. Intended to be used as - // CHECK(lock.IsHeld()). - inline bool IsHeld() const { - return base::subtle::NoBarrier_Load(&lockword_) != kSpinLockFree; - } - - static const base::LinkerInitialized LINKER_INITIALIZED; // backwards compat - private: - enum { kSpinLockFree = 0 }; - enum { kSpinLockHeld = 1 }; - enum { kSpinLockSleeper = 2 }; - - volatile Atomic32 lockword_; - - void SlowLock(); - void SlowUnlock(uint64 wait_cycles); - Atomic32 SpinLoop(int64 initial_wait_timestamp, Atomic32* wait_cycles); - inline int32 CalculateWaitCycles(int64 wait_start_time); - - DISALLOW_COPY_AND_ASSIGN(SpinLock); -}; - -// Corresponding locker object that arranges to acquire a spinlock for -// the duration of a C++ scope. -class SCOPED_LOCKABLE SpinLockHolder { - private: - SpinLock* lock_; - public: - inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l) - : lock_(l) { - l->Lock(); - } - // TODO(csilvers): uncomment the annotation when we figure out how to - // support this macro with 0 args (see thread_annotations.h) - inline ~SpinLockHolder() /*UNLOCK_FUNCTION()*/ { lock_->Unlock(); } -}; -// Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock); -#define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name) - - -#endif // BASE_SPINLOCK_H_ http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock_internal.cc ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock_internal.cc b/third_party/gperftools/src/base/spinlock_internal.cc deleted file mode 100644 index e090f9b..0000000 --- a/third_party/gperftools/src/base/spinlock_internal.cc +++ /dev/null @@ -1,122 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2010, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// The OS-specific header included below must provide two calls: -// base::internal::SpinLockDelay() and base::internal::SpinLockWake(). -// See spinlock_internal.h for the spec of SpinLockWake(). - -// void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) -// SpinLockDelay() generates an apprproate spin delay on iteration "loop" of a -// spin loop on location *w, whose previously observed value was "value". -// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, -// or may wait for a delay that can be truncated by a call to SpinlockWake(w). -// In all cases, it must return in bounded time even if SpinlockWake() is not -// called. - -#include "base/spinlock_internal.h" - -// forward declaration for use by spinlock_*-inl.h -namespace base { namespace internal { static int SuggestedDelayNS(int loop); }} - -#if defined(_WIN32) -#include "base/spinlock_win32-inl.h" -#elif defined(__linux__) -#include "base/spinlock_linux-inl.h" -#else -#include "base/spinlock_posix-inl.h" -#endif - -namespace base { -namespace internal { - -// See spinlock_internal.h for spec. -int32 SpinLockWait(volatile Atomic32 *w, int n, - const SpinLockWaitTransition trans[]) { - int32 v; - bool done = false; - for (int loop = 0; !done; loop++) { - v = base::subtle::Acquire_Load(w); - int i; - for (i = 0; i != n && v != trans[i].from; i++) { - } - if (i == n) { - SpinLockDelay(w, v, loop); // no matching transition - } else if (trans[i].to == v || // null transition - base::subtle::Acquire_CompareAndSwap(w, v, trans[i].to) == v) { - done = trans[i].done; - } - } - return v; -} - -// Return a suggested delay in nanoseconds for iteration number "loop" -static int SuggestedDelayNS(int loop) { - // Weak pseudo-random number generator to get some spread between threads - // when many are spinning. -#ifdef BASE_HAS_ATOMIC64 - static base::subtle::Atomic64 rand; - uint64 r = base::subtle::NoBarrier_Load(&rand); - r = 0x5deece66dLL * r + 0xb; // numbers from nrand48() - base::subtle::NoBarrier_Store(&rand, r); - - r <<= 16; // 48-bit random number now in top 48-bits. - if (loop < 0 || loop > 32) { // limit loop to 0..32 - loop = 32; - } - // loop>>3 cannot exceed 4 because loop cannot exceed 32. - // Select top 20..24 bits of lower 48 bits, - // giving approximately 0ms to 16ms. - // Mean is exponential in loop for first 32 iterations, then 8ms. - // The futex path multiplies this by 16, since we expect explicit wakeups - // almost always on that path. - return r >> (44 - (loop >> 3)); -#else - static Atomic32 rand; - uint32 r = base::subtle::NoBarrier_Load(&rand); - r = 0x343fd * r + 0x269ec3; // numbers from MSVC++ - base::subtle::NoBarrier_Store(&rand, r); - - r <<= 1; // 31-bit random number now in top 31-bits. - if (loop < 0 || loop > 32) { // limit loop to 0..32 - loop = 32; - } - // loop>>3 cannot exceed 4 because loop cannot exceed 32. - // Select top 20..24 bits of lower 31 bits, - // giving approximately 0ms to 16ms. - // Mean is exponential in loop for first 32 iterations, then 8ms. - // The futex path multiplies this by 16, since we expect explicit wakeups - // almost always on that path. - return r >> (12 - (loop >> 3)); -#endif -} - -} // namespace internal -} // namespace base http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock_internal.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock_internal.h b/third_party/gperftools/src/base/spinlock_internal.h deleted file mode 100644 index 4d3c17f..0000000 --- a/third_party/gperftools/src/base/spinlock_internal.h +++ /dev/null @@ -1,65 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2010, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * This file is an internal part spinlock.cc and once.cc - * It may not be used directly by code outside of //base. - */ - -#ifndef BASE_SPINLOCK_INTERNAL_H_ -#define BASE_SPINLOCK_INTERNAL_H_ - -#include <config.h> -#include "base/basictypes.h" -#include "base/atomicops.h" - -namespace base { -namespace internal { - -// SpinLockWait() waits until it can perform one of several transitions from -// "from" to "to". It returns when it performs a transition where done==true. -struct SpinLockWaitTransition { - int32 from; - int32 to; - bool done; -}; - -// Wait until *w can transition from trans[i].from to trans[i].to for some i -// satisfying 0<=i<n && trans[i].done, atomically make the transition, -// then return the old value of *w. Make any other atomic tranistions -// where !trans[i].done, but continue waiting. -int32 SpinLockWait(volatile Atomic32 *w, int n, - const SpinLockWaitTransition trans[]); -void SpinLockWake(volatile Atomic32 *w, bool all); -void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop); - -} // namespace internal -} // namespace base -#endif http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock_linux-inl.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock_linux-inl.h b/third_party/gperftools/src/base/spinlock_linux-inl.h deleted file mode 100644 index 86d4d04..0000000 --- a/third_party/gperftools/src/base/spinlock_linux-inl.h +++ /dev/null @@ -1,104 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2009, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * This file is a Linux-specific part of spinlock_internal.cc - */ - -#include <errno.h> -#include <sched.h> -#include <time.h> -#include <limits.h> -#include "base/linux_syscall_support.h" - -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 -#define FUTEX_PRIVATE_FLAG 128 - -static bool have_futex; -static int futex_private_flag = FUTEX_PRIVATE_FLAG; - -namespace { -static struct InitModule { - InitModule() { - int x = 0; - // futexes are ints, so we can use them only when - // that's the same size as the lockword_ in SpinLock. -#ifdef __arm__ - // ARM linux doesn't support sys_futex1(void*, int, int, struct timespec*); - have_futex = 0; -#else - have_futex = (sizeof (Atomic32) == sizeof (int) && - sys_futex(&x, FUTEX_WAKE, 1, 0) >= 0); -#endif - if (have_futex && - sys_futex(&x, FUTEX_WAKE | futex_private_flag, 1, 0) < 0) { - futex_private_flag = 0; - } - } -} init_module; - -} // anonymous namespace - - -namespace base { -namespace internal { - -void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { - if (loop != 0) { - int save_errno = errno; - struct timespec tm; - tm.tv_sec = 0; - if (have_futex) { - tm.tv_nsec = base::internal::SuggestedDelayNS(loop); - } else { - tm.tv_nsec = 2000001; // above 2ms so linux 2.4 doesn't spin - } - if (have_futex) { - tm.tv_nsec *= 16; // increase the delay; we expect explicit wakeups - sys_futex(reinterpret_cast<int *>(const_cast<Atomic32 *>(w)), - FUTEX_WAIT | futex_private_flag, - value, reinterpret_cast<struct kernel_timespec *>(&tm)); - } else { - nanosleep(&tm, NULL); - } - errno = save_errno; - } -} - -void SpinLockWake(volatile Atomic32 *w, bool all) { - if (have_futex) { - sys_futex(reinterpret_cast<int *>(const_cast<Atomic32 *>(w)), - FUTEX_WAKE | futex_private_flag, all? INT_MAX : 1, 0); - } -} - -} // namespace internal -} // namespace base http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock_posix-inl.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock_posix-inl.h b/third_party/gperftools/src/base/spinlock_posix-inl.h deleted file mode 100644 index e73a30f..0000000 --- a/third_party/gperftools/src/base/spinlock_posix-inl.h +++ /dev/null @@ -1,63 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2009, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * This file is a Posix-specific part of spinlock_internal.cc - */ - -#include <config.h> -#include <errno.h> -#ifdef HAVE_SCHED_H -#include <sched.h> /* For sched_yield() */ -#endif -#include <time.h> /* For nanosleep() */ - -namespace base { -namespace internal { - -void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { - int save_errno = errno; - if (loop == 0) { - } else if (loop == 1) { - sched_yield(); - } else { - struct timespec tm; - tm.tv_sec = 0; - tm.tv_nsec = base::internal::SuggestedDelayNS(loop); - nanosleep(&tm, NULL); - } - errno = save_errno; -} - -void SpinLockWake(volatile Atomic32 *w, bool all) { -} - -} // namespace internal -} // namespace base http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/spinlock_win32-inl.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/spinlock_win32-inl.h b/third_party/gperftools/src/base/spinlock_win32-inl.h deleted file mode 100644 index 956b965..0000000 --- a/third_party/gperftools/src/base/spinlock_win32-inl.h +++ /dev/null @@ -1,54 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2009, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * This file is a Win32-specific part of spinlock_internal.cc - */ - - -#include <windows.h> - -namespace base { -namespace internal { - -void SpinLockDelay(volatile Atomic32 *w, int32 value, int loop) { - if (loop == 0) { - } else if (loop == 1) { - Sleep(0); - } else { - Sleep(base::internal::SuggestedDelayNS(loop) / 1000000); - } -} - -void SpinLockWake(volatile Atomic32 *w, bool all) { -} - -} // namespace internal -} // namespace base http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/stl_allocator.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/stl_allocator.h b/third_party/gperftools/src/base/stl_allocator.h deleted file mode 100644 index 2345f46..0000000 --- a/third_party/gperftools/src/base/stl_allocator.h +++ /dev/null @@ -1,98 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2006, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Maxim Lifantsev - */ - - -#ifndef BASE_STL_ALLOCATOR_H_ -#define BASE_STL_ALLOCATOR_H_ - -#include <config.h> - -#include <stddef.h> // for ptrdiff_t -#include <limits> - -#include "base/logging.h" - -// Generic allocator class for STL objects -// that uses a given type-less allocator Alloc, which must provide: -// static void* Alloc::Allocate(size_t size); -// static void Alloc::Free(void* ptr, size_t size); -// -// STL_Allocator<T, MyAlloc> provides the same thread-safety -// guarantees as MyAlloc. -// -// Usage example: -// set<T, less<T>, STL_Allocator<T, MyAlloc> > my_set; -// CAVEAT: Parts of the code below are probably specific -// to the STL version(s) we are using. -// The code is simply lifted from what std::allocator<> provides. -template <typename T, class Alloc> -class STL_Allocator { - public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template <class T1> struct rebind { - typedef STL_Allocator<T1, Alloc> other; - }; - - STL_Allocator() { } - STL_Allocator(const STL_Allocator&) { } - template <class T1> STL_Allocator(const STL_Allocator<T1, Alloc>&) { } - ~STL_Allocator() { } - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, const void* = 0) { - RAW_DCHECK((n * sizeof(T)) / sizeof(T) == n, "n is too big to allocate"); - return static_cast<T*>(Alloc::Allocate(n * sizeof(T))); - } - void deallocate(pointer p, size_type n) { Alloc::Free(p, n * sizeof(T)); } - - size_type max_size() const { return size_t(-1) / sizeof(T); } - - void construct(pointer p, const T& val) { ::new(p) T(val); } - void construct(pointer p) { ::new(p) T(); } - void destroy(pointer p) { p->~T(); } - - // There's no state, so these allocators are always equal - bool operator==(const STL_Allocator&) const { return true; } -}; - -#endif // BASE_STL_ALLOCATOR_H_ http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/synchronization_profiling.h ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/synchronization_profiling.h b/third_party/gperftools/src/base/synchronization_profiling.h deleted file mode 100644 index b495034..0000000 --- a/third_party/gperftools/src/base/synchronization_profiling.h +++ /dev/null @@ -1,51 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2010, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Chris Ruemmler - */ - -#ifndef BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ -#define BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ - -#include "base/basictypes.h" - -namespace base { - -// We can do contention-profiling of SpinLocks, but the code is in -// mutex.cc, which is not always linked in with spinlock. Hence we -// provide a weak definition, which are used if mutex.cc isn't linked in. - -// Submit the number of cycles the spinlock spent contending. -ATTRIBUTE_WEAK extern void SubmitSpinLockProfileData(const void *, int64); -extern void SubmitSpinLockProfileData(const void *contendedlock, - int64 wait_cycles) {} -} -#endif // BASE_AUXILIARY_SYNCHRONIZATION_PROFILING_H_ http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/9661f956/third_party/gperftools/src/base/sysinfo.cc ---------------------------------------------------------------------- diff --git a/third_party/gperftools/src/base/sysinfo.cc b/third_party/gperftools/src/base/sysinfo.cc deleted file mode 100644 index cad751b..0000000 --- a/third_party/gperftools/src/base/sysinfo.cc +++ /dev/null @@ -1,1153 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <config.h> -#if (defined(_WIN32) || defined(__MINGW32__)) && !defined(__CYGWIN__) && !defined(__CYGWIN32) -# define PLATFORM_WINDOWS 1 -#endif - -#include <ctype.h> // for isspace() -#include <stdlib.h> // for getenv() -#include <stdio.h> // for snprintf(), sscanf() -#include <string.h> // for memmove(), memchr(), etc. -#include <fcntl.h> // for open() -#include <errno.h> // for errno -#ifdef HAVE_UNISTD_H -#include <unistd.h> // for read() -#endif -#if defined __MACH__ // Mac OS X, almost certainly -#include <mach-o/dyld.h> // for iterating over dll's in ProcMapsIter -#include <mach-o/loader.h> // for iterating over dll's in ProcMapsIter -#include <sys/types.h> -#include <sys/sysctl.h> // how we figure out numcpu's on OS X -#elif defined __FreeBSD__ -#include <sys/sysctl.h> -#elif defined __sun__ // Solaris -#include <procfs.h> // for, e.g., prmap_t -#elif defined(PLATFORM_WINDOWS) -#include <process.h> // for getpid() (actually, _getpid()) -#include <shlwapi.h> // for SHGetValueA() -#include <tlhelp32.h> // for Module32First() -#endif -#include "base/sysinfo.h" -#include "base/commandlineflags.h" -#include "base/dynamic_annotations.h" // for RunningOnValgrind -#include "base/logging.h" -#include "base/cycleclock.h" - -#ifdef PLATFORM_WINDOWS -#ifdef MODULEENTRY32 -// In a change from the usual W-A pattern, there is no A variant of -// MODULEENTRY32. Tlhelp32.h #defines the W variant, but not the A. -// In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be -// MODULEENTRY32W. These #undefs are the only way I see to get back -// access to the original, ascii struct (and related functions). -#undef MODULEENTRY32 -#undef Module32First -#undef Module32Next -#undef PMODULEENTRY32 -#undef LPMODULEENTRY32 -#endif /* MODULEENTRY32 */ -// MinGW doesn't seem to define this, perhaps some windowsen don't either. -#ifndef TH32CS_SNAPMODULE32 -#define TH32CS_SNAPMODULE32 0 -#endif /* TH32CS_SNAPMODULE32 */ -#endif /* PLATFORM_WINDOWS */ - -// Re-run fn until it doesn't cause EINTR. -#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR) - -// open/read/close can set errno, which may be illegal at this -// time, so prefer making the syscalls directly if we can. -#ifdef HAVE_SYS_SYSCALL_H -# include <sys/syscall.h> -#endif -#ifdef SYS_open // solaris 11, at least sometimes, only defines SYS_openat -# define safeopen(filename, mode) syscall(SYS_open, filename, mode) -#else -# define safeopen(filename, mode) open(filename, mode) -#endif -#ifdef SYS_read -# define saferead(fd, buffer, size) syscall(SYS_read, fd, buffer, size) -#else -# define saferead(fd, buffer, size) read(fd, buffer, size) -#endif -#ifdef SYS_close -# define safeclose(fd) syscall(SYS_close, fd) -#else -# define safeclose(fd) close(fd) -#endif - -// ---------------------------------------------------------------------- -// GetenvBeforeMain() -// GetUniquePathFromEnv() -// Some non-trivial getenv-related functions. -// ---------------------------------------------------------------------- - -// It's not safe to call getenv() in the malloc hooks, because they -// might be called extremely early, before libc is done setting up -// correctly. In particular, the thread library may not be done -// setting up errno. So instead, we use the built-in __environ array -// if it exists, and otherwise read /proc/self/environ directly, using -// system calls to read the file, and thus avoid setting errno. -// /proc/self/environ has a limit of how much data it exports (around -// 8K), so it's not an ideal solution. -const char* GetenvBeforeMain(const char* name) { -#if defined(HAVE___ENVIRON) // if we have it, it's declared in unistd.h - if (__environ) { // can exist but be NULL, if statically linked - const int namelen = strlen(name); - for (char** p = __environ; *p; p++) { - if (strlen(*p) < namelen) { - continue; - } - if (!memcmp(*p, name, namelen) && (*p)[namelen] == '=') // it's a match - return *p + namelen+1; // point after = - } - return NULL; - } -#endif -#if defined(PLATFORM_WINDOWS) - // TODO(mbelshe) - repeated calls to this function will overwrite the - // contents of the static buffer. - static char envvar_buf[1024]; // enough to hold any envvar we care about - if (!GetEnvironmentVariableA(name, envvar_buf, sizeof(envvar_buf)-1)) - return NULL; - return envvar_buf; -#endif - // static is ok because this function should only be called before - // main(), when we're single-threaded. - static char envbuf[16<<10]; - if (*envbuf == '\0') { // haven't read the environ yet - int fd = safeopen("/proc/self/environ", O_RDONLY); - // The -2 below guarantees the last two bytes of the buffer will be \0\0 - if (fd == -1 || // unable to open the file, fall back onto libc - saferead(fd, envbuf, sizeof(envbuf) - 2) < 0) { // error reading file - RAW_VLOG(1, "Unable to open /proc/self/environ, falling back " - "on getenv(\"%s\"), which may not work", name); - if (fd != -1) safeclose(fd); - return getenv(name); - } - safeclose(fd); - } - const int namelen = strlen(name); - const char* p = envbuf; - while (*p != '\0') { // will happen at the \0\0 that terminates the buffer - // proc file has the format NAME=value\0NAME=value\0NAME=value\0... - const char* endp = (char*)memchr(p, '\0', sizeof(envbuf) - (p - envbuf)); - if (endp == NULL) // this entry isn't NUL terminated - return NULL; - else if (!memcmp(p, name, namelen) && p[namelen] == '=') // it's a match - return p + namelen+1; // point after = - p = endp + 1; - } - return NULL; // env var never found -} - -extern "C" { - const char* TCMallocGetenvSafe(const char* name) { - return GetenvBeforeMain(name); - } -} - -// This takes as an argument an environment-variable name (like -// CPUPROFILE) whose value is supposed to be a file-path, and sets -// path to that path, and returns true. If the env var doesn't exist, -// or is the empty string, leave path unchanged and returns false. -// The reason this is non-trivial is that this function handles munged -// pathnames. Here's why: -// -// If we're a child process of the 'main' process, we can't just use -// getenv("CPUPROFILE") -- the parent process will be using that path. -// Instead we append our pid to the pathname. How do we tell if we're a -// child process? Ideally we'd set an environment variable that all -// our children would inherit. But -- and this is seemingly a bug in -// gcc -- if you do a setenv() in a shared libarary in a global -// constructor, the environment setting is lost by the time main() is -// called. The only safe thing we can do in such a situation is to -// modify the existing envvar. So we do a hack: in the parent, we set -// the high bit of the 1st char of CPUPROFILE. In the child, we -// notice the high bit is set and append the pid(). This works -// assuming cpuprofile filenames don't normally have the high bit set -// in their first character! If that assumption is violated, we'll -// still get a profile, but one with an unexpected name. -// TODO(csilvers): set an envvar instead when we can do it reliably. -bool GetUniquePathFromEnv(const char* env_name, char* path) { - char* envval = getenv(env_name); - if (envval == NULL || *envval == '\0') - return false; - if (envval[0] & 128) { // high bit is set - snprintf(path, PATH_MAX, "%c%s_%u", // add pid and clear high bit - envval[0] & 127, envval+1, (unsigned int)(getpid())); - } else { - snprintf(path, PATH_MAX, "%s", envval); - envval[0] |= 128; // set high bit for kids to see - } - return true; -} - -// ---------------------------------------------------------------------- -// CyclesPerSecond() -// NumCPUs() -// It's important this not call malloc! -- they may be called at -// global-construct time, before we've set up all our proper malloc -// hooks and such. -// ---------------------------------------------------------------------- - -static double cpuinfo_cycles_per_second = 1.0; // 0.0 might be dangerous -static int cpuinfo_num_cpus = 1; // Conservative guess - -void SleepForMilliseconds(int milliseconds) { -#ifdef PLATFORM_WINDOWS - _sleep(milliseconds); // Windows's _sleep takes milliseconds argument -#else - // Sleep for a few milliseconds - struct timespec sleep_time; - sleep_time.tv_sec = milliseconds / 1000; - sleep_time.tv_nsec = (milliseconds % 1000) * 1000000; - while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) - ; // Ignore signals and wait for the full interval to elapse. -#endif -} - -// Helper function estimates cycles/sec by observing cycles elapsed during -// sleep(). Using small sleep time decreases accuracy significantly. -static int64 EstimateCyclesPerSecond(const int estimate_time_ms) { - assert(estimate_time_ms > 0); - if (estimate_time_ms <= 0) - return 1; - double multiplier = 1000.0 / (double)estimate_time_ms; // scale by this much - - const int64 start_ticks = CycleClock::Now(); - SleepForMilliseconds(estimate_time_ms); - const int64 guess = int64(multiplier * (CycleClock::Now() - start_ticks)); - return guess; -} - -// ReadIntFromFile is only called on linux and cygwin platforms. -#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) -// Helper function for reading an int from a file. Returns true if successful -// and the memory location pointed to by value is set to the value read. -static bool ReadIntFromFile(const char *file, int *value) { - bool ret = false; - int fd = open(file, O_RDONLY); - if (fd != -1) { - char line[1024]; - char* err; - memset(line, '\0', sizeof(line)); - read(fd, line, sizeof(line) - 1); - const int temp_value = strtol(line, &err, 10); - if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { - *value = temp_value; - ret = true; - } - close(fd); - } - return ret; -} -#endif - -// WARNING: logging calls back to InitializeSystemInfo() so it must -// not invoke any logging code. Also, InitializeSystemInfo() can be -// called before main() -- in fact it *must* be since already_called -// isn't protected -- before malloc hooks are properly set up, so -// we make an effort not to call any routines which might allocate -// memory. - -static void InitializeSystemInfo() { - static bool already_called = false; // safe if we run before threads - if (already_called) return; - already_called = true; - - bool saw_mhz = false; - - if (RunningOnValgrind()) { - // Valgrind may slow the progress of time artificially (--scale-time=N - // option). We thus can't rely on CPU Mhz info stored in /sys or /proc - // files. Thus, actually measure the cps. - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(100); - saw_mhz = true; - } - -#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) - char line[1024]; - char* err; - int freq; - - // If the kernel is exporting the tsc frequency use that. There are issues - // where cpuinfo_max_freq cannot be relied on because the BIOS may be - // exporintg an invalid p-state (on x86) or p-states may be used to put the - // processor in a new mode (turbo mode). Essentially, those frequencies - // cannot always be relied upon. The same reasons apply to /proc/cpuinfo as - // well. - if (!saw_mhz && - ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { - // The value is in kHz (as the file name suggests). For example, on a - // 2GHz warpstation, the file contains the value "2000000". - cpuinfo_cycles_per_second = freq * 1000.0; - saw_mhz = true; - } - - // If CPU scaling is in effect, we want to use the *maximum* frequency, - // not whatever CPU speed some random processor happens to be using now. - if (!saw_mhz && - ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", - &freq)) { - // The value is in kHz. For example, on a 2GHz machine, the file - // contains the value "2000000". - cpuinfo_cycles_per_second = freq * 1000.0; - saw_mhz = true; - } - - // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq. - const char* pname = "/proc/cpuinfo"; - int fd = open(pname, O_RDONLY); - if (fd == -1) { - perror(pname); - if (!saw_mhz) { - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); - } - return; // TODO: use generic tester instead? - } - - double bogo_clock = 1.0; - bool saw_bogo = false; - int num_cpus = 0; - line[0] = line[1] = '\0'; - int chars_read = 0; - do { // we'll exit when the last read didn't read anything - // Move the next line to the beginning of the buffer - const int oldlinelen = strlen(line); - if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line - line[0] = '\0'; - else // still other lines left to save - memmove(line, line + oldlinelen+1, sizeof(line) - (oldlinelen+1)); - // Terminate the new line, reading more if we can't find the newline - char* newline = strchr(line, '\n'); - if (newline == NULL) { - const int linelen = strlen(line); - const int bytes_to_read = sizeof(line)-1 - linelen; - assert(bytes_to_read > 0); // because the memmove recovered >=1 bytes - chars_read = read(fd, line + linelen, bytes_to_read); - line[linelen + chars_read] = '\0'; - newline = strchr(line, '\n'); - } - if (newline != NULL) - *newline = '\0'; - -#if defined(__powerpc__) || defined(__ppc__) - // PowerPC cpus report the frequency in "clock" line - if (strncasecmp(line, "clock", sizeof("clock")-1) == 0) { - const char* freqstr = strchr(line, ':'); - if (freqstr) { - // PowerPC frequencies are only reported as MHz (check 'show_cpuinfo' - // function at arch/powerpc/kernel/setup-common.c) - char *endp = strstr(line, "MHz"); - if (endp) { - *endp = 0; - cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; - if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) - saw_mhz = true; - } - } -#else - // When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only - // accept postive values. Some environments (virtual machines) report zero, - // which would cause infinite looping in WallTime_Init. - if (!saw_mhz && strncasecmp(line, "cpu MHz", sizeof("cpu MHz")-1) == 0) { - const char* freqstr = strchr(line, ':'); - if (freqstr) { - cpuinfo_cycles_per_second = strtod(freqstr+1, &err) * 1000000.0; - if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0) - saw_mhz = true; - } - } else if (strncasecmp(line, "bogomips", sizeof("bogomips")-1) == 0) { - const char* freqstr = strchr(line, ':'); - if (freqstr) { - bogo_clock = strtod(freqstr+1, &err) * 1000000.0; - if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0) - saw_bogo = true; - } -#endif - } else if (strncasecmp(line, "processor", sizeof("processor")-1) == 0) { - num_cpus++; // count up every time we see an "processor :" entry - } - } while (chars_read > 0); - close(fd); - - if (!saw_mhz) { - if (saw_bogo) { - // If we didn't find anything better, we'll use bogomips, but - // we're not happy about it. - cpuinfo_cycles_per_second = bogo_clock; - } else { - // If we don't even have bogomips, we'll use the slow estimation. - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); - } - } - if (cpuinfo_cycles_per_second == 0.0) { - cpuinfo_cycles_per_second = 1.0; // maybe unnecessary, but safe - } - if (num_cpus > 0) { - cpuinfo_num_cpus = num_cpus; - } - -#elif defined __FreeBSD__ - // For this sysctl to work, the machine must be configured without - // SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0 - // and later. Before that, it's a 32-bit quantity (and gives the - // wrong answer on machines faster than 2^32 Hz). See - // http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html - // But also compare FreeBSD 7.0: - // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223 - // 231 error = sysctl_handle_quad(oidp, &freq, 0, req); - // To FreeBSD 6.3 (it's the same in 6-STABLE): - // http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131 - // 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); -#if __FreeBSD__ >= 7 - uint64_t hz = 0; -#else - unsigned int hz = 0; -#endif - size_t sz = sizeof(hz); - const char *sysctl_path = "machdep.tsc_freq"; - if ( sysctlbyname(sysctl_path, &hz, &sz, NULL, 0) != 0 ) { - fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n", - sysctl_path, strerror(errno)); - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); - } else { - cpuinfo_cycles_per_second = hz; - } - // TODO(csilvers): also figure out cpuinfo_num_cpus - -#elif defined(PLATFORM_WINDOWS) -# pragma comment(lib, "shlwapi.lib") // for SHGetValue() - // In NT, read MHz from the registry. If we fail to do so or we're in win9x - // then make a crude estimate. - OSVERSIONINFO os; - os.dwOSVersionInfoSize = sizeof(os); - DWORD data, data_size = sizeof(data); - if (GetVersionEx(&os) && - os.dwPlatformId == VER_PLATFORM_WIN32_NT && - SUCCEEDED(SHGetValueA(HKEY_LOCAL_MACHINE, - "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", - "~MHz", NULL, &data, &data_size))) - cpuinfo_cycles_per_second = (int64)data * (int64)(1000 * 1000); // was mhz - else - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(500); // TODO <500? - - // Get the number of processors. - SYSTEM_INFO info; - GetSystemInfo(&info); - cpuinfo_num_cpus = info.dwNumberOfProcessors; - -#elif defined(__MACH__) && defined(__APPLE__) - // returning "mach time units" per second. the current number of elapsed - // mach time units can be found by calling uint64 mach_absolute_time(); - // while not as precise as actual CPU cycles, it is accurate in the face - // of CPU frequency scaling and multi-cpu/core machines. - // Our mac users have these types of machines, and accuracy - // (i.e. correctness) trumps precision. - // See cycleclock.h: CycleClock::Now(), which returns number of mach time - // units on Mac OS X. - mach_timebase_info_data_t timebase_info; - mach_timebase_info(&timebase_info); - double mach_time_units_per_nanosecond = - static_cast<double>(timebase_info.denom) / - static_cast<double>(timebase_info.numer); - cpuinfo_cycles_per_second = mach_time_units_per_nanosecond * 1e9; - - int num_cpus = 0; - size_t size = sizeof(num_cpus); - int numcpus_name[] = { CTL_HW, HW_NCPU }; - if (::sysctl(numcpus_name, arraysize(numcpus_name), &num_cpus, &size, 0, 0) - == 0 - && (size == sizeof(num_cpus))) - cpuinfo_num_cpus = num_cpus; - -#else - // Generic cycles per second counter - cpuinfo_cycles_per_second = EstimateCyclesPerSecond(1000); -#endif -} - -double CyclesPerSecond(void) { - InitializeSystemInfo(); - return cpuinfo_cycles_per_second; -} - -int NumCPUs(void) { - InitializeSystemInfo(); - return cpuinfo_num_cpus; -} - -// ---------------------------------------------------------------------- -// HasPosixThreads() -// Return true if we're running POSIX (e.g., NPTL on Linux) -// threads, as opposed to a non-POSIX thread library. The thing -// that we care about is whether a thread's pid is the same as -// the thread that spawned it. If so, this function returns -// true. -// ---------------------------------------------------------------------- -bool HasPosixThreads() { -#if defined(__linux__) -#ifndef _CS_GNU_LIBPTHREAD_VERSION -#define _CS_GNU_LIBPTHREAD_VERSION 3 -#endif - char buf[32]; - // We assume that, if confstr() doesn't know about this name, then - // the same glibc is providing LinuxThreads. - if (confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf)) == 0) - return false; - return strncmp(buf, "NPTL", 4) == 0; -#elif defined(PLATFORM_WINDOWS) || defined(__CYGWIN__) || defined(__CYGWIN32__) - return false; -#else // other OS - return true; // Assume that everything else has Posix -#endif // else OS_LINUX -} - -// ---------------------------------------------------------------------- - -#if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYGWIN__ || defined __CYGWIN32__ -static void ConstructFilename(const char* spec, pid_t pid, - char* buf, int buf_size) { - CHECK_LT(snprintf(buf, buf_size, - spec, - static_cast<int>(pid ? pid : getpid())), buf_size); -} -#endif - -// A templatized helper function instantiated for Mach (OS X) only. -// It can handle finding info for both 32 bits and 64 bits. -// Returns true if it successfully handled the hdr, false else. -#ifdef __MACH__ // Mac OS X, almost certainly -template<uint32_t kMagic, uint32_t kLCSegment, - typename MachHeader, typename SegmentCommand> -static bool NextExtMachHelper(const mach_header* hdr, - int current_image, int current_load_cmd, - uint64 *start, uint64 *end, char **flags, - uint64 *offset, int64 *inode, char **filename, - uint64 *file_mapping, uint64 *file_pages, - uint64 *anon_mapping, uint64 *anon_pages, - dev_t *dev) { - static char kDefaultPerms[5] = "r-xp"; - if (hdr->magic != kMagic) - return false; - const char* lc = (const char *)hdr + sizeof(MachHeader); - // TODO(csilvers): make this not-quadradic (increment and hold state) - for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd - lc += ((const load_command *)lc)->cmdsize; - if (((const load_command *)lc)->cmd == kLCSegment) { - const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image); - const SegmentCommand* sc = (const SegmentCommand *)lc; - if (start) *start = sc->vmaddr + dlloff; - if (end) *end = sc->vmaddr + sc->vmsize + dlloff; - if (flags) *flags = kDefaultPerms; // can we do better? - if (offset) *offset = sc->fileoff; - if (inode) *inode = 0; - if (filename) - *filename = const_cast<char*>(_dyld_get_image_name(current_image)); - if (file_mapping) *file_mapping = 0; - if (file_pages) *file_pages = 0; // could we use sc->filesize? - if (anon_mapping) *anon_mapping = 0; - if (anon_pages) *anon_pages = 0; - if (dev) *dev = 0; - return true; - } - - return false; -} -#endif - -// Finds |c| in |text|, and assign '\0' at the found position. -// The original character at the modified position should be |c|. -// A pointer to the modified position is stored in |endptr|. -// |endptr| should not be NULL. -static bool ExtractUntilChar(char *text, int c, char **endptr) { - CHECK_NE(text, NULL); - CHECK_NE(endptr, NULL); - char *found; - found = strchr(text, c); - if (found == NULL) { - *endptr = NULL; - return false; - } - - *endptr = found; - *found = '\0'; - return true; -} - -// Increments |*text_pointer| while it points a whitespace character. -// It is to follow sscanf's whilespace handling. -static void SkipWhileWhitespace(char **text_pointer, int c) { - if (isspace(c)) { - while (isspace(**text_pointer) && isspace(*((*text_pointer) + 1))) { - ++(*text_pointer); - } - } -} - -template<class T> -static T StringToInteger(char *text, char **endptr, int base) { - assert(false); - return T(); -} - -template<> -int StringToInteger<int>(char *text, char **endptr, int base) { - return strtol(text, endptr, base); -} - -template<> -int64 StringToInteger<int64>(char *text, char **endptr, int base) { - return strtoll(text, endptr, base); -} - -template<> -uint64 StringToInteger<uint64>(char *text, char **endptr, int base) { - return strtoull(text, endptr, base); -} - -template<typename T> -static T StringToIntegerUntilChar( - char *text, int base, int c, char **endptr_result) { - CHECK_NE(endptr_result, NULL); - *endptr_result = NULL; - - char *endptr_extract; - if (!ExtractUntilChar(text, c, &endptr_extract)) - return 0; - - T result; - char *endptr_strto; - result = StringToInteger<T>(text, &endptr_strto, base); - *endptr_extract = c; - - if (endptr_extract != endptr_strto) - return 0; - - *endptr_result = endptr_extract; - SkipWhileWhitespace(endptr_result, c); - - return result; -} - -static char *CopyStringUntilChar( - char *text, unsigned out_len, int c, char *out) { - char *endptr; - if (!ExtractUntilChar(text, c, &endptr)) - return NULL; - - strncpy(out, text, out_len); - out[out_len-1] = '\0'; - *endptr = c; - - SkipWhileWhitespace(&endptr, c); - return endptr; -} - -template<typename T> -static bool StringToIntegerUntilCharWithCheck( - T *outptr, char *text, int base, int c, char **endptr) { - *outptr = StringToIntegerUntilChar<T>(*endptr, base, c, endptr); - if (*endptr == NULL || **endptr == '\0') return false; - ++(*endptr); - return true; -} - -static bool ParseProcMapsLine(char *text, uint64 *start, uint64 *end, - char *flags, uint64 *offset, - int *major, int *minor, int64 *inode, - unsigned *filename_offset) { -#if defined(__linux__) - /* - * It's similar to: - * sscanf(text, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n", - * start, end, flags, offset, major, minor, inode, filename_offset) - */ - char *endptr = text; - if (endptr == NULL || *endptr == '\0') return false; - - if (!StringToIntegerUntilCharWithCheck(start, endptr, 16, '-', &endptr)) - return false; - - if (!StringToIntegerUntilCharWithCheck(end, endptr, 16, ' ', &endptr)) - return false; - - endptr = CopyStringUntilChar(endptr, 5, ' ', flags); - if (endptr == NULL || *endptr == '\0') return false; - ++endptr; - - if (!StringToIntegerUntilCharWithCheck(offset, endptr, 16, ' ', &endptr)) - return false; - - if (!StringToIntegerUntilCharWithCheck(major, endptr, 16, ':', &endptr)) - return false; - - if (!StringToIntegerUntilCharWithCheck(minor, endptr, 16, ' ', &endptr)) - return false; - - if (!StringToIntegerUntilCharWithCheck(inode, endptr, 10, ' ', &endptr)) - return false; - - *filename_offset = (endptr - text); - return true; -#else - return false; -#endif -} - -ProcMapsIterator::ProcMapsIterator(pid_t pid) { - Init(pid, NULL, false); -} - -ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) { - Init(pid, buffer, false); -} - -ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer, - bool use_maps_backing) { - Init(pid, buffer, use_maps_backing); -} - -void ProcMapsIterator::Init(pid_t pid, Buffer *buffer, - bool use_maps_backing) { - pid_ = pid; - using_maps_backing_ = use_maps_backing; - dynamic_buffer_ = NULL; - if (!buffer) { - // If the user didn't pass in any buffer storage, allocate it - // now. This is the normal case; the signal handler passes in a - // static buffer. - buffer = dynamic_buffer_ = new Buffer; - } else { - dynamic_buffer_ = NULL; - } - - ibuf_ = buffer->buf_; - - stext_ = etext_ = nextline_ = ibuf_; - ebuf_ = ibuf_ + Buffer::kBufSize - 1; - nextline_ = ibuf_; - -#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__) - if (use_maps_backing) { // don't bother with clever "self" stuff in this case - ConstructFilename("/proc/%d/maps_backing", pid, ibuf_, Buffer::kBufSize); - } else if (pid == 0) { - // We have to kludge a bit to deal with the args ConstructFilename - // expects. The 1 is never used -- it's only impt. that it's not 0. - ConstructFilename("/proc/self/maps", 1, ibuf_, Buffer::kBufSize); - } else { - ConstructFilename("/proc/%d/maps", pid, ibuf_, Buffer::kBufSize); - } - // No error logging since this can be called from the crash dump - // handler at awkward moments. Users should call Valid() before - // using. - NO_INTR(fd_ = open(ibuf_, O_RDONLY)); -#elif defined(__FreeBSD__) - // We don't support maps_backing on freebsd - if (pid == 0) { - ConstructFilename("/proc/curproc/map", 1, ibuf_, Buffer::kBufSize); - } else { - ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); - } - NO_INTR(fd_ = open(ibuf_, O_RDONLY)); -#elif defined(__sun__) - if (pid == 0) { - ConstructFilename("/proc/self/map", 1, ibuf_, Buffer::kBufSize); - } else { - ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize); - } - NO_INTR(fd_ = open(ibuf_, O_RDONLY)); -#elif defined(__MACH__) - current_image_ = _dyld_image_count(); // count down from the top - current_load_cmd_ = -1; -#elif defined(PLATFORM_WINDOWS) - snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | - TH32CS_SNAPMODULE32, - GetCurrentProcessId()); - memset(&module_, 0, sizeof(module_)); -#else - fd_ = -1; // so Valid() is always false -#endif - -} - -ProcMapsIterator::~ProcMapsIterator() { -#if defined(PLATFORM_WINDOWS) - if (snapshot_ != INVALID_HANDLE_VALUE) CloseHandle(snapshot_); -#elif defined(__MACH__) - // no cleanup necessary! -#else - if (fd_ >= 0) NO_INTR(close(fd_)); -#endif - delete dynamic_buffer_; -} - -bool ProcMapsIterator::Valid() const { -#if defined(PLATFORM_WINDOWS) - return snapshot_ != INVALID_HANDLE_VALUE; -#elif defined(__MACH__) - return 1; -#else - return fd_ != -1; -#endif -} - -bool ProcMapsIterator::Next(uint64 *start, uint64 *end, char **flags, - uint64 *offset, int64 *inode, char **filename) { - return NextExt(start, end, flags, offset, inode, filename, NULL, NULL, - NULL, NULL, NULL); -} - -// This has too many arguments. It should really be building -// a map object and returning it. The problem is that this is called -// when the memory allocator state is undefined, hence the arguments. -bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags, - uint64 *offset, int64 *inode, char **filename, - uint64 *file_mapping, uint64 *file_pages, - uint64 *anon_mapping, uint64 *anon_pages, - dev_t *dev) { - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__CYGWIN32__) - do { - // Advance to the start of the next line - stext_ = nextline_; - - // See if we have a complete line in the buffer already - nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ - stext_)); - if (!nextline_) { - // Shift/fill the buffer so we do have a line - int count = etext_ - stext_; - - // Move the current text to the start of the buffer - memmove(ibuf_, stext_, count); - stext_ = ibuf_; - etext_ = ibuf_ + count; - - int nread = 0; // fill up buffer with text - while (etext_ < ebuf_) { - NO_INTR(nread = read(fd_, etext_, ebuf_ - etext_)); - if (nread > 0) - etext_ += nread; - else - break; - } - - // Zero out remaining characters in buffer at EOF to avoid returning - // garbage from subsequent calls. - if (etext_ != ebuf_ && nread == 0) { - memset(etext_, 0, ebuf_ - etext_); - } - *etext_ = '\n'; // sentinel; safe because ibuf extends 1 char beyond ebuf - nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ + 1 - stext_)); - } - *nextline_ = 0; // turn newline into nul - nextline_ += ((nextline_ < etext_)? 1 : 0); // skip nul if not end of text - // stext_ now points at a nul-terminated line - uint64 tmpstart, tmpend, tmpoffset; - int64 tmpinode; - int major, minor; - unsigned filename_offset = 0; -#if defined(__linux__) - // for now, assume all linuxes have the same format - if (!ParseProcMapsLine( - stext_, - start ? start : &tmpstart, - end ? end : &tmpend, - flags_, - offset ? offset : &tmpoffset, - &major, &minor, - inode ? inode : &tmpinode, &filename_offset)) continue; -#elif defined(__CYGWIN__) || defined(__CYGWIN32__) - // cygwin is like linux, except the third field is the "entry point" - // rather than the offset (see format_process_maps at - // http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/fhandler_process.cc?rev=1.89&content-type=text/x-cvsweb-markup&cvsroot=src - // Offset is always be 0 on cygwin: cygwin implements an mmap - // by loading the whole file and then calling NtMapViewOfSection. - // Cygwin also seems to set its flags kinda randomly; use windows default. - char tmpflags[5]; - if (offset) - *offset = 0; - strcpy(flags_, "r-xp"); - if (sscanf(stext_, "%llx-%llx %4s %llx %x:%x %lld %n", - start ? start : &tmpstart, - end ? end : &tmpend, - tmpflags, - &tmpoffset, - &major, &minor, - inode ? inode : &tmpinode, &filename_offset) != 7) continue; -#elif defined(__FreeBSD__) - // For the format, see http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/fs/procfs/procfs_map.c?rev=1.31&content-type=text/x-cvsweb-markup - tmpstart = tmpend = tmpoffset = 0; - tmpinode = 0; - major = minor = 0; // can't get this info in freebsd - if (inode) - *inode = 0; // nor this - if (offset) - *offset = 0; // seems like this should be in there, but maybe not - // start end resident privateresident obj(?) prot refcnt shadowcnt - // flags copy_on_write needs_copy type filename: - // 0x8048000 0x804a000 2 0 0xc104ce70 r-x 1 0 0x0 COW NC vnode /bin/cat - if (sscanf(stext_, "0x%" SCNx64 " 0x%" SCNx64 " %*d %*d %*p %3s %*d %*d 0x%*x %*s %*s %*s %n", - start ? start : &tmpstart, - end ? end : &tmpend, - flags_, - &filename_offset) != 3) continue; -#endif - - // Depending on the Linux kernel being used, there may or may not be a space - // after the inode if there is no filename. sscanf will in such situations - // nondeterministically either fill in filename_offset or not (the results - // differ on multiple calls in the same run even with identical arguments). - // We don't want to wander off somewhere beyond the end of the string. - size_t stext_length = strlen(stext_); - if (filename_offset == 0 || filename_offset > stext_length) - filename_offset = stext_length; - - // We found an entry - if (flags) *flags = flags_; - if (filename) *filename = stext_ + filename_offset; - if (dev) *dev = minor | (major << 8); - - if (using_maps_backing_) { - // Extract and parse physical page backing info. - char *backing_ptr = stext_ + filename_offset + - strlen(stext_+filename_offset); - - // find the second '(' - int paren_count = 0; - while (--backing_ptr > stext_) { - if (*backing_ptr == '(') { - ++paren_count; - if (paren_count >= 2) { - uint64 tmp_file_mapping; - uint64 tmp_file_pages; - uint64 tmp_anon_mapping; - uint64 tmp_anon_pages; - - sscanf(backing_ptr+1, "F %" SCNx64 " %" SCNd64 ") (A %" SCNx64 " %" SCNd64 ")", - file_mapping ? file_mapping : &tmp_file_mapping, - file_pages ? file_pages : &tmp_file_pages, - anon_mapping ? anon_mapping : &tmp_anon_mapping, - anon_pages ? anon_pages : &tmp_anon_pages); - // null terminate the file name (there is a space - // before the first (. - backing_ptr[-1] = 0; - break; - } - } - } - } - - return true; - } while (etext_ > ibuf_); -#elif defined(__sun__) - // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1 - static char kPerms[8][4] = { "---", "--x", "-w-", "-wx", - "r--", "r-x", "rw-", "rwx" }; - COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4); - COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2); - COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1); - Buffer object_path; - int nread = 0; // fill up buffer with text - NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t))); - if (nread == sizeof(prmap_t)) { - long inode_from_mapname = 0; - prmap_t* mapinfo = reinterpret_cast<prmap_t*>(ibuf_); - // Best-effort attempt to get the inode from the filename. I think the - // two middle ints are major and minor device numbers, but I'm not sure. - sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname); - - if (pid_ == 0) { - CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, - "/proc/self/path/%s", mapinfo->pr_mapname), - Buffer::kBufSize); - } else { - CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize, - "/proc/%d/path/%s", - static_cast<int>(pid_), mapinfo->pr_mapname), - Buffer::kBufSize); - } - ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX); - CHECK_LT(len, PATH_MAX); - if (len < 0) - len = 0; - current_filename_[len] = '\0'; - - if (start) *start = mapinfo->pr_vaddr; - if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size; - if (flags) *flags = kPerms[mapinfo->pr_mflags & 7]; - if (offset) *offset = mapinfo->pr_offset; - if (inode) *inode = inode_from_mapname; - if (filename) *filename = current_filename_; - if (file_mapping) *file_mapping = 0; - if (file_pages) *file_pages = 0; - if (anon_mapping) *anon_mapping = 0; - if (anon_pages) *anon_pages = 0; - if (dev) *dev = 0; - return true; - } -#elif defined(__MACH__) - // We return a separate entry for each segment in the DLL. (TODO(csilvers): - // can we do better?) A DLL ("image") has load-commands, some of which - // talk about segment boundaries. - // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/minivoicemail/dlfcn.c?revision=53912 - for (; current_image_ >= 0; current_image_--) { - const mach_header* hdr = _dyld_get_image_header(current_image_); - if (!hdr) continue; - if (current_load_cmd_ < 0) // set up for this image - current_load_cmd_ = hdr->ncmds; // again, go from the top down - - // We start with the next load command (we've already looked at this one). - for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) { -#ifdef MH_MAGIC_64 - if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64, - struct mach_header_64, struct segment_command_64>( - hdr, current_image_, current_load_cmd_, - start, end, flags, offset, inode, filename, - file_mapping, file_pages, anon_mapping, - anon_pages, dev)) { - return true; - } -#endif - if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT, - struct mach_header, struct segment_command>( - hdr, current_image_, current_load_cmd_, - start, end, flags, offset, inode, filename, - file_mapping, file_pages, anon_mapping, - anon_pages, dev)) { - return true; - } - } - // If we get here, no more load_cmd's in this image talk about - // segments. Go on to the next image. - } -#elif defined(PLATFORM_WINDOWS) - static char kDefaultPerms[5] = "r-xp"; - BOOL ok; - if (module_.dwSize == 0) { // only possible before first call - module_.dwSize = sizeof(module_); - ok = Module32First(snapshot_, &module_); - } else { - ok = Module32Next(snapshot_, &module_); - } - if (ok) { - uint64 base_addr = reinterpret_cast<DWORD_PTR>(module_.modBaseAddr); - if (start) *start = base_addr; - if (end) *end = base_addr + module_.modBaseSize; - if (flags) *flags = kDefaultPerms; - if (offset) *offset = 0; - if (inode) *inode = 0; - if (filename) *filename = module_.szExePath; - if (file_mapping) *file_mapping = 0; - if (file_pages) *file_pages = 0; - if (anon_mapping) *anon_mapping = 0; - if (anon_pages) *anon_pages = 0; - if (dev) *dev = 0; - return true; - } -#endif - - // We didn't find anything - return false; -} - -int ProcMapsIterator::FormatLine(char* buffer, int bufsize, - uint64 start, uint64 end, const char *flags, - uint64 offset, int64 inode, - const char *filename, dev_t dev) { - // We assume 'flags' looks like 'rwxp' or 'rwx'. - char r = (flags && flags[0] == 'r') ? 'r' : '-'; - char w = (flags && flags[0] && flags[1] == 'w') ? 'w' : '-'; - char x = (flags && flags[0] && flags[1] && flags[2] == 'x') ? 'x' : '-'; - // p always seems set on linux, so we set the default to 'p', not '-' - char p = (flags && flags[0] && flags[1] && flags[2] && flags[3] != 'p') - ? '-' : 'p'; - - const int rc = snprintf(buffer, bufsize, - "%08" PRIx64 "-%08" PRIx64 " %c%c%c%c %08" PRIx64 " %02x:%02x %-11" PRId64 " %s\n", - start, end, r,w,x,p, offset, - static_cast<int>(dev/256), static_cast<int>(dev%256), - inode, filename); - return (rc < 0 || rc >= bufsize) ? 0 : rc; -} - -namespace tcmalloc { - -// Helper to add the list of mapped shared libraries to a profile. -// Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size' -// and return the actual size occupied in 'buf'. We fill wrote_all to true -// if we successfully wrote all proc lines to buf, false else. -// We do not provision for 0-terminating 'buf'. -int FillProcSelfMaps(char buf[], int size, bool* wrote_all) { - ProcMapsIterator::Buffer iterbuf; - ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" - - uint64 start, end, offset; - int64 inode; - char *flags, *filename; - int bytes_written = 0; - *wrote_all = true; - while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { - const int line_length = it.FormatLine(buf + bytes_written, - size - bytes_written, - start, end, flags, offset, - inode, filename, 0); - if (line_length == 0) - *wrote_all = false; // failed to write this line out - else - bytes_written += line_length; - - } - return bytes_written; -} - -// Dump the same data as FillProcSelfMaps reads to fd. -// It seems easier to repeat parts of FillProcSelfMaps here than to -// reuse it via a call. -void DumpProcSelfMaps(RawFD fd) { - ProcMapsIterator::Buffer iterbuf; - ProcMapsIterator it(0, &iterbuf); // 0 means "current pid" - - uint64 start, end, offset; - int64 inode; - char *flags, *filename; - ProcMapsIterator::Buffer linebuf; - while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) { - int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_), - start, end, flags, offset, inode, filename, - 0); - RawWrite(fd, linebuf.buf_, written); - } -} - -} // namespace tcmalloc