summaryrefslogtreecommitdiffstats
path: root/net/proxy/polling_proxy_config_service.cc
diff options
context:
space:
mode:
authoreroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-23 06:02:40 +0000
committereroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-23 06:02:40 +0000
commit119655003d8f225282179043e990df879062e529 (patch)
tree4ee907ddfb8e308a00b5bb9b624e072b028623b6 /net/proxy/polling_proxy_config_service.cc
parentdacc2c255ae3f823e4a39d975e97c067a76dacf9 (diff)
downloadchromium_src-119655003d8f225282179043e990df879062e529.zip
chromium_src-119655003d8f225282179043e990df879062e529.tar.gz
chromium_src-119655003d8f225282179043e990df879062e529.tar.bz2
Change the ProxyConfigService interface to be asynchronous, and support observers.
The Windows implementation is still using a polling mechanism under the hood, however that polling has been moved to the worker pool so it won't block the IO thread in case WinHttpGetIEProxyConfigForCurrentUser is slow (crbug.com/12189). BUG=12189 Review URL: http://codereview.chromium.org/3056011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53442 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/proxy/polling_proxy_config_service.cc')
-rw-r--r--net/proxy/polling_proxy_config_service.cc166
1 files changed, 166 insertions, 0 deletions
diff --git a/net/proxy/polling_proxy_config_service.cc b/net/proxy/polling_proxy_config_service.cc
new file mode 100644
index 0000000..ac42d9c
--- /dev/null
+++ b/net/proxy/polling_proxy_config_service.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2010 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 "net/proxy/polling_proxy_config_service.h"
+
+#include "base/lock.h"
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "base/scoped_ptr.h"
+#include "base/worker_pool.h"
+#include "net/proxy/proxy_config.h"
+
+namespace net {
+
+// Reference-counted wrapper that does all the work (needs to be
+// reference-counted since we post tasks between threads; may outlive
+// the parent PollingProxyConfigService).
+class PollingProxyConfigService::Core
+ : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
+ public:
+ Core(base::TimeDelta poll_interval,
+ GetConfigFunction get_config_func)
+ : get_config_func_(get_config_func),
+ has_config_(false),
+ poll_task_outstanding_(false),
+ poll_interval_(poll_interval),
+ have_initialized_origin_loop_(false) {
+ }
+
+ // Called when the parent PollingProxyConfigService is destroyed
+ // (observers should not be called past this point).
+ void Orphan() {
+ AutoLock l(lock_);
+ origin_loop_proxy_ = NULL;
+ }
+
+ bool GetLatestProxyConfig(ProxyConfig* config) {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ OnLazyPoll();
+
+ // If we have already retrieved the proxy settings (on worker thread)
+ // then return what we last saw.
+ if (has_config_) {
+ *config = last_config_;
+ return true;
+ }
+ return false;
+ }
+
+ void AddObserver(Observer* observer) {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+ observers_.RemoveObserver(observer);
+ }
+
+ // Check for a new configuration if enough time has elapsed.
+ void OnLazyPoll() {
+ LazyInitializeOriginLoop();
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ if (poll_task_outstanding_)
+ return; // Still waiting for earlier test to finish.
+
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ if (last_poll_time_.is_null() ||
+ (now - last_poll_time_) > poll_interval_) {
+ last_poll_time_ = now;
+ poll_task_outstanding_ = true;
+ WorkerPool::PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &Core::PollOnWorkerThread, get_config_func_), true);
+ }
+ }
+
+ private:
+ void PollOnWorkerThread(GetConfigFunction func) {
+ ProxyConfig config;
+ func(&config);
+
+ AutoLock l(lock_);
+ if (origin_loop_proxy_) {
+ origin_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &Core::GetConfigCompleted, config));
+ }
+ }
+
+ // Called after the worker thread has finished retrieving a configuration.
+ void GetConfigCompleted(const ProxyConfig& config) {
+ DCHECK(poll_task_outstanding_);
+ poll_task_outstanding_ = false;
+
+ if (!origin_loop_proxy_)
+ return; // Was orphaned (parent has already been destroyed).
+
+ DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
+
+ if (!has_config_ || !last_config_.Equals(config)) {
+ // If the configuration has changed, notify the observers.
+ has_config_ = true;
+ last_config_ = config;
+ FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(config));
+ }
+ }
+
+ void LazyInitializeOriginLoop() {
+ // TODO(eroman): Really this should be done in the constructor, but right
+ // now chrome is constructing the ProxyConfigService on the
+ // UI thread so we can't cache the IO thread for the purpose
+ // of DCHECKs until the first call is made.
+ if (!have_initialized_origin_loop_) {
+ origin_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
+ have_initialized_origin_loop_ = true;
+ }
+ }
+
+ GetConfigFunction get_config_func_;
+ ObserverList<Observer> observers_;
+ bool has_config_;
+ bool poll_task_outstanding_;
+ ProxyConfig last_config_;
+ base::TimeTicks last_poll_time_;
+ base::TimeDelta poll_interval_;
+ bool have_initialized_origin_loop_;
+
+ Lock lock_;
+ scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
+};
+
+PollingProxyConfigService::PollingProxyConfigService(
+ base::TimeDelta poll_interval,
+ GetConfigFunction get_config_func)
+ : core_(new Core(poll_interval, get_config_func)) {
+}
+
+PollingProxyConfigService::~PollingProxyConfigService() {
+ core_->Orphan();
+}
+
+void PollingProxyConfigService::AddObserver(Observer* observer) {
+ core_->AddObserver(observer);
+}
+
+void PollingProxyConfigService::RemoveObserver(Observer* observer) {
+ core_->RemoveObserver(observer);
+}
+
+bool PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
+ return core_->GetLatestProxyConfig(config);
+}
+
+void PollingProxyConfigService::OnLazyPoll() {
+ core_->OnLazyPoll();
+}
+
+} // namespace net