15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/multi_threaded_proxy_resolver.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/stringprintf.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_info.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(eroman): Have the MultiThreadedProxyResolver clear its PAC script 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data when SetPacScript fails. That will reclaim memory when 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// testing bogus scripts. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An "executor" is a job-runner for PAC requests. It encapsulates a worker 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread and a synchronous ProxyResolver (which will be operated on said 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread.) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiThreadedProxyResolver::Executor 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<MultiThreadedProxyResolver::Executor > { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |coordinator| must remain valid throughout our lifetime. It is used to 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // signal when the executor is ready to receive work by calling 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |coordinator->OnExecutorReady()|. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The constructor takes ownership of |resolver|. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |thread_number| is an identifier used when naming the worker thread. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor(MultiThreadedProxyResolver* coordinator, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thread_number); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Submit a job to this executor. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void StartJob(Job* job); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Callback for when a job has completed running on the executor's thread. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnJobCompleted(Job* job); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cleanup the executor. Cancels all outstanding work, and frees the thread 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and resolver. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Destroy(); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns the outstanding job, or NULL. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Job* outstanding_job() const { return outstanding_job_.get(); } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver() { return resolver_.get(); } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thread_number() const { return thread_number_; } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<Executor>; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Executor(); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiThreadedProxyResolver* coordinator_; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int thread_number_; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The currently active job for this executor (either a SetPacScript or 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetProxyForURL task). 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Job> outstanding_job_; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The synchronous resolver implementation. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ProxyResolver> resolver_; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The thread where |resolver_| is run on. 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that declaration ordering is important here. |thread_| needs to be 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destroyed *before* |resolver_|, in case |resolver_| is currently 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // executing on |thread_|. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<base::Thread> thread_; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiThreadedProxyResolver::Job --------------------------------------------- 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiThreadedProxyResolver::Job 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public base::RefCountedThreadSafe<MultiThreadedProxyResolver::Job> { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Identifies the subclass of Job (only being used for debugging purposes). 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum Type { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TYPE_GET_PROXY_FOR_URL, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TYPE_SET_PAC_SCRIPT, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TYPE_SET_PAC_SCRIPT_INTERNAL, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Job(Type type, const CompletionCallback& callback) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : type_(type), 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_(callback), 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor_(NULL), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_cancelled_(false) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_executor(Executor* executor) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor_ = executor; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "executor" is the job runner that is scheduling this job. If 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this job has not been submitted to an executor yet, this will be 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL (and we know it hasn't started yet). 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor* executor() { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return executor_; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark the job as having been cancelled. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Cancel() { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_cancelled_ = true; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if Cancel() has been called. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_cancelled() const { return was_cancelled_; } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Type type() const { return type_; } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if this job still has a user callback. Some jobs 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do not have a user callback, because they were helper jobs 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // scheduled internally (for example TYPE_SET_PAC_SCRIPT_INTERNAL). 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise jobs that correspond with user-initiated work will 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have a non-null callback up until the callback is run. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool has_user_callback() const { return !callback_.is_null(); } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This method is called when the job is inserted into a wait queue 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because no executors were ready to accept it. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void WaitingForThread() {} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This method is called just before the job is posted to the work thread. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void FinishedWaitingForThread() {} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This method is called on the worker thread to do the job's work. On 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // completion, implementors are expected to call OnJobCompleted() on 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |origin_loop|. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) = 0; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void OnJobCompleted() { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |executor_| will be NULL if the executor has already been deleted. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (executor_) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor_->OnJobCompleted(this); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RunUserCallback(int result) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(has_user_callback()); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback callback = callback_; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Reset the callback so has_user_callback() will now return false. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_.Reset(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback.Run(result); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class base::RefCountedThreadSafe<MultiThreadedProxyResolver::Job>; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Job() {} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Type type_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompletionCallback callback_; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor* executor_; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_cancelled_; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiThreadedProxyResolver::SetPacScriptJob --------------------------------- 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Runs on the worker thread to call ProxyResolver::SetPacScript. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiThreadedProxyResolver::SetPacScriptJob 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public MultiThreadedProxyResolver::Job { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetPacScriptJob(const scoped_refptr<ProxyResolverScriptData>& script_data, 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : Job(!callback.is_null() ? TYPE_SET_PAC_SCRIPT : 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TYPE_SET_PAC_SCRIPT_INTERNAL, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback), 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_data_(script_data) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs on the worker thread. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver = executor()->resolver(); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = resolver->SetPacScript(script_data_, CompletionCallback()); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(rv, ERR_IO_PENDING); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origin_loop->PostTask( 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&SetPacScriptJob::RequestComplete, this, rv)); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~SetPacScriptJob() {} 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs the completion callback on the origin thread. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void RequestComplete(int result_code) { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The task may have been cancelled after it was started. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!was_cancelled() && has_user_callback()) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunUserCallback(result_code); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnJobCompleted(); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const scoped_refptr<ProxyResolverScriptData> script_data_; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiThreadedProxyResolver::GetProxyForURLJob ------------------------------ 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiThreadedProxyResolver::GetProxyForURLJob 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public MultiThreadedProxyResolver::Job { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |url| -- the URL of the query. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |results| -- the structure to fill with proxy resolve results. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetProxyForURLJob(const GURL& url, 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyInfo* results, 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback& callback, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BoundNetLog& net_log) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : Job(TYPE_GET_PROXY_FOR_URL, callback), 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_(results), 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_(net_log), 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_(url), 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_waiting_for_thread_(false) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!callback.is_null()); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BoundNetLog* net_log() { return &net_log_; } 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void WaitingForThread() OVERRIDE { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_waiting_for_thread_ = true; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.BeginEvent(NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void FinishedWaitingForThread() OVERRIDE { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(executor()); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (was_waiting_for_thread_) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.EndEvent(NetLog::TYPE_WAITING_FOR_PROXY_RESOLVER_THREAD); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_.AddEvent( 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::TYPE_SUBMITTED_TO_RESOLVER_THREAD, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog::IntegerCallback("thread_number", executor()->thread_number())); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs on the worker thread. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver = executor()->resolver(); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int rv = resolver->GetProxyForURL( 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_, &results_buf_, CompletionCallback(), NULL, net_log_); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_NE(rv, ERR_IO_PENDING); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) origin_loop->PostTask( 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&GetProxyForURLJob::QueryComplete, this, rv)); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~GetProxyForURLJob() {} 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Runs the completion callback on the origin thread. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void QueryComplete(int result_code) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The Job may have been cancelled after it was started. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!was_cancelled()) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result_code >= OK) { // Note: unit-tests use values > 0. 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) results_->Use(results_buf_); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RunUserCallback(result_code); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnJobCompleted(); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Must only be used on the "origin" thread. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyInfo* results_; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can be used on either "origin" or worker thread. 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BoundNetLog net_log_; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL url_; 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Usable from within DoQuery on the worker thread. 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyInfo results_buf_; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_waiting_for_thread_; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiThreadedProxyResolver::Executor ---------------------------------------- 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::Executor::Executor( 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiThreadedProxyResolver* coordinator, 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver, 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thread_number) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : coordinator_(coordinator), 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_number_(thread_number), 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_(resolver) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(coordinator); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(resolver); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start up the thread. 2950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch thread_.reset(new base::Thread(base::StringPrintf("PAC thread #%d", 2960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch thread_number))); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(thread_->Start()); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::Executor::StartJob(Job* job) { 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!outstanding_job_.get()); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) outstanding_job_ = job; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Run the job. Once it has completed (regardless of whether it was 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cancelled), it will invoke OnJobCompleted() on this thread. 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->set_executor(this); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->FinishedWaitingForThread(); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_->message_loop()->PostTask( 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&Job::Run, job, base::MessageLoopProxy::current())); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::Executor::OnJobCompleted(Job* job) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(job, outstanding_job_.get()); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) outstanding_job_ = NULL; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) coordinator_->OnExecutorReady(this); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::Executor::Destroy() { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(coordinator_); 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See http://crbug.com/69710. 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowIO allow_io; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Join the worker thread. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thread_.reset(); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel any outstanding job. 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (outstanding_job_.get()) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) outstanding_job_->Cancel(); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Orphan the job (since this executor may be deleted soon). 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) outstanding_job_->set_executor(NULL); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is now safe to free the ProxyResolver, since all the tasks that 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // were using it on the resolver thread have completed. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_.reset(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Null some stuff as a precaution. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) coordinator_ = NULL; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) outstanding_job_ = NULL; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::Executor::~Executor() { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The important cleanup happens as part of Destroy(), which should always be 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // called first. 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!coordinator_) << "Destroy() was not called"; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!thread_.get()); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!resolver_.get()); 352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!outstanding_job_.get()); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MultiThreadedProxyResolver -------------------------------------------------- 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::MultiThreadedProxyResolver( 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolverFactory* resolver_factory, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t max_num_threads) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : ProxyResolver(resolver_factory->resolvers_expect_pac_bytes()), 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_factory_(resolver_factory), 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_num_threads_(max_num_threads) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(max_num_threads, 1u); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::~MultiThreadedProxyResolver() { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We will cancel all outstanding requests. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_jobs_.clear(); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseAllExecutors(); 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int MultiThreadedProxyResolver::GetProxyForURL( 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, ProxyInfo* results, const CompletionCallback& callback, 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RequestHandle* request, const BoundNetLog& net_log) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!callback.is_null()); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(current_script_data_.get()) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Resolver is un-initialized. Must call SetPacScript() first!"; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<GetProxyForURLJob> job( 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new GetProxyForURLJob(url, results, callback, net_log)); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Completion will be notified through |callback|, unless the caller cancels 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the request using |request|. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (request) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *request = reinterpret_cast<RequestHandle>(job.get()); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is an executor that is ready to run this request, submit it! 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor* executor = FindIdleExecutor(); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (executor) { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0u, pending_jobs_.size()); 392868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) executor->StartJob(job.get()); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_IO_PENDING; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise queue this request. (We will schedule it to a thread once one 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // becomes available). 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->WaitingForThread(); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_jobs_.push_back(job); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we haven't already reached the thread limit, provision a new thread to 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // drain the requests more quickly. 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (executors_.size() < max_num_threads_) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor = AddNewExecutor(); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor->StartJob( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new SetPacScriptJob(current_script_data_, CompletionCallback())); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_IO_PENDING; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::CancelRequest(RequestHandle req) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(req); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Job* job = reinterpret_cast<Job*>(req); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(Job::TYPE_GET_PROXY_FOR_URL, job->type()); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (job->executor()) { 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the job was already submitted to the executor, just mark it 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as cancelled so the user callback isn't run on completion. 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) job->Cancel(); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Otherwise the job is just sitting in a queue. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingJobsQueue::iterator it = 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(pending_jobs_.begin(), pending_jobs_.end(), job); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it != pending_jobs_.end()); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_jobs_.erase(it); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState MultiThreadedProxyResolver::GetLoadState(RequestHandle req) const { 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(req); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return LOAD_STATE_RESOLVING_PROXY_FOR_URL; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::CancelSetPacScript() { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0u, pending_jobs_.size()); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(1u, executors_.size()); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(Job::TYPE_SET_PAC_SCRIPT, 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executors_[0]->outstanding_job()->type()); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Defensively clear some data which shouldn't be getting used 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // anymore. 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_script_data_ = NULL; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseAllExecutors(); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int MultiThreadedProxyResolver::SetPacScript( 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const scoped_refptr<ProxyResolverScriptData>& script_data, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const CompletionCallback&callback) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!callback.is_null()); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save the script details, so we can provision new executors later. 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_script_data_ = script_data; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The user should not have any outstanding requests when they call 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SetPacScript(). 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CheckNoOutstandingUserRequests(); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy all of the current threads and their proxy resolvers. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReleaseAllExecutors(); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Provision a new executor, and run the SetPacScript request. On completion 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // notification will be sent through |callback|. 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor* executor = AddNewExecutor(); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor->StartJob(new SetPacScriptJob(script_data, callback)); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ERR_IO_PENDING; 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::CheckNoOutstandingUserRequests() const { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(0u, pending_jobs_.size()); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ExecutorList::const_iterator it = executors_.begin(); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != executors_.end(); ++it) { 481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const Executor* executor = it->get(); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Job* job = executor->outstanding_job(); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "has_user_callback()" is to exclude jobs for which the callback 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has already been invoked, or was not user-initiated (as in the case of 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lazy thread provisions). User-initiated jobs may !has_user_callback() 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when the callback has already been run. (Since we only clear the 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // outstanding job AFTER the callback has been invoked, it is possible 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for a new request to be started from within the callback). 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!job || job->was_cancelled() || !job->has_user_callback()); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::ReleaseAllExecutors() { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ExecutorList::iterator it = executors_.begin(); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != executors_.end(); ++it) { 497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Executor* executor = it->get(); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executor->Destroy(); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executors_.clear(); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::Executor* 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::FindIdleExecutor() { 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ExecutorList::iterator it = executors_.begin(); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != executors_.end(); ++it) { 508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Executor* executor = it->get(); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!executor->outstanding_job()) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return executor; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::Executor* 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MultiThreadedProxyResolver::AddNewExecutor() { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(executors_.size(), max_num_threads_); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "thread number" is used to give the thread a unique name. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int thread_number = executors_.size(); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyResolver* resolver = resolver_factory_->CreateProxyResolver(); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Executor* executor = new Executor( 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, resolver, thread_number); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executors_.push_back(make_scoped_refptr(executor)); 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return executor; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MultiThreadedProxyResolver::OnExecutorReady(Executor* executor) { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_jobs_.empty()) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the next job to process (FIFO). Transfer it from the pending queue 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to the executor. 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<Job> job = pending_jobs_.front(); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_jobs_.pop_front(); 537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) executor->StartJob(job.get()); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 541