diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-03 21:00:14 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-03 21:00:14 +0000 |
commit | 1ac6af94287a2f821a43003b2be2ba21f319a66d (patch) | |
tree | 3398fd0b22e8f9bde49f5aa7f50ff3ab1a42a81c /net | |
parent | cc204b2cfb421e72bb9d6187fa88cb412576fc94 (diff) | |
download | chromium_src-1ac6af94287a2f821a43003b2be2ba21f319a66d.zip chromium_src-1ac6af94287a2f821a43003b2be2ba21f319a66d.tar.gz chromium_src-1ac6af94287a2f821a43003b2be2ba21f319a66d.tar.bz2 |
Make HostResolver NonThreadSafe and not thread safe refcounted.
Required making SyncHostResolverBridge not use RefCountedThreadSafe. I refactored the innards to have a thread safe refcounted Core implementation.
BUG=45298
Review URL: http://codereview.chromium.org/2122015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48867 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/host_resolver.h | 4 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 9 | ||||
-rw-r--r-- | net/base/host_resolver_impl.h | 2 | ||||
-rw-r--r-- | net/proxy/sync_host_resolver_bridge.cc | 189 | ||||
-rw-r--r-- | net/proxy/sync_host_resolver_bridge.h | 38 | ||||
-rw-r--r-- | net/proxy/sync_host_resolver_bridge_unittest.cc | 62 |
6 files changed, 183 insertions, 121 deletions
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index e4bf847..d798688 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -32,7 +32,7 @@ class NetworkChangeNotifier; // request at a time is to create a SingleRequestHostResolver wrapper around // HostResolver (which will automatically cancel the single request when it // goes out of scope). -class HostResolver : public base::RefCountedThreadSafe<HostResolver> { +class HostResolver : public base::RefCounted<HostResolver> { public: // The parameters for doing a Resolve(). |hostname| and |port| are required, // the rest are optional (and have reasonable defaults). @@ -179,7 +179,7 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> { virtual HostResolverImpl* GetAsHostResolverImpl() { return NULL; } protected: - friend class base::RefCountedThreadSafe<HostResolver>; + friend class base::RefCounted<HostResolver>; HostResolver() { } diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index 1f89af4..f3bc5c1 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -755,6 +755,8 @@ int HostResolverImpl::Resolve(const RequestInfo& info, CompletionCallback* callback, RequestHandle* out_req, const BoundNetLog& net_log) { + DCHECK(CalledOnValidThread()); + if (shutdown_) return ERR_UNEXPECTED; @@ -840,6 +842,7 @@ int HostResolverImpl::Resolve(const RequestInfo& info, // See OnJobComplete(Job*) for why it is important not to clean out // cancelled requests from Job::requests_. void HostResolverImpl::CancelRequest(RequestHandle req_handle) { + DCHECK(CalledOnValidThread()); if (shutdown_) { // TODO(eroman): temp hack for: http://crbug.com/18373 // Because we destroy outstanding requests during Shutdown(), @@ -869,10 +872,12 @@ void HostResolverImpl::CancelRequest(RequestHandle req_handle) { } void HostResolverImpl::AddObserver(HostResolver::Observer* observer) { + DCHECK(CalledOnValidThread()); observers_.push_back(observer); } void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) { + DCHECK(CalledOnValidThread()); ObserversList::iterator it = std::find(observers_.begin(), observers_.end(), observer); @@ -883,18 +888,21 @@ void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) { } void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) { + DCHECK(CalledOnValidThread()); ipv6_probe_monitoring_ = false; DiscardIPv6ProbeJob(); default_address_family_ = address_family; } void HostResolverImpl::ProbeIPv6Support() { + DCHECK(CalledOnValidThread()); DCHECK(!ipv6_probe_monitoring_); ipv6_probe_monitoring_ = true; OnIPAddressChanged(); // Give initial setup call. } void HostResolverImpl::Shutdown() { + DCHECK(CalledOnValidThread()); shutdown_ = true; // Cancel the outstanding jobs. @@ -907,6 +915,7 @@ void HostResolverImpl::Shutdown() { void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index, size_t max_outstanding_jobs, size_t max_pending_requests) { + DCHECK(CalledOnValidThread()); CHECK_GE(pool_index, 0); CHECK_LT(pool_index, POOL_COUNT); CHECK(jobs_.empty()) << "Can only set constraints during setup"; diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h index 417cc77..a0e34ca 100644 --- a/net/base/host_resolver_impl.h +++ b/net/base/host_resolver_impl.h @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/non_thread_safe.h" #include "base/scoped_ptr.h" #include "net/base/capturing_net_log.h" #include "net/base/host_cache.h" @@ -49,6 +50,7 @@ namespace net { // Requests are ordered in the queue based on their priority. class HostResolverImpl : public HostResolver, + public NonThreadSafe, public NetworkChangeNotifier::Observer { public: // The index into |job_pools_| for the various job pools. Pools with a higher diff --git a/net/proxy/sync_host_resolver_bridge.cc b/net/proxy/sync_host_resolver_bridge.cc index 31a326d..caf4549 100644 --- a/net/proxy/sync_host_resolver_bridge.cc +++ b/net/proxy/sync_host_resolver_bridge.cc @@ -6,50 +6,123 @@ #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/lock.h" #include "base/message_loop.h" +#include "base/waitable_event.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" namespace net { -// SyncHostResolverBridge ----------------------------------------------------- +// SyncHostResolverBridge::Core ---------------------------------------------- -SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver, - MessageLoop* host_resolver_loop) +class SyncHostResolverBridge::Core + : public base::RefCountedThreadSafe<SyncHostResolverBridge::Core> { + public: + Core(HostResolver* resolver, MessageLoop* host_resolver_loop); + + int ResolveSynchronously(const HostResolver::RequestInfo& info, + AddressList* addresses); + + // Returns true if Shutdown() has been called. + bool HasShutdown() const { + AutoLock l(lock_); + return HasShutdownLocked(); + } + + // Called on |host_resolver_loop_|. + void Shutdown(); + + private: + friend class base::RefCountedThreadSafe<SyncHostResolverBridge::Core>; + + bool HasShutdownLocked() const { + return has_shutdown_; + } + + // Called on |host_resolver_loop_|. + void StartResolve(const HostResolver::RequestInfo& info, + AddressList* addresses); + + // Called on |host_resolver_loop_|. + void OnResolveCompletion(int result); + + // Not called on |host_resolver_loop_|. + int WaitForResolveCompletion(); + + const scoped_refptr<HostResolver> host_resolver_; + MessageLoop* const host_resolver_loop_; + net::CompletionCallbackImpl<Core> callback_; + // The result from the current request (set on |host_resolver_loop_|). + int err_; + // The currently outstanding request to |host_resolver_|, or NULL. + HostResolver::RequestHandle outstanding_request_; + + // Event to notify completion of resolve request. We always Signal() on + // |host_resolver_loop_| and Wait() on a different thread. + base::WaitableEvent event_; + + // True if Shutdown() has been called. Must hold |lock_| to access it. + bool has_shutdown_; + + // Mutex to guard accesses to |has_shutdown_|. + mutable Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(Core); +}; + +SyncHostResolverBridge::Core::Core(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)), + callback_(this, &Core::OnResolveCompletion)), + err_(0), 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); + event_(true, false), + has_shutdown_(false) {} +int SyncHostResolverBridge::Core::ResolveSynchronously( + const HostResolver::RequestInfo& info, + net::AddressList* addresses) { // Otherwise start an async resolve on the resolver's thread. host_resolver_loop_->PostTask( FROM_HERE, - NewRunnableMethod(this, &SyncHostResolverBridge::StartResolve, + NewRunnableMethod(this, &Core::StartResolve, info, addresses)); - // Wait for the resolve to complete in the resolver's thread. + return WaitForResolveCompletion(); +} + +void SyncHostResolverBridge::Core::StartResolve( + const HostResolver::RequestInfo& info, + net::AddressList* addresses) { + DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); + 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::Core::OnResolveCompletion(int result) { + DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); + err_ = result; + outstanding_request_ = NULL; + event_.Signal(); +} + +int SyncHostResolverBridge::Core::WaitForResolveCompletion() { + DCHECK_NE(MessageLoop::current(), host_resolver_loop_); event_.Wait(); { AutoLock l(lock_); - if (has_shutdown_) + if (HasShutdownLocked()) return ERR_ABORTED; event_.Reset(); } @@ -57,19 +130,7 @@ int SyncHostResolverBridge::Resolve(const RequestInfo& info, return err_; } -void SyncHostResolverBridge::CancelRequest(RequestHandle req) { - NOTREACHED(); -} - -void SyncHostResolverBridge::AddObserver(Observer* observer) { - NOTREACHED(); -} - -void SyncHostResolverBridge::RemoveObserver(Observer* observer) { - NOTREACHED(); -} - -void SyncHostResolverBridge::Shutdown() { +void SyncHostResolverBridge::Core::Shutdown() { DCHECK_EQ(MessageLoop::current(), host_resolver_loop_); if (outstanding_request_) { @@ -77,32 +138,54 @@ void SyncHostResolverBridge::Shutdown() { outstanding_request_ = NULL; } - AutoLock l(lock_); - has_shutdown_ = true; + { + 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_); +// SyncHostResolverBridge ----------------------------------------------------- - if (HasShutdown()) - return; +SyncHostResolverBridge::SyncHostResolverBridge(HostResolver* host_resolver, + MessageLoop* host_resolver_loop) + : host_resolver_loop_(host_resolver_loop), + core_(new Core(host_resolver, host_resolver_loop)) { + DCHECK(host_resolver_loop_); +} - int error = host_resolver_->Resolve( - info, addresses, &callback_, &outstanding_request_, BoundNetLog()); - if (error != ERR_IO_PENDING) - OnResolveCompletion(error); // Completed synchronously. +SyncHostResolverBridge::~SyncHostResolverBridge() { + DCHECK(core_->HasShutdown()); } -void SyncHostResolverBridge::OnResolveCompletion(int result) { - DCHECK_EQ(host_resolver_loop_, MessageLoop::current()); - err_ = result; - outstanding_request_ = NULL; - event_.Signal(); +int SyncHostResolverBridge::Resolve(const RequestInfo& info, + AddressList* addresses, + CompletionCallback* callback, + RequestHandle* out_req, + const BoundNetLog& net_log) { + DCHECK(!callback); + DCHECK(!out_req); + + return core_->ResolveSynchronously(info, addresses); +} + +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_); + core_->Shutdown(); } // SingleThreadedProxyResolverUsingBridgedHostResolver ----------------------- diff --git a/net/proxy/sync_host_resolver_bridge.h b/net/proxy/sync_host_resolver_bridge.h index d082043..4d25b4d 100644 --- a/net/proxy/sync_host_resolver_bridge.h +++ b/net/proxy/sync_host_resolver_bridge.h @@ -5,9 +5,7 @@ #ifndef NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_ #define NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_ -#include "base/lock.h" #include "base/scoped_ptr.h" -#include "base/waitable_event.h" #include "net/base/host_resolver.h" #include "net/proxy/single_threaded_proxy_resolver.h" @@ -40,39 +38,10 @@ class SyncHostResolverBridge : public HostResolver { void Shutdown(); private: - // Called on |host_resolver_loop_|. - void StartResolve(const HostResolver::RequestInfo& info, - net::AddressList* addresses); + class Core; - // Called on |host_resolver_loop_|. - void OnResolveCompletion(int result); - - // Returns true if Shutdown() has been called. - bool HasShutdown() const { - AutoLock l(lock_); - return has_shutdown_; - } - - scoped_refptr<HostResolver> host_resolver_; - MessageLoop* host_resolver_loop_; - - // Event to notify completion of resolve request. - base::WaitableEvent event_; - - // Callback for when the resolve completes on host_resolver_loop_. - net::CompletionCallbackImpl<SyncHostResolverBridge> callback_; - - // The result from the current request (set on |host_resolver_loop_|). - int err_; - - // The currently outstanding request to |host_resolver_|, or NULL. - HostResolver::RequestHandle outstanding_request_; - - // True if Shutdown() has been called. Must hold |lock_| to access it. - bool has_shutdown_; - - // Mutex to guard accesses to |has_shutdown_|. - mutable Lock lock_; + MessageLoop* const host_resolver_loop_; + scoped_refptr<Core> core_; }; // Subclass of SingleThreadedProxyResolver that additionally calls @@ -94,4 +63,3 @@ class SingleThreadedProxyResolverUsingBridgedHostResolver } // namespace net #endif // NET_PROXY_SYNC_HOST_RESOLVER_BRIDGE_H_ - diff --git a/net/proxy/sync_host_resolver_bridge_unittest.cc b/net/proxy/sync_host_resolver_bridge_unittest.cc index 916252b..42dbacc 100644 --- a/net/proxy/sync_host_resolver_bridge_unittest.cc +++ b/net/proxy/sync_host_resolver_bridge_unittest.cc @@ -5,6 +5,7 @@ #include "net/proxy/sync_host_resolver_bridge.h" #include "base/thread.h" +#include "base/waitable_event.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" @@ -116,16 +117,20 @@ class SyncProxyResolver : public ProxyResolver { // network stack. class IOThread : public base::Thread { public: - explicit IOThread(HostResolver* async_resolver) - : base::Thread("IO-thread"), async_resolver_(async_resolver) { - } + IOThread() : base::Thread("IO-thread") {} virtual ~IOThread() { Stop(); } + const scoped_refptr<BlockableHostResolver>& async_resolver() { + return async_resolver_; + } + protected: virtual void Init() { + async_resolver_ = new BlockableHostResolver(); + // Create a synchronous host resolver that operates the async host // resolver on THIS thread. scoped_refptr<SyncHostResolverBridge> sync_resolver = @@ -149,10 +154,19 @@ class IOThread : public base::Thread { // Delete the single threaded proxy resolver. proxy_resolver_.reset(); + + // During the teardown sequence of the single threaded proxy resolver, + // the outstanding host resolve should have been cancelled. + EXPECT_TRUE(async_resolver_->was_request_cancelled()); + + async_resolver_ = NULL; } private: - HostResolver* async_resolver_; + // This (async) host resolver will outlive the thread that is operating it + // synchronously. + scoped_refptr<BlockableHostResolver> async_resolver_; + scoped_ptr<ProxyResolver> proxy_resolver_; // Data for the outstanding request to the single threaded proxy resolver. @@ -165,35 +179,21 @@ class IOThread : public base::Thread { // is outstanding on the SyncHostResolverBridge. // This is a regression test for http://crbug.com/41244. TEST(SingleThreadedProxyResolverWithBridgedHostResolverTest, ShutdownDeadlock) { - // This (async) host resolver will outlive the thread that is operating it - // synchronously. - scoped_refptr<BlockableHostResolver> host_resolver = - new BlockableHostResolver(); - - { - IOThread io_thread(host_resolver.get()); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - ASSERT_TRUE(io_thread.StartWithOptions(options)); - - // Wait until the host resolver receives a request (this means that the - // PAC thread is now blocked, waiting for the async response from the - // host resolver. - host_resolver->WaitUntilRequestIsReceived(); - - // Now upon exitting this scope, the IOThread is destroyed -- this will - // stop the IOThread, which will in turn delete the - // SingleThreadedProxyResolver, which in turn will stop its internal - // PAC thread (which is currently blocked waiting on the host resolve which - // is running on IOThread). - } - - // During the teardown sequence of the single threaded proxy resolver, - // the outstanding host resolve should have been cancelled. - EXPECT_TRUE(host_resolver->was_request_cancelled()); + IOThread io_thread; + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + ASSERT_TRUE(io_thread.StartWithOptions(options)); + + io_thread.async_resolver()->WaitUntilRequestIsReceived(); + + // Now upon exitting this scope, the IOThread is destroyed -- this will + // stop the IOThread, which will in turn delete the + // SingleThreadedProxyResolver, which in turn will stop its internal + // PAC thread (which is currently blocked waiting on the host resolve which + // is running on IOThread). The IOThread::Cleanup() will verify that after + // the PAC thread is stopped, it cancels the request on the HostResolver. } } // namespace } // namespace net - |