| Index: base/metrics/stats_table.cc
|
| diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc
|
| index 403e28c9297c3da629ff1e21d7af85beae1f647c..716b7cfc91db93de1b618ffb31592c7c23bdd7dc 100644
|
| --- a/base/metrics/stats_table.cc
|
| +++ b/base/metrics/stats_table.cc
|
| @@ -15,7 +15,9 @@
|
| #include "base/threading/thread_local_storage.h"
|
|
|
| #if defined(OS_POSIX)
|
| +#include "base/posix/global_descriptors.h"
|
| #include "errno.h"
|
| +#include "ipc/ipc_descriptors.h"
|
| #endif
|
|
|
| namespace base {
|
| @@ -88,10 +90,10 @@ inline int AlignedSize(int size) {
|
|
|
| } // namespace
|
|
|
| -// The StatsTable::Private maintains convenience pointers into the
|
| +// The StatsTable::Internal maintains convenience pointers into the
|
| // shared memory segment. Use this class to keep the data structure
|
| // clean and accessible.
|
| -class StatsTable::Private {
|
| +class StatsTable::Internal {
|
| public:
|
| // Various header information contained in the memory mapped segment.
|
| struct TableHeader {
|
| @@ -101,12 +103,14 @@ class StatsTable::Private {
|
| int max_threads;
|
| };
|
|
|
| - // Construct a new Private based on expected size parameters, or
|
| + // Construct a new Internal based on expected size parameters, or
|
| // return NULL on failure.
|
| - static Private* New(const std::string& name, int size,
|
| - int max_threads, int max_counters);
|
| + static Internal* New(const std::string& name,
|
| + int size,
|
| + int max_threads,
|
| + int max_counters);
|
|
|
| - SharedMemory* shared_memory() { return &shared_memory_; }
|
| + SharedMemory* shared_memory() { return shared_memory_.get(); }
|
|
|
| // Accessors for our header pointers
|
| TableHeader* table_header() const { return table_header_; }
|
| @@ -136,8 +140,9 @@ class StatsTable::Private {
|
|
|
| private:
|
| // Constructor is private because you should use New() instead.
|
| - Private()
|
| - : table_header_(NULL),
|
| + explicit Internal(SharedMemory* shared_memory)
|
| + : shared_memory_(shared_memory),
|
| + table_header_(NULL),
|
| thread_names_table_(NULL),
|
| thread_tid_table_(NULL),
|
| thread_pid_table_(NULL),
|
| @@ -145,6 +150,10 @@ class StatsTable::Private {
|
| data_table_(NULL) {
|
| }
|
|
|
| + // Create or open the SharedMemory used by the stats table.
|
| + static SharedMemory* CreateSharedMemory(const std::string& name,
|
| + int size);
|
| +
|
| // Initializes the table on first access. Sets header values
|
| // appropriately and zeroes all counters.
|
| void InitializeTable(void* memory, int size, int max_counters,
|
| @@ -153,41 +162,68 @@ class StatsTable::Private {
|
| // Initializes our in-memory pointers into a pre-created StatsTable.
|
| void ComputeMappedPointers(void* memory);
|
|
|
| - SharedMemory shared_memory_;
|
| + scoped_ptr<SharedMemory> shared_memory_;
|
| TableHeader* table_header_;
|
| char* thread_names_table_;
|
| PlatformThreadId* thread_tid_table_;
|
| int* thread_pid_table_;
|
| char* counter_names_table_;
|
| int* data_table_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Internal);
|
| };
|
|
|
| // static
|
| -StatsTable::Private* StatsTable::Private::New(const std::string& name,
|
| - int size,
|
| - int max_threads,
|
| - int max_counters) {
|
| - scoped_ptr<Private> priv(new Private());
|
| - if (!priv->shared_memory_.CreateNamed(name, true, size))
|
| +StatsTable::Internal* StatsTable::Internal::New(const std::string& name,
|
| + int size,
|
| + int max_threads,
|
| + int max_counters) {
|
| + scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(name, size));
|
| + if (!shared_memory.get())
|
| return NULL;
|
| - if (!priv->shared_memory_.Map(size))
|
| + if (!shared_memory->Map(size))
|
| return NULL;
|
| - void* memory = priv->shared_memory_.memory();
|
| + void* memory = shared_memory->memory();
|
|
|
| + scoped_ptr<Internal> internal(new Internal(shared_memory.release()));
|
| TableHeader* header = static_cast<TableHeader*>(memory);
|
|
|
| // If the version does not match, then assume the table needs
|
| // to be initialized.
|
| if (header->version != kTableVersion)
|
| - priv->InitializeTable(memory, size, max_counters, max_threads);
|
| + internal->InitializeTable(memory, size, max_counters, max_threads);
|
|
|
| // We have a valid table, so compute our pointers.
|
| - priv->ComputeMappedPointers(memory);
|
| + internal->ComputeMappedPointers(memory);
|
| +
|
| + return internal.release();
|
| +}
|
|
|
| - return priv.release();
|
| +// static
|
| +SharedMemory* StatsTable::Internal::CreateSharedMemory(const std::string& name,
|
| + int size) {
|
| +#if defined(OS_POSIX)
|
| + GlobalDescriptors* global_descriptors = GlobalDescriptors::GetInstance();
|
| + if (global_descriptors->MaybeGet(kStatsTableSharedMemFd) != -1) {
|
| + // Open the shared memory file descriptor passed by the browser process.
|
| + FileDescriptor file_descriptor(
|
| + global_descriptors->Get(kStatsTableSharedMemFd), false);
|
| + return new SharedMemory(file_descriptor, false);
|
| + }
|
| + // Otherwise we need to create it.
|
| + scoped_ptr<SharedMemory> shared_memory(new SharedMemory());
|
| + if (!shared_memory->CreateAnonymous(size))
|
| + return NULL;
|
| + return shared_memory.release();
|
| +#elif defined(OS_WIN)
|
| + scoped_ptr<SharedMemory> shared_memory(new SharedMemory());
|
| + if (!shared_memory->CreateNamed(name, true, size))
|
| + return NULL;
|
| + return shared_memory.release();
|
| +#endif
|
| }
|
|
|
| -void StatsTable::Private::InitializeTable(void* memory, int size,
|
| +void StatsTable::Internal::InitializeTable(void* memory, int size,
|
| int max_counters,
|
| int max_threads) {
|
| // Zero everything.
|
| @@ -201,7 +237,7 @@ void StatsTable::Private::InitializeTable(void* memory, int size,
|
| header->max_threads = max_threads;
|
| }
|
|
|
| -void StatsTable::Private::ComputeMappedPointers(void* memory) {
|
| +void StatsTable::Internal::ComputeMappedPointers(void* memory) {
|
| char* data = static_cast<char*>(memory);
|
| int offset = 0;
|
|
|
| @@ -252,19 +288,19 @@ StatsTable* global_table = NULL;
|
|
|
| StatsTable::StatsTable(const std::string& name, int max_threads,
|
| int max_counters)
|
| - : impl_(NULL),
|
| + : internal_(NULL),
|
| tls_index_(SlotReturnFunction) {
|
| int table_size =
|
| - AlignedSize(sizeof(Private::TableHeader)) +
|
| + AlignedSize(sizeof(Internal::TableHeader)) +
|
| AlignedSize((max_counters * sizeof(char) * kMaxCounterNameLength)) +
|
| AlignedSize((max_threads * sizeof(char) * kMaxThreadNameLength)) +
|
| AlignedSize(max_threads * sizeof(int)) +
|
| AlignedSize(max_threads * sizeof(int)) +
|
| AlignedSize((sizeof(int) * (max_counters * max_threads)));
|
|
|
| - impl_ = Private::New(name, table_size, max_threads, max_counters);
|
| + internal_ = Internal::New(name, table_size, max_threads, max_counters);
|
|
|
| - if (!impl_)
|
| + if (!internal_)
|
| DPLOG(ERROR) << "StatsTable did not initialize";
|
| }
|
|
|
| @@ -278,7 +314,7 @@ StatsTable::~StatsTable() {
|
| tls_index_.Free();
|
|
|
| // Cleanup our shared memory.
|
| - delete impl_;
|
| + delete internal_;
|
|
|
| // If we are the global table, unregister ourselves.
|
| if (global_table == this)
|
| @@ -302,14 +338,14 @@ int StatsTable::GetSlot() const {
|
|
|
| int StatsTable::RegisterThread(const std::string& name) {
|
| int slot = 0;
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| // Registering a thread requires that we lock the shared memory
|
| // so that two threads don't grab the same slot. Fortunately,
|
| // thread creation shouldn't happen in inner loops.
|
| {
|
| - SharedMemoryAutoLock lock(impl_->shared_memory());
|
| + SharedMemoryAutoLock lock(internal_->shared_memory());
|
| slot = FindEmptyThread();
|
| if (!slot) {
|
| return 0;
|
| @@ -319,10 +355,10 @@ int StatsTable::RegisterThread(const std::string& name) {
|
| std::string thread_name = name;
|
| if (name.empty())
|
| thread_name = kUnknownName;
|
| - strlcpy(impl_->thread_name(slot), thread_name.c_str(),
|
| + strlcpy(internal_->thread_name(slot), thread_name.c_str(),
|
| kMaxThreadNameLength);
|
| - *(impl_->thread_tid(slot)) = PlatformThread::CurrentId();
|
| - *(impl_->thread_pid(slot)) = GetCurrentProcId();
|
| + *(internal_->thread_tid(slot)) = PlatformThread::CurrentId();
|
| + *(internal_->thread_pid(slot)) = GetCurrentProcId();
|
| }
|
|
|
| // Set our thread local storage.
|
| @@ -334,14 +370,14 @@ int StatsTable::RegisterThread(const std::string& name) {
|
| }
|
|
|
| int StatsTable::CountThreadsRegistered() const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| // Loop through the shared memory and count the threads that are active.
|
| // We intentionally do not lock the table during the operation.
|
| int count = 0;
|
| - for (int index = 1; index <= impl_->max_threads(); index++) {
|
| - char* name = impl_->thread_name(index);
|
| + for (int index = 1; index <= internal_->max_threads(); index++) {
|
| + char* name = internal_->thread_name(index);
|
| if (*name != '\0')
|
| count++;
|
| }
|
| @@ -352,7 +388,7 @@ int StatsTable::FindCounter(const std::string& name) {
|
| // Note: the API returns counters numbered from 1..N, although
|
| // internally, the array is 0..N-1. This is so that we can return
|
| // zero as "not found".
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| // Create a scope for our auto-lock.
|
| @@ -371,20 +407,20 @@ int StatsTable::FindCounter(const std::string& name) {
|
| }
|
|
|
| int* StatsTable::GetLocation(int counter_id, int slot_id) const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return NULL;
|
| - if (slot_id > impl_->max_threads())
|
| + if (slot_id > internal_->max_threads())
|
| return NULL;
|
|
|
| - int* row = impl_->row(counter_id);
|
| + int* row = internal_->row(counter_id);
|
| return &(row[slot_id-1]);
|
| }
|
|
|
| const char* StatsTable::GetRowName(int index) const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return NULL;
|
|
|
| - return impl_->counter_name(index);
|
| + return internal_->counter_name(index);
|
| }
|
|
|
| int StatsTable::GetRowValue(int index) const {
|
| @@ -392,13 +428,13 @@ int StatsTable::GetRowValue(int index) const {
|
| }
|
|
|
| int StatsTable::GetRowValue(int index, int pid) const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| int rv = 0;
|
| - int* row = impl_->row(index);
|
| - for (int slot_id = 1; slot_id <= impl_->max_threads(); slot_id++) {
|
| - if (pid == 0 || *impl_->thread_pid(slot_id) == pid)
|
| + int* row = internal_->row(index);
|
| + for (int slot_id = 1; slot_id <= internal_->max_threads(); slot_id++) {
|
| + if (pid == 0 || *internal_->thread_pid(slot_id) == pid)
|
| rv += row[slot_id-1];
|
| }
|
| return rv;
|
| @@ -409,7 +445,7 @@ int StatsTable::GetCounterValue(const std::string& name) {
|
| }
|
|
|
| int StatsTable::GetCounterValue(const std::string& name, int pid) {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| int row = FindCounter(name);
|
| @@ -419,15 +455,15 @@ int StatsTable::GetCounterValue(const std::string& name, int pid) {
|
| }
|
|
|
| int StatsTable::GetMaxCounters() const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
| - return impl_->max_counters();
|
| + return internal_->max_counters();
|
| }
|
|
|
| int StatsTable::GetMaxThreads() const {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
| - return impl_->max_threads();
|
| + return internal_->max_threads();
|
| }
|
|
|
| int* StatsTable::FindLocation(const char* name) {
|
| @@ -457,10 +493,10 @@ void StatsTable::UnregisterThread() {
|
| void StatsTable::UnregisterThread(TLSData* data) {
|
| if (!data)
|
| return;
|
| - DCHECK(impl_);
|
| + DCHECK(internal_);
|
|
|
| // Mark the slot free by zeroing out the thread name.
|
| - char* name = impl_->thread_name(data->slot);
|
| + char* name = internal_->thread_name(data->slot);
|
| *name = '\0';
|
|
|
| // Remove the calling thread's TLS so that it cannot use the slot.
|
| @@ -488,16 +524,16 @@ int StatsTable::FindEmptyThread() const {
|
| // in TLS, which is always initialized to zero, not -1. If 0 were
|
| // returned as a valid slot number, it would be confused with the
|
| // uninitialized state.
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| int index = 1;
|
| - for (; index <= impl_->max_threads(); index++) {
|
| - char* name = impl_->thread_name(index);
|
| + for (; index <= internal_->max_threads(); index++) {
|
| + char* name = internal_->thread_name(index);
|
| if (!*name)
|
| break;
|
| }
|
| - if (index > impl_->max_threads())
|
| + if (index > internal_->max_threads())
|
| return 0; // The table is full.
|
| return index;
|
| }
|
| @@ -510,12 +546,12 @@ int StatsTable::FindCounterOrEmptyRow(const std::string& name) const {
|
| // There isn't much reason for this other than to be consistent
|
| // with the way we track columns for thread slots. (See comments
|
| // in FindEmptyThread for why it is done this way).
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| int free_slot = 0;
|
| - for (int index = 1; index <= impl_->max_counters(); index++) {
|
| - char* row_name = impl_->counter_name(index);
|
| + for (int index = 1; index <= internal_->max_counters(); index++) {
|
| + char* row_name = internal_->counter_name(index);
|
| if (!*row_name && !free_slot)
|
| free_slot = index; // save that we found a free slot
|
| else if (!strncmp(row_name, name.c_str(), kMaxCounterNameLength))
|
| @@ -525,14 +561,14 @@ int StatsTable::FindCounterOrEmptyRow(const std::string& name) const {
|
| }
|
|
|
| int StatsTable::AddCounter(const std::string& name) {
|
| - if (!impl_)
|
| + if (!internal_)
|
| return 0;
|
|
|
| int counter_id = 0;
|
| {
|
| // To add a counter to the shared memory, we need the
|
| // shared memory lock.
|
| - SharedMemoryAutoLock lock(impl_->shared_memory());
|
| + SharedMemoryAutoLock lock(internal_->shared_memory());
|
|
|
| // We have space, so create a new counter.
|
| counter_id = FindCounterOrEmptyRow(name);
|
| @@ -542,7 +578,7 @@ int StatsTable::AddCounter(const std::string& name) {
|
| std::string counter_name = name;
|
| if (name.empty())
|
| counter_name = kUnknownName;
|
| - strlcpy(impl_->counter_name(counter_id), counter_name.c_str(),
|
| + strlcpy(internal_->counter_name(counter_id), counter_name.c_str(),
|
| kMaxCounterNameLength);
|
| }
|
|
|
| @@ -565,4 +601,12 @@ StatsTable::TLSData* StatsTable::GetTLSData() const {
|
| return data;
|
| }
|
|
|
| +#if defined(OS_POSIX)
|
| +SharedMemoryHandle StatsTable::GetSharedMemoryHandle() const {
|
| + if (!internal_)
|
| + return SharedMemory::NULLHandle();
|
| + return internal_->shared_memory()->handle();
|
| +}
|
| +#endif
|
| +
|
| } // namespace base
|
|
|