summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/debug/trace_event_impl.cc185
-rw-r--r--base/debug/trace_event_impl.h27
-rw-r--r--base/debug/trace_event_unittest.cc83
3 files changed, 193 insertions, 102 deletions
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index ab282e7..176f67c 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -910,62 +910,71 @@ void TraceLog::GetKnownCategoryGroups(
void TraceLog::SetEnabled(const CategoryFilter& category_filter,
Options options) {
- AutoLock lock(lock_);
+ std::vector<EnabledStateObserver*> observer_list;
+ {
+ AutoLock lock(lock_);
- if (enable_count_++ > 0) {
- if (options != trace_options_) {
- DLOG(ERROR) << "Attemting to re-enable tracing with a different "
- << "set of options.";
+ if (enable_count_++ > 0) {
+ if (options != trace_options_) {
+ DLOG(ERROR) << "Attemting to re-enable tracing with a different "
+ << "set of options.";
+ }
+
+ category_filter_.Merge(category_filter);
+ EnableIncludedCategoryGroups();
+ return;
}
- category_filter_.Merge(category_filter);
- EnableIncludedCategoryGroups();
- return;
- }
+ if (options != trace_options_) {
+ trace_options_ = options;
+ logged_events_.reset(GetTraceBuffer());
+ }
- if (options != trace_options_) {
- trace_options_ = options;
- logged_events_.reset(GetTraceBuffer());
- }
+ if (dispatching_to_observer_list_) {
+ DLOG(ERROR) <<
+ "Cannot manipulate TraceLog::Enabled state from an observer.";
+ return;
+ }
- if (dispatching_to_observer_list_) {
- DLOG(ERROR) <<
- "Cannot manipulate TraceLog::Enabled state from an observer.";
- return;
- }
+ num_traces_recorded_++;
- num_traces_recorded_++;
+ category_filter_ = CategoryFilter(category_filter);
+ EnableIncludedCategoryGroups();
- dispatching_to_observer_list_ = true;
- FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
- OnTraceLogWillEnable());
- dispatching_to_observer_list_ = false;
+ // Not supported in split-dll build. http://crbug.com/237249
+ #if !defined(CHROME_SPLIT_DLL)
+ if (options & ENABLE_SAMPLING) {
+ sampling_thread_.reset(new TraceSamplingThread);
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state0,
+ "bucket0",
+ Bind(&TraceSamplingThread::DefaultSampleCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state1,
+ "bucket1",
+ Bind(&TraceSamplingThread::DefaultSampleCallback));
+ sampling_thread_->RegisterSampleBucket(
+ &g_trace_state2,
+ "bucket2",
+ Bind(&TraceSamplingThread::DefaultSampleCallback));
+ if (!PlatformThread::Create(
+ 0, sampling_thread_.get(), &sampling_thread_handle_)) {
+ DCHECK(false) << "failed to create thread";
+ }
+ }
+ #endif
- category_filter_ = CategoryFilter(category_filter);
- EnableIncludedCategoryGroups();
+ dispatching_to_observer_list_ = true;
+ observer_list = enabled_state_observer_list_;
+ }
+ // Notify observers outside the lock in case they trigger trace events.
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ observer_list[i]->OnTraceLogEnabled();
- // Not supported in split-dll build. http://crbug.com/237249
-#if !defined(CHROME_SPLIT_DLL)
- if (options & ENABLE_SAMPLING) {
- sampling_thread_.reset(new TraceSamplingThread);
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state0,
- "bucket0",
- Bind(&TraceSamplingThread::DefaultSampleCallback));
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state1,
- "bucket1",
- Bind(&TraceSamplingThread::DefaultSampleCallback));
- sampling_thread_->RegisterSampleBucket(
- &g_trace_state2,
- "bucket2",
- Bind(&TraceSamplingThread::DefaultSampleCallback));
- if (!PlatformThread::Create(
- 0, sampling_thread_.get(), &sampling_thread_handle_)) {
- DCHECK(false) << "failed to create thread";
- }
+ {
+ AutoLock lock(lock_);
+ dispatching_to_observer_list_ = false;
}
-#endif
}
const CategoryFilter& TraceLog::GetCurrentCategoryFilter() {
@@ -975,39 +984,49 @@ const CategoryFilter& TraceLog::GetCurrentCategoryFilter() {
}
void TraceLog::SetDisabled() {
- AutoLock lock(lock_);
- DCHECK(enable_count_ > 0);
- if (--enable_count_ != 0)
- return;
+ std::vector<EnabledStateObserver*> observer_list;
+ {
+ AutoLock lock(lock_);
+ DCHECK(enable_count_ > 0);
+ if (--enable_count_ != 0)
+ return;
- if (dispatching_to_observer_list_) {
- DLOG(ERROR)
- << "Cannot manipulate TraceLog::Enabled state from an observer.";
- return;
- }
+ if (dispatching_to_observer_list_) {
+ DLOG(ERROR)
+ << "Cannot manipulate TraceLog::Enabled state from an observer.";
+ return;
+ }
- if (sampling_thread_.get()) {
- // Stop the sampling thread.
- sampling_thread_->Stop();
- lock_.Release();
- PlatformThread::Join(sampling_thread_handle_);
- lock_.Acquire();
- sampling_thread_handle_ = PlatformThreadHandle();
- sampling_thread_.reset();
+ if (sampling_thread_.get()) {
+ // Stop the sampling thread.
+ sampling_thread_->Stop();
+ lock_.Release();
+ PlatformThread::Join(sampling_thread_handle_);
+ lock_.Acquire();
+ sampling_thread_handle_ = PlatformThreadHandle();
+ sampling_thread_.reset();
+ }
+
+ category_filter_.Clear();
+ watch_category_ = NULL;
+ watch_event_name_ = "";
+ for (int i = 0; i < g_category_index; i++)
+ SetCategoryGroupEnabled(i, false);
+ AddThreadNameMetadataEvents();
+
+ dispatching_to_observer_list_ = true;
+ observer_list = enabled_state_observer_list_;
}
- dispatching_to_observer_list_ = true;
- FOR_EACH_OBSERVER(EnabledStateChangedObserver,
- enabled_state_observer_list_,
- OnTraceLogWillDisable());
- dispatching_to_observer_list_ = false;
+ // Dispatch to observers outside the lock in case the observer triggers a
+ // trace event.
+ for (size_t i = 0; i < observer_list.size(); ++i)
+ observer_list[i]->OnTraceLogDisabled();
- category_filter_.Clear();
- watch_category_ = NULL;
- watch_event_name_ = "";
- for (int i = 0; i < g_category_index; i++)
- SetCategoryGroupEnabled(i, false);
- AddThreadNameMetadataEvents();
+ {
+ AutoLock lock(lock_);
+ dispatching_to_observer_list_ = false;
+ }
}
int TraceLog::GetNumTracesRecorded() {
@@ -1017,13 +1036,17 @@ int TraceLog::GetNumTracesRecorded() {
return num_traces_recorded_;
}
-void TraceLog::AddEnabledStateObserver(EnabledStateChangedObserver* listener) {
- enabled_state_observer_list_.AddObserver(listener);
+void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
+ enabled_state_observer_list_.push_back(listener);
}
-void TraceLog::RemoveEnabledStateObserver(
- EnabledStateChangedObserver* listener) {
- enabled_state_observer_list_.RemoveObserver(listener);
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+ std::vector<EnabledStateObserver*>::iterator it =
+ std::find(enabled_state_observer_list_.begin(),
+ enabled_state_observer_list_.end(),
+ listener);
+ if (it != enabled_state_observer_list_.end())
+ enabled_state_observer_list_.erase(it);
}
float TraceLog::GetBufferPercentFull() const {
@@ -1320,6 +1343,10 @@ void TraceLog::SetTimeOffset(TimeDelta offset) {
time_offset_ = offset;
}
+size_t TraceLog::GetObserverCountForTest() const {
+ return enabled_state_observer_list_.size();
+}
+
bool CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
const std::string& str) {
return str.empty() ||
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 384e09f..a7ebaf2 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -332,21 +332,18 @@ class BASE_EXPORT TraceLog {
// Enabled state listeners give a callback when tracing is enabled or
// disabled. This can be used to tie into other library's tracing systems
// on-demand.
- class EnabledStateChangedObserver {
+ class EnabledStateObserver {
public:
- // Called just before the tracing system becomes
- // enabled. TraceLog::IsEnabled will return false at this point and trace
- // macros and methods called within the observer will deadlock.
- virtual void OnTraceLogWillEnable() { }
-
- // Called just before the tracing system disables. TraceLog::IsEnabled is
- // still false at this point TRACE macros will still be capturing
- // data. However, trace macros and methods called within the observer will
- // deadlock.
- virtual void OnTraceLogWillDisable() { }
+ // Called just after the tracing system becomes enabled, outside of the
+ // |lock_|. TraceLog::IsEnabled() is true at this point.
+ virtual void OnTraceLogEnabled() = 0;
+
+ // Called just after the tracing system disables, outside of the |lock_|.
+ // TraceLog::IsEnabled() is false at this point.
+ virtual void OnTraceLogDisabled() = 0;
};
- void AddEnabledStateObserver(EnabledStateChangedObserver* listener);
- void RemoveEnabledStateObserver(EnabledStateChangedObserver* listener);
+ void AddEnabledStateObserver(EnabledStateObserver* listener);
+ void RemoveEnabledStateObserver(EnabledStateObserver* listener);
float GetBufferPercentFull() const;
@@ -458,6 +455,8 @@ class BASE_EXPORT TraceLog {
// that should be reported.
void SetTimeOffset(TimeDelta offset);
+ size_t GetObserverCountForTest() const;
+
private:
// This allows constructor and destructor to be private and usable only
// by the Singleton class.
@@ -538,7 +537,7 @@ class BASE_EXPORT TraceLog {
scoped_ptr<TraceBuffer> logged_events_;
EventCallback event_callback_;
bool dispatching_to_observer_list_;
- ObserverList<EnabledStateChangedObserver> enabled_state_observer_list_;
+ std::vector<EnabledStateObserver*> enabled_state_observer_list_;
base::hash_map<int, std::string> thread_names_;
base::hash_map<int, std::stack<TimeTicks> > thread_event_start_times_;
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index d2d38c7..8685ceb 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -819,10 +819,10 @@ TEST_F(TraceEventTestFixture, DataCaptured) {
}
class MockEnabledStateChangedObserver :
- public base::debug::TraceLog::EnabledStateChangedObserver {
+ public base::debug::TraceLog::EnabledStateObserver {
public:
- MOCK_METHOD0(OnTraceLogWillEnable, void());
- MOCK_METHOD0(OnTraceLogWillDisable, void());
+ MOCK_METHOD0(OnTraceLogEnabled, void());
+ MOCK_METHOD0(OnTraceLogDisabled, void());
};
TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
@@ -831,11 +831,12 @@ TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
MockEnabledStateChangedObserver observer;
TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
- EXPECT_CALL(observer, OnTraceLogWillEnable())
+ EXPECT_CALL(observer, OnTraceLogEnabled())
.Times(1);
TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
TraceLog::RECORD_UNTIL_FULL);
testing::Mock::VerifyAndClear(&observer);
+ EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
// Cleanup.
TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
@@ -851,13 +852,14 @@ TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
testing::StrictMock<MockEnabledStateChangedObserver> observer;
TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
- EXPECT_CALL(observer, OnTraceLogWillEnable())
+ EXPECT_CALL(observer, OnTraceLogEnabled())
.Times(0);
- EXPECT_CALL(observer, OnTraceLogWillDisable())
+ EXPECT_CALL(observer, OnTraceLogDisabled())
.Times(0);
TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
TraceLog::RECORD_UNTIL_FULL);
testing::Mock::VerifyAndClear(&observer);
+ EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
// Cleanup.
TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
@@ -875,9 +877,9 @@ TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnNestedDisable) {
testing::StrictMock<MockEnabledStateChangedObserver> observer;
TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
- EXPECT_CALL(observer, OnTraceLogWillEnable())
+ EXPECT_CALL(observer, OnTraceLogEnabled())
.Times(0);
- EXPECT_CALL(observer, OnTraceLogWillDisable())
+ EXPECT_CALL(observer, OnTraceLogDisabled())
.Times(0);
TraceLog::GetInstance()->SetDisabled();
testing::Mock::VerifyAndClear(&observer);
@@ -896,7 +898,7 @@ TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
MockEnabledStateChangedObserver observer;
TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
- EXPECT_CALL(observer, OnTraceLogWillDisable())
+ EXPECT_CALL(observer, OnTraceLogDisabled())
.Times(1);
TraceLog::GetInstance()->SetDisabled();
testing::Mock::VerifyAndClear(&observer);
@@ -905,6 +907,69 @@ TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
}
+// Tests the IsEnabled() state of TraceLog changes before callbacks.
+class AfterStateChangeEnabledStateObserver
+ : public base::debug::TraceLog::EnabledStateObserver {
+ public:
+ AfterStateChangeEnabledStateObserver() {}
+ virtual ~AfterStateChangeEnabledStateObserver() {}
+
+ // base::debug::TraceLog::EnabledStateObserver overrides:
+ virtual void OnTraceLogEnabled() OVERRIDE {
+ EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+ }
+
+ virtual void OnTraceLogDisabled() OVERRIDE {
+ EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+ }
+};
+
+TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) {
+ ManualTestSetUp();
+
+ AfterStateChangeEnabledStateObserver observer;
+ TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+ TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+ TraceLog::RECORD_UNTIL_FULL);
+ EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+
+ TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Tests that a state observer can remove itself during a callback.
+class SelfRemovingEnabledStateObserver
+ : public base::debug::TraceLog::EnabledStateObserver {
+ public:
+ SelfRemovingEnabledStateObserver() {}
+ virtual ~SelfRemovingEnabledStateObserver() {}
+
+ // base::debug::TraceLog::EnabledStateObserver overrides:
+ virtual void OnTraceLogEnabled() OVERRIDE {}
+
+ virtual void OnTraceLogDisabled() OVERRIDE {
+ TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+ }
+};
+
+TEST_F(TraceEventTestFixture, SelfRemovingObserver) {
+ ManualTestSetUp();
+ ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+ SelfRemovingEnabledStateObserver observer;
+ TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+ EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+ TraceLog::GetInstance()->SetEnabled(CategoryFilter("*"),
+ TraceLog::RECORD_UNTIL_FULL);
+ TraceLog::GetInstance()->SetDisabled();
+ // The observer removed itself on disable.
+ EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+
bool IsNewTrace() {
bool is_new_trace;
TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);