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