Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: chrome/common/net/network_change_observer_proxy.cc

Issue 2802015: Massively simplify the NetworkChangeNotifier infrastructure:... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Some notes that may help anyone trying to reason about this code:
6 //
7 // - The source thread must be guaranteed to outlive the target
8 // thread. This is so that it is guaranteed that any task posted to
9 // the source thread will eventually be run. In particular, we want
10 // to make sure that Detach() causes us to eventually be removed as
11 // an observer.
12 //
13 // Note that this implies that any task posted to the target thread
14 // from the source thread may not run. But we post only
15 // TargetObserverOnIPAddressChanged() tasks on the target thread,
16 // which we can safely drop.
17 //
18 // - The source NetworkChangeNotifier must be guaranteed to outlive
19 // the target thread. This is so that it is guaranteed that any
20 // task posted to the source thread can safely access the source
21 // NetworkChangeNotifier.
22 //
23 // - Ref-counting this class is necessary, although as a consequence
24 // we can't make any guarantees about which thread will destroy an
25 // instance. Earlier versions of this class tried to get away
26 // without ref-counting. One version deleted the class in
27 // Unobserve(); this didn't work because there may still be
28 // TargetObserverOnIPAddressChanged() tasks on the target thread.
29 // An attempt to fix this was to post a DeleteTask on the target
30 // thread from Unobserve(), but this meant that there would be no
31 // way of knowing when on the target thread the instance would be
32 // deleted. Indeed, as mentioned above, any tasks posted on the
33 // target thread may not run, so this introduced the possibility of
34 // a memory leak.
35 //
36 // - It is important that all posted tasks that work with a proxy be
37 // RunnableMethods so that the ref-counting guarantees that the
38 // proxy is still valid when the task runs.
39
40 #include "chrome/common/net/network_change_observer_proxy.h"
41
42 #include <cstddef>
43
44 #include "base/logging.h"
45 #include "base/message_loop.h"
46 #include "base/task.h"
47 #include "chrome/common/net/network_change_notifier_thread.h"
48 #include "net/base/network_change_notifier.h"
49
50 namespace chrome_common_net {
51
52 NetworkChangeObserverProxy::NetworkChangeObserverProxy(
53 const NetworkChangeNotifierThread* source_thread,
54 MessageLoop* target_message_loop)
55 : source_thread_(source_thread),
56 target_message_loop_(target_message_loop),
57 target_observer_(NULL) {
58 DCHECK(source_thread_);
59 MessageLoop* source_message_loop = source_thread_->GetMessageLoop();
60 DCHECK(source_message_loop);
61 DCHECK(target_message_loop_);
62 DCHECK_NE(source_message_loop, target_message_loop_);
63 DCHECK_EQ(MessageLoop::current(), target_message_loop_);
64 }
65
66 void NetworkChangeObserverProxy::Attach(
67 net::NetworkChangeNotifier::Observer* target_observer) {
68 DCHECK_EQ(MessageLoop::current(), target_message_loop_);
69 DCHECK(!target_observer_);
70 target_observer_ = target_observer;
71 DCHECK(target_observer_);
72 source_thread_->GetMessageLoop()->PostTask(
73 FROM_HERE,
74 NewRunnableMethod(this, &NetworkChangeObserverProxy::Observe));
75 }
76
77 void NetworkChangeObserverProxy::Detach() {
78 DCHECK_EQ(MessageLoop::current(), target_message_loop_);
79 DCHECK(target_observer_);
80 target_observer_ = NULL;
81 source_thread_->GetMessageLoop()->PostTask(
82 FROM_HERE,
83 NewRunnableMethod(this, &NetworkChangeObserverProxy::Unobserve));
84 }
85
86 NetworkChangeObserverProxy::~NetworkChangeObserverProxy() {
87 MessageLoop* current_message_loop = MessageLoop::current();
88 // We can be deleted on either the source or target thread, so the
89 // best we can do is check that we're on either.
90 DCHECK((current_message_loop == source_thread_->GetMessageLoop()) ||
91 (current_message_loop == target_message_loop_));
92 // Even though only the target thread uses target_observer_, it
93 // should still be unset even if we're on the source thread; posting
94 // a task is effectively a memory barrier.
95 DCHECK(!target_observer_);
96 }
97
98 void NetworkChangeObserverProxy::Observe() {
99 DCHECK_EQ(MessageLoop::current(), source_thread_->GetMessageLoop());
100 net::NetworkChangeNotifier* source_network_change_notifier =
101 source_thread_->GetNetworkChangeNotifier();
102 DCHECK(source_network_change_notifier);
103 source_network_change_notifier->AddObserver(this);
104 }
105
106 // The Task from which this was called may hold the last reference to
107 // us (this is how we can get deleted on the source thread).
108 void NetworkChangeObserverProxy::Unobserve() {
109 DCHECK_EQ(MessageLoop::current(), source_thread_->GetMessageLoop());
110 net::NetworkChangeNotifier* source_network_change_notifier =
111 source_thread_->GetNetworkChangeNotifier();
112 DCHECK(source_network_change_notifier);
113 source_network_change_notifier->RemoveObserver(this);
114 }
115
116 // Although we may get this event after Detach() has been called on
117 // the target thread, we know that Unobserve() hasn't been called yet.
118 // But we know that it has been posted, so it at least holds a
119 // reference to us.
120 void NetworkChangeObserverProxy::OnIPAddressChanged() {
121 DCHECK_EQ(MessageLoop::current(), source_thread_->GetMessageLoop());
122 target_message_loop_->PostTask(
123 FROM_HERE,
124 NewRunnableMethod(
125 this,
126 &NetworkChangeObserverProxy::TargetObserverOnIPAddressChanged));
127 }
128
129 // The Task from which this was called may hold the last reference to
130 // us (this is how we can get deleted on the target thread).
131 void NetworkChangeObserverProxy::TargetObserverOnIPAddressChanged() {
132 DCHECK_EQ(MessageLoop::current(), target_message_loop_);
133 if (target_observer_)
134 target_observer_->OnIPAddressChanged();
135 }
136
137 } // namespace chrome_common_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698