blob: 11905557063fd4d464577ab7cbf3ac835d508ef4 [file] [log] [blame]
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
#define CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/condition_variable.h"
#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/time.h"
class MessageLoop;
class Task;
class HistogramSynchronizer : public
base::RefCountedThreadSafe<HistogramSynchronizer> {
public:
enum RendererHistogramRequester {
ASYNC_HISTOGRAMS,
SYNCHRONOUS_HISTOGRAMS
};
static const int kReservedSequenceNumber = 0;
HistogramSynchronizer();
~HistogramSynchronizer();
// Return pointer to the singleton instance, which is allocated and
// deallocated on the main UI thread (during system startup and teardown).
static HistogramSynchronizer* CurrentSynchronizer();
// Contact all renderers, and get them to upload to the browser any/all
// changes to histograms. Return when all changes have been acquired, or when
// the wait time expires (whichever is sooner). This method is called on the
// main UI thread from about:histograms.
void FetchRendererHistogramsSynchronously(base::TimeDelta wait_time);
// Contact all renderers, and get them to upload to the browser any/all
// changes to histograms. When all changes have been acquired, or when the
// wait time expires (whichever is sooner), post the callback_task to the UI
// thread. Note the callback_task is posted exactly once. This method is
// called on the IO thread from UMA via PostMessage.
static void FetchRendererHistogramsAsynchronously(
MessageLoop* callback_thread, Task* callback_task, int wait_time);
// This method is called on the IO thread. Desrializes the histograms and
// records that we have received histograms from a renderer process.
static void DeserializeHistogramList(
int sequence_number, const std::vector<std::string>& histograms);
private:
// Records that we have received the histograms from a renderer for the given
// sequence number. If we have received a response from all histograms, either
// signal the waiting process or call the callback function. Returns true when
// we receive histograms from the last of N renderers that were contacted for
// an update. This is called on IO Thread.
bool RecordRendererHistogram(int sequence_number);
void SetCallbackTaskToCallAfterGettingHistograms(
MessageLoop* callback_thread, Task* callback_task);
void ForceHistogramSynchronizationDoneCallback(int sequence_number);
// Calls the callback task, if there is a callback_task.
void CallCallbackTaskAndResetData();
// Gets a new sequence number to be sent to renderers from broswer process.
// This will also reset the current pending renderers for the given type.
int GetNextAvaibleSequenceNumber(RendererHistogramRequester requster);
// Increments the count of the renderers we're waiting for for the request
// of the given type.
void IncrementPendingRenderers(RendererHistogramRequester requester);
// For use ONLY in a DCHECK. This method initializes io_message_loop_ in its
// first call and then compares io_message_loop_ with MessageLoop::current()
// in subsequent calls. This method guarantees we're consistently on the
// singular IO thread and we don't need to worry about locks.
bool IsOnIoThread();
// This lock_ protects access to sequence number and
// synchronous_renderers_pending_.
Lock lock_;
// This condition variable is used to block caller of the synchronous request
// to update histograms, and to signal that thread when updates are completed.
ConditionVariable received_all_renderer_historgrams_;
// When a request is made to asynchronously update the histograms, we store
// the task and thread we use to post a completion notification in
// callback_task_ and callback_thread_.
Task* callback_task_;
MessageLoop* callback_thread_;
// For use ONLY in a DCHECK and is used in IsOnIoThread(). io_message_loop_ is
// initialized during the first call to IsOnIoThread(), and then compares
// MessageLoop::current() against io_message_loop_ in subsequent calls for
// consistency.
MessageLoop* io_message_loop_;
// We don't track the actual renderers that are contacted for an update, only
// the count of the number of renderers, and we can sometimes time-out and
// give up on a "slow to respond" renderer. We use a sequence_number to be
// sure a response from a renderer is associated with the current round of
// requests (and not merely a VERY belated prior response).
// next_available_sequence_number_ is the next available number (used to
// avoid reuse for a long time).
int next_available_sequence_number_;
// The sequence number used by the most recent asynchronous update request to
// contact all renderers.
int async_sequence_number_;
// The number of renderers that have not yet responded to requests (as part of
// an asynchronous update).
int async_renderers_pending_;
// The time when we were told to start the fetch histograms asynchronously
// from renderers.
base::TimeTicks async_callback_start_time_;
// The sequence number used by the most recent synchronous update request to
// contact all renderers.
int synchronous_sequence_number_;
// The number of renderers that have not yet responded to requests (as part of
// a synchronous update).
int synchronous_renderers_pending_;
// This singleton instance should be started during the single threaded
// portion of main(). It initializes globals to provide support for all future
// calls. This object is created on the UI thread, and it is destroyed after
// all the other threads have gone away. As a result, it is ok to call it
// from the UI thread (for UMA uploads), or for about:histograms.
static HistogramSynchronizer* histogram_synchronizer_;
DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer);
};
#endif // CHROME_COMMON_HISTOGRAM_SYNCHRONIZER_H_