1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/sync_host_resolver_bridge.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h" 83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/address_list.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_log.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/multi_threaded_proxy_resolver.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/test_completion_callback.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/proxy/proxy_info.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(eroman): This test should be moved into 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// multi_threaded_proxy_resolver_unittest.cc. 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net { 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This implementation of HostResolver allows blocking until a resolve request 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// has been received. The resolve requests it receives will never be completed. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BlockableHostResolver : public HostResolver { 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BlockableHostResolver() 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : event_(true, false), 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch was_request_cancelled_(false) { 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int Resolve(const RequestInfo& info, 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddressList* addresses, 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CompletionCallback* callback, 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RequestHandle* out_req, 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BoundNetLog& net_log) { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_TRUE(callback); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_TRUE(out_req); 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *out_req = reinterpret_cast<RequestHandle*>(1); // Magic value. 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Indicate to the caller that a request was received. 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event_.Signal(); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We return ERR_IO_PENDING, as this request will NEVER be completed. 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Expectation is for the caller to later cancel the request. 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ERR_IO_PENDING; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void CancelRequest(RequestHandle req) { 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req); 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch was_request_cancelled_ = true; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void AddObserver(Observer* observer) { 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void RemoveObserver(Observer* observer) { 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Waits until Resolve() has been called. 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void WaitUntilRequestIsReceived() { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch event_.Wait(); 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool was_request_cancelled() const { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return was_request_cancelled_; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Event to notify when a resolve request was received. 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::WaitableEvent event_; 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool was_request_cancelled_; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This implementation of ProxyResolver simply does a synchronous resolve 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// on |host_resolver| in response to GetProxyForURL(). 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SyncProxyResolver : public ProxyResolver { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit SyncProxyResolver(SyncHostResolverBridge* host_resolver) 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ProxyResolver(false), host_resolver_(host_resolver) {} 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int GetProxyForURL(const GURL& url, 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ProxyInfo* results, 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CompletionCallback* callback, 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RequestHandle* request, 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const BoundNetLog& net_log) { 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_FALSE(callback); 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_FALSE(request); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Do a synchronous host resolve. 943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick HostResolver::RequestInfo info(HostPortPair::FromURL(url)); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddressList addresses; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int rv = 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_resolver_->Resolve(info, &addresses, NULL, NULL, BoundNetLog()); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(ERR_ABORTED, rv); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return rv; 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void CancelRequest(RequestHandle request) { 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Shutdown() { 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host_resolver_->Shutdown(); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen virtual void CancelSetPacScript() { 11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen NOTREACHED(); 11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual int SetPacScript( 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const scoped_refptr<ProxyResolverScriptData>& script_data, 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CompletionCallback* callback) { 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return OK; 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SyncHostResolverBridge* const host_resolver_; 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SyncProxyResolverFactory : public ProxyResolverFactory { 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Takes ownership of |sync_host_resolver|. 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit SyncProxyResolverFactory(SyncHostResolverBridge* sync_host_resolver) 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ProxyResolverFactory(false), 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sync_host_resolver_(sync_host_resolver) { 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ProxyResolver* CreateProxyResolver() { 135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return new SyncProxyResolver(sync_host_resolver_.get()); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const scoped_ptr<SyncHostResolverBridge> sync_host_resolver_; 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This helper thread is used to create the circumstances for the deadlock. 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// It is analagous to the "IO thread" which would be main thread running the 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// network stack. 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass IOThread : public base::Thread { 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IOThread() : base::Thread("IO-thread") {} 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~IOThread() { 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Stop(); 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BlockableHostResolver* async_resolver() { 154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return async_resolver_.get(); 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected: 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Init() { 159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick async_resolver_.reset(new BlockableHostResolver()); 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a synchronous host resolver that operates the async host 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // resolver on THIS thread. 163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SyncHostResolverBridge* sync_resolver = 164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick new SyncHostResolverBridge(async_resolver_.get(), message_loop()); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_resolver_.reset( 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new MultiThreadedProxyResolver( 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new SyncProxyResolverFactory(sync_resolver), 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1u)); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the resolver. 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TestCompletionCallback callback; 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_resolver_->SetPacScript(ProxyResolverScriptData::FromURL(GURL()), 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &callback); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_EQ(OK, callback.WaitForResult()); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start an asynchronous request to the proxy resolver 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (note that it will never complete). 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_resolver_->GetProxyForURL(GURL("http://test/"), &results_, 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &callback_, &request_, BoundNetLog()); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void CleanUp() { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Cancel the outstanding request (note however that this will not 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // unblock the PAC thread though). 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_resolver_->CancelRequest(request_); 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Delete the single threaded proxy resolver. 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_resolver_.reset(); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (There may have been a completion posted back to origin thread, avoid 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // leaking it by running). 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->RunAllPending(); 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // During the teardown sequence of the single threaded proxy resolver, 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the outstanding host resolve should have been cancelled. 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EXPECT_TRUE(async_resolver_->was_request_cancelled()); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This (async) host resolver will outlive the thread that is operating it 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // synchronously. 203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick scoped_ptr<BlockableHostResolver> async_resolver_; 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<ProxyResolver> proxy_resolver_; 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Data for the outstanding request to the single threaded proxy resolver. 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TestCompletionCallback callback_; 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ProxyInfo results_; 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ProxyResolver::RequestHandle request_; 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test that a deadlock does not happen during shutdown when a host resolve 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is outstanding on the SyncHostResolverBridge. 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This is a regression test for http://crbug.com/41244. 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST(MultiThreadedProxyResolverTest, ShutdownIsCalledBeforeThreadJoin) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IOThread io_thread; 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::Thread::Options options; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options.message_loop_type = MessageLoop::TYPE_IO; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ASSERT_TRUE(io_thread.StartWithOptions(options)); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch io_thread.async_resolver()->WaitUntilRequestIsReceived(); 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now upon exitting this scope, the IOThread is destroyed -- this will 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // stop the IOThread, which will in turn delete the 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // SingleThreadedProxyResolver, which in turn will stop its internal 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // PAC thread (which is currently blocked waiting on the host resolve which 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is running on IOThread). The IOThread::Cleanup() will verify that after 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the PAC thread is stopped, it cancels the request on the HostResolver. 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace net 235