summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp4
-rw-r--r--base/leak_tracker.h106
-rw-r--r--base/leak_tracker_unittest.cc108
-rw-r--r--base/linked_list.h135
-rw-r--r--base/linked_list_unittest.cc245
-rw-r--r--chrome/browser/browser_process_impl.cc50
-rw-r--r--chrome/browser/browser_process_impl.h4
-rw-r--r--chrome/browser/net/url_fetcher.h3
-rw-r--r--net/url_request/url_request.h3
9 files changed, 647 insertions, 11 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 9bb37cb..d0e3c4f 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -161,6 +161,8 @@
'keyboard_codes_win.h',
'lazy_instance.cc',
'lazy_instance.h',
+ 'leak_tracker.h',
+ 'linked_list.h',
'linked_ptr.h',
'linux_util.cc',
'linux_util.h',
@@ -581,6 +583,8 @@
'json_reader_unittest.cc',
'json_writer_unittest.cc',
'lazy_instance_unittest.cc',
+ 'leak_tracker_unittest.cc',
+ 'linked_list_unittest.cc',
'linked_ptr_unittest.cc',
'mac_util_unittest.cc',
'message_loop_unittest.cc',
diff --git a/base/leak_tracker.h b/base/leak_tracker.h
new file mode 100644
index 0000000..d289691e
--- /dev/null
+++ b/base/leak_tracker.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 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 BASE_LEAK_TRACKER_H_
+#define BASE_LEAK_TRACKER_H_
+
+#ifndef NDEBUG
+#include "base/debug_util.h"
+#include "base/linked_list.h"
+#include "base/logging.h"
+#endif
+
+// LeakTracker is a debug helper to verify that all instances of a class
+// have been destroyed.
+//
+// It is particularly useful for classes that are bound to a single thread --
+// before destroying that thread, one can check that there are no remaining
+// instances of that class.
+//
+// For example, to enable leak tracking for class URLRequest, start by
+// adding a member variable of type LeakTracker<URLRequest>.
+//
+// class URLRequest {
+// ...
+// private:
+// base::LeakTracker<URLRequest> leak_tracker_;
+// };
+//
+//
+// Next, when we believe all instances of URLRequest have been deleted:
+//
+// LeakTracker<URLRequest>::CheckForLeaks();
+//
+// Should the check fail (because there are live instances of URLRequest),
+// then the allocation callstack for each leaked instances is dumped to
+// the error log.
+//
+// In RELEASE mode the check has no effect.
+
+namespace base {
+
+#ifdef NDEBUG
+
+// In release mode we do nothing.
+template<typename T>
+class LeakTracker {
+ public:
+ static void CheckForLeaks() {}
+ static int NumLiveInstances() { return -1; }
+};
+
+#else
+
+// In debug mode we track where the object was allocated from.
+
+template<typename T>
+class LeakTracker : public LinkNode<LeakTracker<T> > {
+ public:
+ LeakTracker() {
+ instances()->Append(this);
+ }
+
+ ~LeakTracker() {
+ this->RemoveFromList();
+ }
+
+ static void CheckForLeaks() {
+ // Walk the allocation list and print each entry it contains.
+ int count = 0;
+ for (LinkNode<LeakTracker<T> >* node = instances()->head();
+ node != instances()->end();
+ node = node->next()) {
+ ++count;
+ LOG(ERROR) << "Leaked " << node << " which was allocated by:";
+ node->value()->allocation_stack_.PrintBacktrace();
+ }
+ DCHECK_EQ(0, count);
+ }
+
+ static int NumLiveInstances() {
+ // Walk the allocation list and count how many entries it has.
+ int count = 0;
+ for (LinkNode<LeakTracker<T> >* node = instances()->head();
+ node != instances()->end();
+ node = node->next()) {
+ ++count;
+ }
+ return count;
+ }
+
+ private:
+ // Each specialization of LeakTracker gets its own static storage.
+ static LinkedList<LeakTracker<T> >* instances() {
+ static LinkedList<LeakTracker<T> > list;
+ return &list;
+ }
+
+ StackTrace allocation_stack_;
+};
+
+#endif // NDEBUG
+
+} // namespace base
+
+#endif // BASE_LEAK_TRACKER_H_
diff --git a/base/leak_tracker_unittest.cc b/base/leak_tracker_unittest.cc
new file mode 100644
index 0000000..8f0e2f2
--- /dev/null
+++ b/base/leak_tracker_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2009 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.
+
+#include "base/leak_tracker.h"
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ClassA {
+ private:
+ base::LeakTracker<ClassA> leak_tracker_;
+};
+
+class ClassB {
+ private:
+ base::LeakTracker<ClassB> leak_tracker_;
+};
+
+#ifdef NDEBUG
+
+// In RELEASE mode, leak tracking is disabled.
+TEST(LeakTrackerTest, ReleaseMode) {
+ EXPECT_EQ(-1, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(-1, base::LeakTracker<ClassB>::NumLiveInstances());
+
+ // Use scoped_ptr so compiler doesn't complain about unused variables.
+ scoped_ptr<ClassA> a1(new ClassA);
+ scoped_ptr<ClassB> b1(new ClassB);
+ scoped_ptr<ClassB> b2(new ClassB);
+
+ EXPECT_EQ(-1, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(-1, base::LeakTracker<ClassB>::NumLiveInstances());
+}
+
+#else
+
+// In DEBUG mode, leak tracking should work.
+TEST(LeakTrackerTest, DebugMode) {
+ {
+ ClassA a1;
+
+ EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
+
+ ClassB b1;
+ ClassB b2;
+
+ EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
+
+ scoped_ptr<ClassA> a2(new ClassA);
+
+ EXPECT_EQ(2, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
+
+ a2.reset();
+
+ EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(2, base::LeakTracker<ClassB>::NumLiveInstances());
+ }
+
+ EXPECT_EQ(0, base::LeakTracker<ClassA>::NumLiveInstances());
+ EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
+}
+
+// Try some orderings of create/remove to hit different cases in the linked-list
+// assembly.
+TEST(LeakTrackerTest, DebugMode_LinkedList) {
+ EXPECT_EQ(0, base::LeakTracker<ClassB>::NumLiveInstances());
+
+ scoped_ptr<ClassA> a1(new ClassA);
+ scoped_ptr<ClassA> a2(new ClassA);
+ scoped_ptr<ClassA> a3(new ClassA);
+ scoped_ptr<ClassA> a4(new ClassA);
+
+ EXPECT_EQ(4, base::LeakTracker<ClassA>::NumLiveInstances());
+
+ // Remove the head of the list (a1).
+ a1.reset();
+ EXPECT_EQ(3, base::LeakTracker<ClassA>::NumLiveInstances());
+
+ // Remove the tail of the list (a4).
+ a4.reset();
+ EXPECT_EQ(2, base::LeakTracker<ClassA>::NumLiveInstances());
+
+ // Append to the new tail of the list (a3).
+ scoped_ptr<ClassA> a5(new ClassA);
+ EXPECT_EQ(3, base::LeakTracker<ClassA>::NumLiveInstances());
+
+ a2.reset();
+ a3.reset();
+
+ EXPECT_EQ(1, base::LeakTracker<ClassA>::NumLiveInstances());
+
+ a5.reset();
+ EXPECT_EQ(0, base::LeakTracker<ClassA>::NumLiveInstances());
+}
+
+TEST(LeakTrackerTest, DebugMode_NoOpCheckForLeaks) {
+ // There are no live instances of ClassA, so this should do nothing.
+ base::LeakTracker<ClassA>::CheckForLeaks();
+}
+
+#endif // NDEBUG
+
+} // namespace
diff --git a/base/linked_list.h b/base/linked_list.h
new file mode 100644
index 0000000..c197008
--- /dev/null
+++ b/base/linked_list.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2009 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 BASE_LINKED_LIST_H_
+#define BASE_LINKED_LIST_H_
+
+// Simple LinkedList type.
+//
+// To use, start by declaring the class which will be contained in the linked
+// list, as extending LinkNode (this gives it next/previous pointers).
+//
+// class MyNodeType : public LinkNode<MyNodeType> {
+// ...
+// };
+//
+// Next, to keep track of the list's head/tail, use a LinkedList instance:
+//
+// LinkedList<MyNodeType> list;
+//
+// To add elements to the list, use any of LinkedList::Append,
+// LinkNode::InsertBefore, or LinkNode::InsertAfter:
+//
+// LinkNode<MyNodeType>* n1 = ...;
+// LinkNode<MyNodeType>* n2 = ...;
+// LinkNode<MyNodeType>* n3 = ...;
+//
+// list.Append(n1);
+// list.Append(n3);
+// n3->InsertBefore(n3);
+//
+// Lastly, to iterate through the linked list forwards:
+//
+// for (LinkNode<MyNodeType>* node = list.head();
+// node != list.end();
+// node = node->next()) {
+// MyNodeType* value = node->value();
+// ...
+// }
+//
+// Or to iterate the linked list backwards:
+//
+// for (LinkNode<MyNodeType>* node = list.tail();
+// node != list.end();
+// node = node->previous()) {
+// MyNodeType* value = node->value();
+// ...
+// }
+//
+
+namespace base {
+
+template <typename T>
+class LinkNode {
+ public:
+ LinkNode() : previous_(0), next_(0) {}
+ LinkNode(LinkNode<T>* previous, LinkNode<T>* next)
+ : previous_(previous), next_(next) {}
+
+ // Insert |this| into the linked list, before |e|.
+ void InsertBefore(LinkNode<T>* e) {
+ this->next_ = e;
+ this->previous_ = e->previous_;
+ e->previous_->next_ = this;
+ e->previous_ = this;
+ }
+
+ // Insert |this| into the linked list, after |e|.
+ void InsertAfter(LinkNode<T>* e) {
+ this->next_ = e->next_;
+ this->previous_ = e;
+ e->next_->previous_ = this;
+ e->next_ = this;
+ }
+
+ // Remove |this| from the linked list.
+ void RemoveFromList() {
+ this->previous_->next_ = this->next_;
+ this->next_->previous_ = this->previous_;
+ }
+
+ LinkNode<T>* previous() const {
+ return previous_;
+ }
+
+ LinkNode<T>* next() const {
+ return next_;
+ }
+
+ // Cast from the node-type to the value type.
+ const T* value() const {
+ return reinterpret_cast<const T*>(this);
+ }
+
+ T* value() {
+ return reinterpret_cast<T*>(this);
+ }
+
+ private:
+ LinkNode<T>* previous_;
+ LinkNode<T>* next_;
+};
+
+template <typename T>
+class LinkedList {
+ public:
+ // The "root" node is self-referential, and forms the basis of a circular
+ // list (root_.next() will point back to the start of the list,
+ // and root_->previous() wraps around to the end of the list).
+ LinkedList() : root_(&root_, &root_) {}
+
+ // Appends |e| to the end of the linked list.
+ void Append(LinkNode<T>* e) {
+ e->InsertBefore(&root_);
+ }
+
+ LinkNode<T>* head() const {
+ return root_.next();
+ }
+
+ LinkNode<T>* tail() const {
+ return root_.previous();
+ }
+
+ const LinkNode<T>* end() const {
+ return &root_;
+ }
+
+ private:
+ LinkNode<T> root_;
+};
+
+} // namespace base
+
+#endif // BASE_LINKED_LIST_H_
diff --git a/base/linked_list_unittest.cc b/base/linked_list_unittest.cc
new file mode 100644
index 0000000..835d927
--- /dev/null
+++ b/base/linked_list_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2009 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.
+
+#include "base/linked_list.h"
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Node : public LinkNode<Node> {
+ public:
+ explicit Node(int id) : id_(id) {}
+
+ int id() const { return id_; }
+
+ private:
+ int id_;
+};
+
+// Checks that when iterating |list| (either from head to tail, or from
+// tail to head, as determined by |forward|), we get back |node_ids|,
+// which is an array of size |num_nodes|.
+void ExpectListContentsForDirection(const LinkedList<Node>& list,
+ int num_nodes, const int* node_ids, bool forward) {
+ int i = 0;
+ for (const LinkNode<Node>* node = (forward ? list.head() : list.tail());
+ node != list.end();
+ node = (forward ? node->next() : node->previous())) {
+ ASSERT_LT(i, num_nodes);
+ int index_of_id = forward ? i : num_nodes - i - 1;
+ EXPECT_EQ(node_ids[index_of_id], node->value()->id());
+ ++i;
+ }
+ EXPECT_EQ(num_nodes, i);
+}
+
+void ExpectListContents(const LinkedList<Node>& list,
+ int num_nodes,
+ const int* node_ids) {
+ {
+ SCOPED_TRACE("Iterating forward (from head to tail)");
+ ExpectListContentsForDirection(list, num_nodes, node_ids, true);
+ }
+ {
+ SCOPED_TRACE("Iterating backward (from tail to head)");
+ ExpectListContentsForDirection(list, num_nodes, node_ids, false);
+ }
+}
+
+TEST(LinkedList, Empty) {
+ LinkedList<Node> list;
+ EXPECT_EQ(list.end(), list.head());
+ EXPECT_EQ(list.end(), list.tail());
+ ExpectListContents(list, 0, NULL);
+}
+
+
+TEST(LinkedList, Append) {
+ LinkedList<Node> list;
+ ExpectListContents(list, 0, NULL);
+
+ Node n1(1);
+ list.Append(&n1);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n1, list.tail());
+ {
+ const int expected[] = {1};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ Node n2(2);
+ list.Append(&n2);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n2, list.tail());
+ {
+ const int expected[] = {1, 2};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ Node n3(3);
+ list.Append(&n3);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n3, list.tail());
+ {
+ const int expected[] = {1, 2, 3};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+}
+
+TEST(LinkedList, RemoveFromList) {
+ LinkedList<Node> list;
+
+ Node n1(1);
+ Node n2(2);
+ Node n3(3);
+ Node n4(4);
+ Node n5(5);
+
+ list.Append(&n1);
+ list.Append(&n2);
+ list.Append(&n3);
+ list.Append(&n4);
+ list.Append(&n5);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n5, list.tail());
+ {
+ const int expected[] = {1, 2, 3, 4, 5};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ // Remove from the middle.
+ n3.RemoveFromList();
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n5, list.tail());
+ {
+ const int expected[] = {1, 2, 4, 5};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ // Remove from the tail.
+ n5.RemoveFromList();
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n4, list.tail());
+ {
+ const int expected[] = {1, 2, 4};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ // Remove from the head.
+ n1.RemoveFromList();
+
+ EXPECT_EQ(&n2, list.head());
+ EXPECT_EQ(&n4, list.tail());
+ {
+ const int expected[] = {2, 4};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ // Empty the list.
+ n2.RemoveFromList();
+ n4.RemoveFromList();
+
+ ExpectListContents(list, 0, NULL);
+ EXPECT_EQ(list.end(), list.head());
+ EXPECT_EQ(list.end(), list.tail());
+
+ // Fill the list once again.
+ list.Append(&n1);
+ list.Append(&n2);
+ list.Append(&n3);
+ list.Append(&n4);
+ list.Append(&n5);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n5, list.tail());
+ {
+ const int expected[] = {1, 2, 3, 4, 5};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+}
+
+TEST(LinkedList, InsertBefore) {
+ LinkedList<Node> list;
+
+ Node n1(1);
+ Node n2(2);
+ Node n3(3);
+ Node n4(4);
+
+ list.Append(&n1);
+ list.Append(&n2);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n2, list.tail());
+ {
+ const int expected[] = {1, 2};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ n3.InsertBefore(&n2);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n2, list.tail());
+ {
+ const int expected[] = {1, 3, 2};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ n4.InsertBefore(&n1);
+
+ EXPECT_EQ(&n4, list.head());
+ EXPECT_EQ(&n2, list.tail());
+ {
+ const int expected[] = {4, 1, 3, 2};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+}
+
+TEST(LinkedList, InsertAfter) {
+ LinkedList<Node> list;
+
+ Node n1(1);
+ Node n2(2);
+ Node n3(3);
+ Node n4(4);
+
+ list.Append(&n1);
+ list.Append(&n2);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n2, list.tail());
+ {
+ const int expected[] = {1, 2};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ n3.InsertAfter(&n2);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n3, list.tail());
+ {
+ const int expected[] = {1, 2, 3};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+
+ n4.InsertAfter(&n1);
+
+ EXPECT_EQ(&n1, list.head());
+ EXPECT_EQ(&n3, list.tail());
+ {
+ const int expected[] = {1, 4, 2, 3};
+ ExpectListContents(list, arraysize(expected), expected);
+ }
+}
+
+} // namespace
+} // namespace base
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 552e171..4007cf6 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -58,7 +58,7 @@ class BrowserProcessSubThread : public ChromeThread {
: ChromeThread(identifier) {
}
- ~BrowserProcessSubThread() {
+ virtual ~BrowserProcessSubThread() {
// We cannot rely on our base class to stop the thread since we want our
// CleanUp function to run.
Stop();
@@ -92,6 +92,26 @@ class BrowserProcessSubThread : public ChromeThread {
NotificationService* notification_service_;
};
+class IOThread : public BrowserProcessSubThread {
+ public:
+ IOThread() : BrowserProcessSubThread(ChromeThread::IO) {}
+
+ virtual ~IOThread() {
+ // We cannot rely on our base class to stop the thread since we want our
+ // CleanUp function to run.
+ Stop();
+ }
+
+ protected:
+ virtual void CleanUp() {
+ // URLFetcher and URLRequest instances must NOT outlive the IO thread.
+ base::LeakTracker<URLRequest>::CheckForLeaks();
+ base::LeakTracker<URLFetcher>::CheckForLeaks();
+
+ BrowserProcessSubThread::CleanUp();
+ }
+};
+
} // namespace
BrowserProcessImpl::BrowserProcessImpl(const CommandLine& command_line)
@@ -172,13 +192,6 @@ BrowserProcessImpl::~BrowserProcessImpl() {
resource_dispatcher_host()->Shutdown();
}
- // Shutdown DNS prefetching now to ensure that network stack objects
- // living on the IO thread get destroyed before the IO thread goes away.
- if (io_thread_.get()) {
- io_thread_->message_loop()->PostTask(FROM_HERE,
- NewRunnableFunction(chrome_browser_net::EnsureDnsPrefetchShutdown));
- }
-
#if defined(OS_LINUX)
// The IO thread must outlive the BACKGROUND_X11 thread.
background_x11_thread_.reset();
@@ -187,7 +200,7 @@ BrowserProcessImpl::~BrowserProcessImpl() {
// Need to stop io_thread_ before resource_dispatcher_host_, since
// io_thread_ may still deref ResourceDispatcherHost and handle resource
// request before going away.
- io_thread_.reset();
+ ResetIOThread();
// Clean up state that lives on the file_thread_ before it goes away.
if (resource_dispatcher_host_.get()) {
@@ -307,8 +320,7 @@ void BrowserProcessImpl::CreateIOThread() {
background_x11_thread_.swap(background_x11_thread);
#endif
- scoped_ptr<base::Thread> thread(
- new BrowserProcessSubThread(ChromeThread::IO));
+ scoped_ptr<base::Thread> thread(new IOThread);
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
if (!thread->StartWithOptions(options))
@@ -316,6 +328,22 @@ void BrowserProcessImpl::CreateIOThread() {
io_thread_.swap(thread);
}
+void BrowserProcessImpl::ResetIOThread() {
+ if (io_thread_.get()) {
+ io_thread_->message_loop()->PostTask(FROM_HERE,
+ NewRunnableFunction(CleanupOnIOThread));
+ }
+ io_thread_.reset();
+}
+
+// static
+void BrowserProcessImpl::CleanupOnIOThread() {
+ // Shutdown DNS prefetching now to ensure that network stack objects
+ // living on the IO thread get destroyed before the IO thread goes away.
+ chrome_browser_net::EnsureDnsPrefetchShutdown();
+ // TODO(eroman): can this be merged into IOThread::CleanUp() ?
+}
+
void BrowserProcessImpl::CreateFileThread() {
DCHECK(!created_file_thread_ && file_thread_.get() == NULL);
created_file_thread_ = true;
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 421ba03..ac0edde 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -193,7 +193,11 @@ class BrowserProcessImpl : public BrowserProcess, public NonThreadSafe {
void CreateResourceDispatcherHost();
void CreatePrefService();
void CreateMetricsService();
+
void CreateIOThread();
+ void ResetIOThread();
+ static void CleanupOnIOThread();
+
void CreateFileThread();
void CreateDBThread();
void CreateTemplateURLModel();
diff --git a/chrome/browser/net/url_fetcher.h b/chrome/browser/net/url_fetcher.h
index 0ed4715..6b1c87c 100644
--- a/chrome/browser/net/url_fetcher.h
+++ b/chrome/browser/net/url_fetcher.h
@@ -10,6 +10,7 @@
#ifndef CHROME_BROWSER_URL_FETCHER_H_
#define CHROME_BROWSER_URL_FETCHER_H_
+#include "base/leak_tracker.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "chrome/browser/net/url_fetcher_protect.h"
@@ -163,6 +164,8 @@ class URLFetcher {
static Factory* factory_;
+ base::LeakTracker<URLFetcher> leak_tracker_;
+
DISALLOW_EVIL_CONSTRUCTORS(URLFetcher);
};
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index e9539cb..5a97fc6 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/leak_tracker.h"
#include "base/linked_ptr.h"
#include "base/logging.h"
#include "base/ref_counted.h"
@@ -592,6 +593,8 @@ class URLRequest {
// this to determine which URLRequest to allocate sockets to first.
int priority_;
+ base::LeakTracker<URLRequest> leak_tracker_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequest);
};