diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-17 00:07:04 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-17 00:07:04 +0000 |
commit | 1ca2b45a6e0b6490d0ab1ff940e2d7769660682b (patch) | |
tree | f6740d35ae7bf87007f6794a49f53f2858ead7b7 /net/proxy/sync_host_resolver_bridge.cc | |
parent | 54ce726e1af62939cb12b09dc687737b114d426c (diff) | |
download | chromium_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.cc | 123 |
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 |