summaryrefslogtreecommitdiffstats
path: root/net/proxy/sync_host_resolver_bridge.cc
diff options
context:
space:
mode:
authoreroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-17 00:07:04 +0000
committereroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-17 00:07:04 +0000
commit1ca2b45a6e0b6490d0ab1ff940e2d7769660682b (patch)
treef6740d35ae7bf87007f6794a49f53f2858ead7b7 /net/proxy/sync_host_resolver_bridge.cc
parent54ce726e1af62939cb12b09dc687737b114d426c (diff)
downloadchromium_src-1ca2b45a6e0b6490d0ab1ff940e2d7769660682b.zip
chromium_src-1ca2b45a6e0b6490d0ab1ff940e2d7769660682b.tar.gz
chromium_src-1ca2b45a6e0b6490d0ab1ff940e2d7769660682b.tar.bz2
Fix a deadlock that could happen during shutdown if a host resolve request was outstanding by a PAC script.
The solution is to abort the oustanding host resolver request during shutdown, and wake-up the blocked PAC thread. BUG=41244 TEST=SingleThreadedProxyResolverWithBridgedHostResolverTest.ShutdownDeadlock Review URL: http://codereview.chromium.org/1527037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44864 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/proxy/sync_host_resolver_bridge.cc')
-rw-r--r--net/proxy/sync_host_resolver_bridge.cc123
1 files changed, 123 insertions, 0 deletions
diff --git a/net/proxy/sync_host_resolver_bridge.cc b/net/proxy/sync_host_resolver_bridge.cc
new file mode 100644
index 0000000..31a326d
--- /dev/null
+++ b/net/proxy/sync_host_resolver_bridge.cc
@@ -0,0 +1,123 @@
+// 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/sync_host_resolver_bridge.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+
+namespace net {
+
+// SyncHostResolverBridge -----------------------------------------------------
+
+SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver,
+ MessageLoop* host_resolver_loop)
+ : host_resolver_(host_resolver),
+ host_resolver_loop_(host_resolver_loop),
+ event_(true, false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ callback_(this, &SyncHostResolverBridge::OnResolveCompletion)),
+ outstanding_request_(NULL),
+ has_shutdown_(false) {
+ DCHECK(host_resolver_loop_);
+}
+
+SyncHostResolverBridge::~SyncHostResolverBridge() {
+ DCHECK(HasShutdown());
+}
+
+int SyncHostResolverBridge::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ CompletionCallback* callback,
+ RequestHandle* out_req,
+ const BoundNetLog& net_log) {
+ DCHECK(!callback);
+ DCHECK(!out_req);
+
+ // Otherwise start an async resolve on the resolver's thread.
+ host_resolver_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &SyncHostResolverBridge::StartResolve,
+ info, addresses));
+
+ // Wait for the resolve to complete in the resolver's thread.
+ event_.Wait();
+
+ {
+ AutoLock l(lock_);
+ if (has_shutdown_)
+ return ERR_ABORTED;
+ event_.Reset();
+ }
+
+ return err_;
+}
+
+void SyncHostResolverBridge::CancelRequest(RequestHandle req) {
+ NOTREACHED();
+}
+
+void SyncHostResolverBridge::AddObserver(Observer* observer) {
+ NOTREACHED();
+}
+
+void SyncHostResolverBridge::RemoveObserver(Observer* observer) {
+ NOTREACHED();
+}
+
+void SyncHostResolverBridge::Shutdown() {
+ DCHECK_EQ(MessageLoop::current(), host_resolver_loop_);
+
+ if (outstanding_request_) {
+ host_resolver_->CancelRequest(outstanding_request_);
+ outstanding_request_ = NULL;
+ }
+
+ AutoLock l(lock_);
+ has_shutdown_ = true;
+
+ // Wake up the PAC thread in case it was waiting for resolve completion.
+ event_.Signal();
+}
+
+void SyncHostResolverBridge::StartResolve(const HostResolver::RequestInfo& info,
+ net::AddressList* addresses) {
+ DCHECK_EQ(host_resolver_loop_, MessageLoop::current());
+ DCHECK(!outstanding_request_);
+
+ if (HasShutdown())
+ return;
+
+ int error = host_resolver_->Resolve(
+ info, addresses, &callback_, &outstanding_request_, BoundNetLog());
+ if (error != ERR_IO_PENDING)
+ OnResolveCompletion(error); // Completed synchronously.
+}
+
+void SyncHostResolverBridge::OnResolveCompletion(int result) {
+ DCHECK_EQ(host_resolver_loop_, MessageLoop::current());
+ err_ = result;
+ outstanding_request_ = NULL;
+ event_.Signal();
+}
+
+// SingleThreadedProxyResolverUsingBridgedHostResolver -----------------------
+
+SingleThreadedProxyResolverUsingBridgedHostResolver::
+SingleThreadedProxyResolverUsingBridgedHostResolver(
+ ProxyResolver* proxy_resolver,
+ SyncHostResolverBridge* bridged_host_resolver)
+ : SingleThreadedProxyResolver(proxy_resolver),
+ bridged_host_resolver_(bridged_host_resolver) {
+}
+
+SingleThreadedProxyResolverUsingBridgedHostResolver::
+~SingleThreadedProxyResolverUsingBridgedHostResolver() {
+ bridged_host_resolver_->Shutdown();
+}
+
+} // namespace net