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
3 // found in the LICENSE file.
5 #include "net/proxy/polling_proxy_config_service.h"
8 #include "base/location.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/observer_list.h"
12 #include "base/synchronization/lock.h"
13 #include "base/threading/worker_pool.h"
14 #include "net/proxy/proxy_config.h"
18 // Reference-counted wrapper that does all the work (needs to be
19 // reference-counted since we post tasks between threads; may outlive
20 // the parent PollingProxyConfigService).
21 class PollingProxyConfigService::Core
22 : public base::RefCountedThreadSafe
<PollingProxyConfigService::Core
> {
24 Core(base::TimeDelta poll_interval
,
25 GetConfigFunction get_config_func
)
26 : get_config_func_(get_config_func
),
27 poll_interval_(poll_interval
),
28 have_initialized_origin_loop_(false),
30 poll_task_outstanding_(false),
31 poll_task_queued_(false) {
34 // Called when the parent PollingProxyConfigService is destroyed
35 // (observers should not be called past this point).
37 base::AutoLock
l(lock_
);
38 origin_loop_proxy_
= NULL
;
41 bool GetLatestProxyConfig(ProxyConfig
* config
) {
42 LazyInitializeOriginLoop();
43 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
47 // If we have already retrieved the proxy settings (on worker thread)
48 // then return what we last saw.
50 *config
= last_config_
;
56 void AddObserver(Observer
* observer
) {
57 LazyInitializeOriginLoop();
58 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
59 observers_
.AddObserver(observer
);
62 void RemoveObserver(Observer
* observer
) {
63 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
64 observers_
.RemoveObserver(observer
);
67 // Check for a new configuration if enough time has elapsed.
69 LazyInitializeOriginLoop();
70 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
72 if (last_poll_time_
.is_null() ||
73 (base::TimeTicks::Now() - last_poll_time_
) > poll_interval_
) {
78 void CheckForChangesNow() {
79 LazyInitializeOriginLoop();
80 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
82 if (poll_task_outstanding_
) {
83 // 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
86 poll_task_queued_
= true;
90 last_poll_time_
= base::TimeTicks::Now();
91 poll_task_outstanding_
= true;
92 poll_task_queued_
= false;
93 base::WorkerPool::PostTask(
95 base::Bind(&Core::PollOnWorkerThread
, this, get_config_func_
),
100 friend class base::RefCountedThreadSafe
<Core
>;
103 void PollOnWorkerThread(GetConfigFunction func
) {
107 base::AutoLock
l(lock_
);
108 if (origin_loop_proxy_
.get()) {
109 origin_loop_proxy_
->PostTask(
110 FROM_HERE
, base::Bind(&Core::GetConfigCompleted
, this, config
));
114 // Called after the worker thread has finished retrieving a configuration.
115 void GetConfigCompleted(const ProxyConfig
& config
) {
116 DCHECK(poll_task_outstanding_
);
117 poll_task_outstanding_
= false;
119 if (!origin_loop_proxy_
.get())
120 return; // Was orphaned (parent has already been destroyed).
122 DCHECK(origin_loop_proxy_
->BelongsToCurrentThread());
124 if (!has_config_
|| !last_config_
.Equals(config
)) {
125 // If the configuration has changed, notify the observers.
127 last_config_
= config
;
128 FOR_EACH_OBSERVER(Observer
, observers_
,
129 OnProxyConfigChanged(config
,
130 ProxyConfigService::CONFIG_VALID
));
133 if (poll_task_queued_
)
134 CheckForChangesNow();
137 void LazyInitializeOriginLoop() {
138 // TODO(eroman): Really this should be done in the constructor, but right
139 // now chrome is constructing the ProxyConfigService on the
140 // UI thread so we can't cache the IO thread for the purpose
141 // of DCHECKs until the first call is made.
142 if (!have_initialized_origin_loop_
) {
143 origin_loop_proxy_
= base::MessageLoopProxy::current();
144 have_initialized_origin_loop_
= true;
148 GetConfigFunction get_config_func_
;
149 ObserverList
<Observer
> observers_
;
150 ProxyConfig last_config_
;
151 base::TimeTicks last_poll_time_
;
152 base::TimeDelta poll_interval_
;
155 scoped_refptr
<base::MessageLoopProxy
> origin_loop_proxy_
;
157 bool have_initialized_origin_loop_
;
159 bool poll_task_outstanding_
;
160 bool poll_task_queued_
;
163 void PollingProxyConfigService::AddObserver(Observer
* observer
) {
164 core_
->AddObserver(observer
);
167 void PollingProxyConfigService::RemoveObserver(Observer
* observer
) {
168 core_
->RemoveObserver(observer
);
171 ProxyConfigService::ConfigAvailability
172 PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig
* config
) {
173 return core_
->GetLatestProxyConfig(config
) ? CONFIG_VALID
: CONFIG_PENDING
;
176 void PollingProxyConfigService::OnLazyPoll() {
180 PollingProxyConfigService::PollingProxyConfigService(
181 base::TimeDelta poll_interval
,
182 GetConfigFunction get_config_func
)
183 : core_(new Core(poll_interval
, get_config_func
)) {
186 PollingProxyConfigService::~PollingProxyConfigService() {
190 void PollingProxyConfigService::CheckForChangesNow() {
191 core_
->CheckForChangesNow();