OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/proxy/polling_proxy_config_service.h" | 5 #include "net/proxy/polling_proxy_config_service.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/message_loop/message_loop_proxy.h" | |
11 #include "base/observer_list.h" | 10 #include "base/observer_list.h" |
| 11 #include "base/single_thread_task_runner.h" |
12 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
| 13 #include "base/thread_task_runner_handle.h" |
13 #include "base/threading/worker_pool.h" | 14 #include "base/threading/worker_pool.h" |
14 #include "net/proxy/proxy_config.h" | 15 #include "net/proxy/proxy_config.h" |
15 | 16 |
16 namespace net { | 17 namespace net { |
17 | 18 |
18 // Reference-counted wrapper that does all the work (needs to be | 19 // Reference-counted wrapper that does all the work (needs to be |
19 // reference-counted since we post tasks between threads; may outlive | 20 // reference-counted since we post tasks between threads; may outlive |
20 // the parent PollingProxyConfigService). | 21 // the parent PollingProxyConfigService). |
21 class PollingProxyConfigService::Core | 22 class PollingProxyConfigService::Core |
22 : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> { | 23 : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> { |
23 public: | 24 public: |
24 Core(base::TimeDelta poll_interval, | 25 Core(base::TimeDelta poll_interval, GetConfigFunction get_config_func) |
25 GetConfigFunction get_config_func) | |
26 : get_config_func_(get_config_func), | 26 : get_config_func_(get_config_func), |
27 poll_interval_(poll_interval), | 27 poll_interval_(poll_interval), |
28 have_initialized_origin_loop_(false), | 28 have_initialized_origin_runner_(false), |
29 has_config_(false), | 29 has_config_(false), |
30 poll_task_outstanding_(false), | 30 poll_task_outstanding_(false), |
31 poll_task_queued_(false) { | 31 poll_task_queued_(false) {} |
32 } | |
33 | 32 |
34 // Called when the parent PollingProxyConfigService is destroyed | 33 // Called when the parent PollingProxyConfigService is destroyed |
35 // (observers should not be called past this point). | 34 // (observers should not be called past this point). |
36 void Orphan() { | 35 void Orphan() { |
37 base::AutoLock l(lock_); | 36 base::AutoLock l(lock_); |
38 origin_loop_proxy_ = NULL; | 37 origin_task_runner_ = NULL; |
39 } | 38 } |
40 | 39 |
41 bool GetLatestProxyConfig(ProxyConfig* config) { | 40 bool GetLatestProxyConfig(ProxyConfig* config) { |
42 LazyInitializeOriginLoop(); | 41 LazyInitializeOriginLoop(); |
43 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 42 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
44 | 43 |
45 OnLazyPoll(); | 44 OnLazyPoll(); |
46 | 45 |
47 // If we have already retrieved the proxy settings (on worker thread) | 46 // If we have already retrieved the proxy settings (on worker thread) |
48 // then return what we last saw. | 47 // then return what we last saw. |
49 if (has_config_) { | 48 if (has_config_) { |
50 *config = last_config_; | 49 *config = last_config_; |
51 return true; | 50 return true; |
52 } | 51 } |
53 return false; | 52 return false; |
54 } | 53 } |
55 | 54 |
56 void AddObserver(Observer* observer) { | 55 void AddObserver(Observer* observer) { |
57 LazyInitializeOriginLoop(); | 56 LazyInitializeOriginLoop(); |
58 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 57 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
59 observers_.AddObserver(observer); | 58 observers_.AddObserver(observer); |
60 } | 59 } |
61 | 60 |
62 void RemoveObserver(Observer* observer) { | 61 void RemoveObserver(Observer* observer) { |
63 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 62 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
64 observers_.RemoveObserver(observer); | 63 observers_.RemoveObserver(observer); |
65 } | 64 } |
66 | 65 |
67 // Check for a new configuration if enough time has elapsed. | 66 // Check for a new configuration if enough time has elapsed. |
68 void OnLazyPoll() { | 67 void OnLazyPoll() { |
69 LazyInitializeOriginLoop(); | 68 LazyInitializeOriginLoop(); |
70 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 69 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
71 | 70 |
72 if (last_poll_time_.is_null() || | 71 if (last_poll_time_.is_null() || |
73 (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) { | 72 (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) { |
74 CheckForChangesNow(); | 73 CheckForChangesNow(); |
75 } | 74 } |
76 } | 75 } |
77 | 76 |
78 void CheckForChangesNow() { | 77 void CheckForChangesNow() { |
79 LazyInitializeOriginLoop(); | 78 LazyInitializeOriginLoop(); |
80 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 79 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
81 | 80 |
82 if (poll_task_outstanding_) { | 81 if (poll_task_outstanding_) { |
83 // Only allow one task to be outstanding at a time. If we get a poll | 82 // Only allow one task to be outstanding at a time. If we get a poll |
84 // request while we are busy, we will defer it until the current poll | 83 // request while we are busy, we will defer it until the current poll |
85 // completes. | 84 // completes. |
86 poll_task_queued_ = true; | 85 poll_task_queued_ = true; |
87 return; | 86 return; |
88 } | 87 } |
89 | 88 |
90 last_poll_time_ = base::TimeTicks::Now(); | 89 last_poll_time_ = base::TimeTicks::Now(); |
91 poll_task_outstanding_ = true; | 90 poll_task_outstanding_ = true; |
92 poll_task_queued_ = false; | 91 poll_task_queued_ = false; |
93 base::WorkerPool::PostTask( | 92 base::WorkerPool::PostTask( |
94 FROM_HERE, | 93 FROM_HERE, |
95 base::Bind(&Core::PollOnWorkerThread, this, get_config_func_), | 94 base::Bind(&Core::PollOnWorkerThread, this, get_config_func_), |
96 true); | 95 true); |
97 } | 96 } |
98 | 97 |
99 private: | 98 private: |
100 friend class base::RefCountedThreadSafe<Core>; | 99 friend class base::RefCountedThreadSafe<Core>; |
101 ~Core() {} | 100 ~Core() {} |
102 | 101 |
103 void PollOnWorkerThread(GetConfigFunction func) { | 102 void PollOnWorkerThread(GetConfigFunction func) { |
104 ProxyConfig config; | 103 ProxyConfig config; |
105 func(&config); | 104 func(&config); |
106 | 105 |
107 base::AutoLock l(lock_); | 106 base::AutoLock l(lock_); |
108 if (origin_loop_proxy_.get()) { | 107 if (origin_task_runner_.get()) { |
109 origin_loop_proxy_->PostTask( | 108 origin_task_runner_->PostTask( |
110 FROM_HERE, base::Bind(&Core::GetConfigCompleted, this, config)); | 109 FROM_HERE, base::Bind(&Core::GetConfigCompleted, this, config)); |
111 } | 110 } |
112 } | 111 } |
113 | 112 |
114 // Called after the worker thread has finished retrieving a configuration. | 113 // Called after the worker thread has finished retrieving a configuration. |
115 void GetConfigCompleted(const ProxyConfig& config) { | 114 void GetConfigCompleted(const ProxyConfig& config) { |
116 DCHECK(poll_task_outstanding_); | 115 DCHECK(poll_task_outstanding_); |
117 poll_task_outstanding_ = false; | 116 poll_task_outstanding_ = false; |
118 | 117 |
119 if (!origin_loop_proxy_.get()) | 118 if (!origin_task_runner_.get()) |
120 return; // Was orphaned (parent has already been destroyed). | 119 return; // Was orphaned (parent has already been destroyed). |
121 | 120 |
122 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 121 DCHECK(origin_task_runner_->BelongsToCurrentThread()); |
123 | 122 |
124 if (!has_config_ || !last_config_.Equals(config)) { | 123 if (!has_config_ || !last_config_.Equals(config)) { |
125 // If the configuration has changed, notify the observers. | 124 // If the configuration has changed, notify the observers. |
126 has_config_ = true; | 125 has_config_ = true; |
127 last_config_ = config; | 126 last_config_ = config; |
128 FOR_EACH_OBSERVER(Observer, observers_, | 127 FOR_EACH_OBSERVER(Observer, observers_, |
129 OnProxyConfigChanged(config, | 128 OnProxyConfigChanged(config, |
130 ProxyConfigService::CONFIG_VALID)); | 129 ProxyConfigService::CONFIG_VALID)); |
131 } | 130 } |
132 | 131 |
133 if (poll_task_queued_) | 132 if (poll_task_queued_) |
134 CheckForChangesNow(); | 133 CheckForChangesNow(); |
135 } | 134 } |
136 | 135 |
137 void LazyInitializeOriginLoop() { | 136 void LazyInitializeOriginLoop() { |
138 // TODO(eroman): Really this should be done in the constructor, but right | 137 // TODO(eroman): Really this should be done in the constructor, but right |
139 // now chrome is constructing the ProxyConfigService on the | 138 // now chrome is constructing the ProxyConfigService on the |
140 // UI thread so we can't cache the IO thread for the purpose | 139 // UI thread so we can't cache the IO thread for the purpose |
141 // of DCHECKs until the first call is made. | 140 // of DCHECKs until the first call is made. |
142 if (!have_initialized_origin_loop_) { | 141 if (!have_initialized_origin_runner_) { |
143 origin_loop_proxy_ = base::MessageLoopProxy::current(); | 142 origin_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
144 have_initialized_origin_loop_ = true; | 143 have_initialized_origin_runner_ = true; |
145 } | 144 } |
146 } | 145 } |
147 | 146 |
148 GetConfigFunction get_config_func_; | 147 GetConfigFunction get_config_func_; |
149 ObserverList<Observer> observers_; | 148 ObserverList<Observer> observers_; |
150 ProxyConfig last_config_; | 149 ProxyConfig last_config_; |
151 base::TimeTicks last_poll_time_; | 150 base::TimeTicks last_poll_time_; |
152 base::TimeDelta poll_interval_; | 151 base::TimeDelta poll_interval_; |
153 | 152 |
154 base::Lock lock_; | 153 base::Lock lock_; |
155 scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_; | 154 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
156 | 155 |
157 bool have_initialized_origin_loop_; | 156 bool have_initialized_origin_runner_; |
158 bool has_config_; | 157 bool has_config_; |
159 bool poll_task_outstanding_; | 158 bool poll_task_outstanding_; |
160 bool poll_task_queued_; | 159 bool poll_task_queued_; |
161 }; | 160 }; |
162 | 161 |
163 void PollingProxyConfigService::AddObserver(Observer* observer) { | 162 void PollingProxyConfigService::AddObserver(Observer* observer) { |
164 core_->AddObserver(observer); | 163 core_->AddObserver(observer); |
165 } | 164 } |
166 | 165 |
167 void PollingProxyConfigService::RemoveObserver(Observer* observer) { | 166 void PollingProxyConfigService::RemoveObserver(Observer* observer) { |
(...skipping 17 matching lines...) Expand all Loading... |
185 | 184 |
186 PollingProxyConfigService::~PollingProxyConfigService() { | 185 PollingProxyConfigService::~PollingProxyConfigService() { |
187 core_->Orphan(); | 186 core_->Orphan(); |
188 } | 187 } |
189 | 188 |
190 void PollingProxyConfigService::CheckForChangesNow() { | 189 void PollingProxyConfigService::CheckForChangesNow() { |
191 core_->CheckForChangesNow(); | 190 core_->CheckForChangesNow(); |
192 } | 191 } |
193 | 192 |
194 } // namespace net | 193 } // namespace net |
OLD | NEW |