diff options
Diffstat (limited to 'net/base/host_resolver.cc')
-rw-r--r-- | net/base/host_resolver.cc | 141 |
1 files changed, 85 insertions, 56 deletions
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc index 101c5ec..6d79b46 100644 --- a/net/base/host_resolver.cc +++ b/net/base/host_resolver.cc @@ -32,7 +32,9 @@ #include <ws2tcpip.h> #include <wspiapi.h> // Needed for Win2k compat. +#include "base/message_loop.h" #include "base/string_util.h" +#include "base/worker_pool.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/base/winsock_init.h" @@ -56,58 +58,94 @@ static int ResolveAddrInfo(const std::string& host, const std::string& port, //----------------------------------------------------------------------------- -struct HostResolver::Request : +class HostResolver::Request : public base::RefCountedThreadSafe<HostResolver::Request> { - Request() : error(OK), results(NULL) { - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &origin_thread, - 0, FALSE, DUPLICATE_SAME_ACCESS); + public: + Request(HostResolver* resolver, + const std::string& host, + const std::string& port, + AddressList* addresses, + CompletionCallback* callback) + : host_(host), + port_(port), + resolver_(resolver), + addresses_(addresses), + callback_(callback), + origin_loop_(MessageLoop::current()), + error_(OK), + results_(NULL) { } + ~Request() { - CloseHandle(origin_thread); + if (results_) + freeaddrinfo(results_); } - // Only used on the origin thread (where Resolve was called). - AddressList* addresses; - CompletionCallback* callback; + void DoLookup() { + // Running on the worker thread + error_ = ResolveAddrInfo(host_, port_, &results_); - // Set on the origin thread, read on the worker thread. - std::string host; - std::string port; - HANDLE origin_thread; - - // Assigned on the worker thread. - int error; - struct addrinfo* results; - - static void CALLBACK ReturnResults(ULONG_PTR param) { - Request* r = reinterpret_cast<Request*>(param); - // The HostResolver may have gone away. - if (r->addresses) { - if (r->error == OK) - r->addresses->Adopt(r->results); - if (r->callback) - r->callback->Run(r->error); - } else if (r->results) { - freeaddrinfo(r->results); + Task* reply = NewRunnableMethod(this, &Request::DoCallback); + + // The origin loop could go away while we are trying to post to it, so we + // need to call its PostTask method inside a lock. See ~HostResolver. + { + AutoLock locked(origin_loop_lock_); + if (origin_loop_) { + origin_loop_->PostTask(FROM_HERE, reply); + reply = NULL; + } } - r->Release(); + + // Does nothing if it got posted. + delete reply; } - static DWORD WINAPI DoLookup(void* param) { - Request* r = static_cast<Request*>(param); + void DoCallback() { + // Running on the origin thread. + DCHECK(error_ || results_); - r->error = ResolveAddrInfo(r->host, r->port, &r->results); + // We may have been cancelled! + if (!resolver_) + return; - if (!QueueUserAPC(ReturnResults, r->origin_thread, - reinterpret_cast<ULONG_PTR>(param))) { - // The origin thread must have gone away. - if (r->results) - freeaddrinfo(r->results); - r->Release(); + if (!error_) { + addresses_->Adopt(results_); + results_ = NULL; } - return 0; + + // Drop the resolver's reference to us. Do this before running the + // callback since the callback might result in the resolver being + // destroyed. + resolver_->request_ = NULL; + + callback_->Run(error_); + } + + void Cancel() { + resolver_ = NULL; + + AutoLock locked(origin_loop_lock_); + origin_loop_ = NULL; } + + private: + // Set on the origin thread, read on the worker thread. + std::string host_; + std::string port_; + + // Only used on the origin thread (where Resolve was called). + HostResolver* resolver_; + AddressList* addresses_; + CompletionCallback* callback_; + + // Used to post ourselves onto the origin thread. + Lock origin_loop_lock_; + MessageLoop* origin_loop_; + + // Assigned on the worker thread, read on the origin thread. + int error_; + struct addrinfo* results_; }; //----------------------------------------------------------------------------- @@ -117,17 +155,14 @@ HostResolver::HostResolver() { } HostResolver::~HostResolver() { - if (request_) { - // Prevent the thread pool from running the callback. - request_->addresses = NULL; - request_->callback = NULL; - } + if (request_) + request_->Cancel(); } int HostResolver::Resolve(const std::string& hostname, int port, AddressList* addresses, CompletionCallback* callback) { - DCHECK(!request_); + DCHECK(!request_) << "resolver already in use"; const std::string& port_str = IntToString(port); @@ -140,18 +175,12 @@ int HostResolver::Resolve(const std::string& hostname, int port, return rv; } + request_ = new Request(this, hostname, port_str, addresses, callback); + // Dispatch to worker thread... - request_ = new Request(); - request_->host = hostname; - request_->port = port_str; - request_->addresses = addresses; - request_->callback = callback; - - // Balanced in Request::ReturnResults (or DoLookup if there is an error). - request_->AddRef(); - if (!QueueUserWorkItem(Request::DoLookup, request_, WT_EXECUTELONGFUNCTION)) { - DLOG(ERROR) << "QueueUserWorkItem failed: " << GetLastError(); - request_->Release(); + if (!WorkerPool::PostTask(FROM_HERE, + NewRunnableMethod(request_.get(), &Request::DoLookup), true)) { + NOTREACHED(); request_ = NULL; return ERR_FAILED; } |