1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ 6 #define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ 7 8 #include <deque> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/threading/non_thread_safe.h" 15 #include "net/base/net_export.h" 16 #include "net/proxy/proxy_resolver.h" 17 18 namespace base { 19 class Thread; 20 } // namespace base 21 22 namespace net { 23 24 // ProxyResolverFactory is an interface for creating ProxyResolver instances. 25 class ProxyResolverFactory { 26 public: 27 explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes) 28 : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {} 29 30 virtual ~ProxyResolverFactory() {} 31 32 // Creates a new ProxyResolver. The caller is responsible for freeing this 33 // object. 34 virtual ProxyResolver* CreateProxyResolver() = 0; 35 36 bool resolvers_expect_pac_bytes() const { 37 return resolvers_expect_pac_bytes_; 38 } 39 40 private: 41 bool resolvers_expect_pac_bytes_; 42 DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory); 43 }; 44 45 // MultiThreadedProxyResolver is a ProxyResolver implementation that runs 46 // synchronous ProxyResolver implementations on worker threads. 47 // 48 // Threads are created lazily on demand, up to a maximum total. The advantage 49 // of having a pool of threads, is faster performance. In particular, being 50 // able to keep servicing PAC requests even if one blocks its execution. 51 // 52 // During initialization (SetPacScript), a single thread is spun up to test 53 // the script. If this succeeds, we cache the input script, and will re-use 54 // this to lazily provision any new threads as needed. 55 // 56 // For each new thread that we spawn, a corresponding new ProxyResolver is 57 // created using ProxyResolverFactory. 58 // 59 // Because we are creating multiple ProxyResolver instances, this means we 60 // are duplicating script contexts for what is ordinarily seen as being a 61 // single script. This can affect compatibility on some classes of PAC 62 // script: 63 // 64 // (a) Scripts whose initialization has external dependencies on network or 65 // time may end up successfully initializing on some threads, but not 66 // others. So depending on what thread services the request, the result 67 // may jump between several possibilities. 68 // 69 // (b) Scripts whose FindProxyForURL() depends on side-effects may now 70 // work differently. For example, a PAC script which was incrementing 71 // a global counter and using that to make a decision. In the 72 // multi-threaded model, each thread may have a different value for this 73 // counter, so it won't globally be seen as monotonically increasing! 74 class NET_EXPORT_PRIVATE MultiThreadedProxyResolver 75 : public ProxyResolver, 76 NON_EXPORTED_BASE(public base::NonThreadSafe) { 77 public: 78 // Creates an asynchronous ProxyResolver that runs requests on up to 79 // |max_num_threads|. 80 // 81 // For each thread that is created, an accompanying synchronous ProxyResolver 82 // will be provisioned using |resolver_factory|. All methods on these 83 // ProxyResolvers will be called on the one thread, with the exception of 84 // ProxyResolver::Shutdown() which will be called from the origin thread 85 // prior to destruction. 86 // 87 // The constructor takes ownership of |resolver_factory|. 88 MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory, 89 size_t max_num_threads); 90 91 virtual ~MultiThreadedProxyResolver(); 92 93 // ProxyResolver implementation: 94 virtual int GetProxyForURL(const GURL& url, 95 ProxyInfo* results, 96 const CompletionCallback& callback, 97 RequestHandle* request, 98 const BoundNetLog& net_log) OVERRIDE; 99 virtual void CancelRequest(RequestHandle request) OVERRIDE; 100 virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE; 101 virtual void CancelSetPacScript() OVERRIDE; 102 virtual void PurgeMemory() OVERRIDE; 103 virtual int SetPacScript( 104 const scoped_refptr<ProxyResolverScriptData>& script_data, 105 const CompletionCallback& callback) OVERRIDE; 106 107 private: 108 class Executor; 109 class Job; 110 class SetPacScriptJob; 111 class GetProxyForURLJob; 112 // FIFO queue of pending jobs waiting to be started. 113 // TODO(eroman): Make this priority queue. 114 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; 115 typedef std::vector<scoped_refptr<Executor> > ExecutorList; 116 117 // Asserts that there are no outstanding user-initiated jobs on any of the 118 // worker threads. 119 void CheckNoOutstandingUserRequests() const; 120 121 // Stops and deletes all of the worker threads. 122 void ReleaseAllExecutors(); 123 124 // Returns an idle worker thread which is ready to receive GetProxyForURL() 125 // requests. If all threads are occupied, returns NULL. 126 Executor* FindIdleExecutor(); 127 128 // Creates a new worker thread, and appends it to |executors_|. 129 Executor* AddNewExecutor(); 130 131 // Starts the next job from |pending_jobs_| if possible. 132 void OnExecutorReady(Executor* executor); 133 134 const scoped_ptr<ProxyResolverFactory> resolver_factory_; 135 const size_t max_num_threads_; 136 PendingJobsQueue pending_jobs_; 137 ExecutorList executors_; 138 scoped_refptr<ProxyResolverScriptData> current_script_data_; 139 }; 140 141 } // namespace net 142 143 #endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ 144