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: ProxyResolverFactory(bool resolvers_expect_pac_bytes)27 explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes) 28 : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {} 29 ~ProxyResolverFactory()30 virtual ~ProxyResolverFactory() {} 31 32 // Creates a new ProxyResolver. The caller is responsible for freeing this 33 // object. 34 virtual ProxyResolver* CreateProxyResolver() = 0; 35 resolvers_expect_pac_bytes()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 int SetPacScript( 103 const scoped_refptr<ProxyResolverScriptData>& script_data, 104 const CompletionCallback& callback) OVERRIDE; 105 106 private: 107 class Executor; 108 class Job; 109 class SetPacScriptJob; 110 class GetProxyForURLJob; 111 // FIFO queue of pending jobs waiting to be started. 112 // TODO(eroman): Make this priority queue. 113 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; 114 typedef std::vector<scoped_refptr<Executor> > ExecutorList; 115 116 // Asserts that there are no outstanding user-initiated jobs on any of the 117 // worker threads. 118 void CheckNoOutstandingUserRequests() const; 119 120 // Stops and deletes all of the worker threads. 121 void ReleaseAllExecutors(); 122 123 // Returns an idle worker thread which is ready to receive GetProxyForURL() 124 // requests. If all threads are occupied, returns NULL. 125 Executor* FindIdleExecutor(); 126 127 // Creates a new worker thread, and appends it to |executors_|. 128 Executor* AddNewExecutor(); 129 130 // Starts the next job from |pending_jobs_| if possible. 131 void OnExecutorReady(Executor* executor); 132 133 const scoped_ptr<ProxyResolverFactory> resolver_factory_; 134 const size_t max_num_threads_; 135 PendingJobsQueue pending_jobs_; 136 ExecutorList executors_; 137 scoped_refptr<ProxyResolverScriptData> current_script_data_; 138 }; 139 140 } // namespace net 141 142 #endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ 143