| Index: net/proxy/multi_threaded_proxy_resolver.h
|
| ===================================================================
|
| --- net/proxy/multi_threaded_proxy_resolver.h (revision 51914)
|
| +++ net/proxy/multi_threaded_proxy_resolver.h (working copy)
|
| @@ -2,12 +2,15 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#ifndef NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_
|
| -#define NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_
|
| +#ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
|
| +#define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
|
|
|
| #include <deque>
|
| #include <string>
|
| +#include <vector>
|
|
|
| +#include "base/basictypes.h"
|
| +#include "base/non_thread_safe.h"
|
| #include "base/ref_counted.h"
|
| #include "base/scoped_ptr.h"
|
| #include "net/proxy/proxy_resolver.h"
|
| @@ -18,18 +21,73 @@
|
|
|
| namespace net {
|
|
|
| -// ProxyResolver implementation that wraps a synchronous ProxyResolver, and
|
| -// runs it on a single worker thread. If multiple requests accumulate, they
|
| -// are serviced in FIFO order.
|
| -class SingleThreadedProxyResolver : public ProxyResolver {
|
| +// ProxyResolverFactory is an interface for creating ProxyResolver instances.
|
| +class ProxyResolverFactory {
|
| public:
|
| - // |resolver| is a synchronous ProxyResolver implementation. It doesn't
|
| - // have to be thread-safe, since it is run on exactly one thread. The
|
| - // constructor takes ownership of |resolver|.
|
| - explicit SingleThreadedProxyResolver(ProxyResolver* resolver);
|
| + explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes)
|
| + : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {}
|
|
|
| - virtual ~SingleThreadedProxyResolver();
|
| + virtual ~ProxyResolverFactory() {}
|
|
|
| + // Creates a new ProxyResolver. The caller is responsible for freeing this
|
| + // object.
|
| + virtual ProxyResolver* CreateProxyResolver() = 0;
|
| +
|
| + bool resolvers_expect_pac_bytes() const {
|
| + return resolvers_expect_pac_bytes_;
|
| + }
|
| +
|
| + private:
|
| + bool resolvers_expect_pac_bytes_;
|
| + DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory);
|
| +};
|
| +
|
| +// MultiThreadedProxyResolver is a ProxyResolver implementation that runs
|
| +// synchronous ProxyResolver implementations on worker threads.
|
| +//
|
| +// Threads are created lazily on demand, up to a maximum total. The advantage
|
| +// of having a pool of threads, is faster performance. In particular, being
|
| +// able to keep servicing PAC requests even if one blocks its execution.
|
| +//
|
| +// During initialization (SetPacScript), a single thread is spun up to test
|
| +// the script. If this succeeds, we cache the input script, and will re-use
|
| +// this to lazily provision any new threads as needed.
|
| +//
|
| +// For each new thread that we spawn, a corresponding new ProxyResolver is
|
| +// created using ProxyResolverFactory.
|
| +//
|
| +// Because we are creating multiple ProxyResolver instances, this means we
|
| +// are duplicating script contexts for what is ordinarily seen as being a
|
| +// single script. This can affect compatibility on some classes of PAC
|
| +// script:
|
| +//
|
| +// (a) Scripts whose initialization has external dependencies on network or
|
| +// time may end up successfully initializing on some threads, but not
|
| +// others. So depending on what thread services the request, the result
|
| +// may jump between several possibilities.
|
| +//
|
| +// (b) Scripts whose FindProxyForURL() depends on side-effects may now
|
| +// work differently. For example, a PAC script which was incrementing
|
| +// a global counter and using that to make a decision. In the
|
| +// multi-threaded model, each thread may have a different value for this
|
| +// counter, so it won't globally be seen as monotonically increasing!
|
| +class MultiThreadedProxyResolver : public ProxyResolver, public NonThreadSafe {
|
| + public:
|
| + // Creates an asynchronous ProxyResolver that runs requests on up to
|
| + // |max_num_threads|.
|
| + //
|
| + // For each thread that is created, an accompanying synchronous ProxyResolver
|
| + // will be provisioned using |resolver_factory|. All methods on these
|
| + // ProxyResolvers will be called on the one thread, with the exception of
|
| + // ProxyResolver::Shutdown() which will be called from the origin thread
|
| + // prior to destruction.
|
| + //
|
| + // The constructor takes ownership of |resolver_factory|.
|
| + MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory,
|
| + size_t max_num_threads);
|
| +
|
| + virtual ~MultiThreadedProxyResolver();
|
| +
|
| // ProxyResolver implementation:
|
| virtual int GetProxyForURL(const GURL& url,
|
| ProxyInfo* results,
|
| @@ -40,55 +98,47 @@
|
| virtual void CancelSetPacScript();
|
| virtual void PurgeMemory();
|
|
|
| - protected:
|
| - // The wrapped (synchronous) ProxyResolver.
|
| - ProxyResolver* resolver() { return resolver_.get(); }
|
| -
|
| private:
|
| - // Refcounted helper class that bridges between origin thread and worker
|
| - // thread.
|
| + class Executor;
|
| class Job;
|
| - friend class Job;
|
| - class SetPacScriptTask;
|
| - friend class SetPacScriptTask;
|
| - // FIFO queue that contains the in-progress job, and any pending jobs.
|
| + class SetPacScriptJob;
|
| + class GetProxyForURLJob;
|
| + // FIFO queue of pending jobs waiting to be started.
|
| + // TODO(eroman): Make this priority queue.
|
| typedef std::deque<scoped_refptr<Job> > PendingJobsQueue;
|
| + typedef std::vector<scoped_refptr<Executor> > ExecutorList;
|
|
|
| - base::Thread* thread() { return thread_.get(); }
|
| -
|
| // ProxyResolver implementation:
|
| virtual int SetPacScript(const GURL& pac_url,
|
| const string16& pac_script,
|
| CompletionCallback* callback);
|
|
|
| - // Starts the worker thread if it isn't already running.
|
| - void EnsureThreadStarted();
|
| + // Asserts that there are no outstanding user-initiated jobs on any of the
|
| + // worker threads.
|
| + void CheckNoOutstandingUserRequests() const;
|
|
|
| - // Starts the next job from |pending_jobs_| if possible.
|
| - void ProcessPendingJobs();
|
| + // Stops and deletes all of the worker threads.
|
| + void ReleaseAllExecutors();
|
|
|
| - // Removes the front entry of the jobs queue. |expected_job| is our
|
| - // expectation of what the front of the job queue is; it is only used by
|
| - // DCHECK for verification purposes.
|
| - void RemoveFrontOfJobsQueueAndStartNext(Job* expected_job);
|
| + // Returns an idle worker thread which is ready to receive GetProxyForURL()
|
| + // requests. If all threads are occupied, returns NULL.
|
| + Executor* FindIdleExecutor();
|
|
|
| - // Clears |outstanding_set_pac_script_task_|.
|
| - // Called when |task| has just finished.
|
| - void RemoveOutstandingSetPacScriptTask(SetPacScriptTask* task);
|
| + // Creates a new worker thread, and appends it to |executors_|.
|
| + Executor* AddNewExecutor();
|
|
|
| - // The synchronous resolver implementation.
|
| - scoped_ptr<ProxyResolver> resolver_;
|
| + // Starts the next job from |pending_jobs_| if possible.
|
| + void OnExecutorReady(Executor* executor);
|
|
|
| - // The thread where |resolver_| is run on.
|
| - // Note that declaration ordering is important here. |thread_| needs to be
|
| - // destroyed *before* |resolver_|, in case |resolver_| is currently
|
| - // executing on |thread_|.
|
| - scoped_ptr<base::Thread> thread_;
|
| -
|
| + const scoped_ptr<ProxyResolverFactory> resolver_factory_;
|
| + const size_t max_num_threads_;
|
| PendingJobsQueue pending_jobs_;
|
| - scoped_refptr<SetPacScriptTask> outstanding_set_pac_script_task_;
|
| + ExecutorList executors_;
|
| + bool was_set_pac_script_called_;
|
| + GURL current_pac_url_;
|
| + string16 current_pac_script_;
|
| };
|
|
|
| } // namespace net
|
|
|
| -#endif // NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_
|
| +#endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
|
|
|