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 #pragma once 8 9 #include <deque> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/threading/non_thread_safe.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 MultiThreadedProxyResolver : public ProxyResolver, 75 public base::NonThreadSafe { 76 public: 77 // Creates an asynchronous ProxyResolver that runs requests on up to 78 // |max_num_threads|. 79 // 80 // For each thread that is created, an accompanying synchronous ProxyResolver 81 // will be provisioned using |resolver_factory|. All methods on these 82 // ProxyResolvers will be called on the one thread, with the exception of 83 // ProxyResolver::Shutdown() which will be called from the origin thread 84 // prior to destruction. 85 // 86 // The constructor takes ownership of |resolver_factory|. 87 MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory, 88 size_t max_num_threads); 89 90 virtual ~MultiThreadedProxyResolver(); 91 92 // ProxyResolver implementation: 93 virtual int GetProxyForURL(const GURL& url, 94 ProxyInfo* results, 95 CompletionCallback* callback, 96 RequestHandle* request, 97 const BoundNetLog& net_log); 98 virtual void CancelRequest(RequestHandle request); 99 virtual void CancelSetPacScript(); 100 virtual void PurgeMemory(); 101 virtual int SetPacScript( 102 const scoped_refptr<ProxyResolverScriptData>& script_data, 103 CompletionCallback* callback); 104 105 private: 106 class Executor; 107 class Job; 108 class SetPacScriptJob; 109 class GetProxyForURLJob; 110 // FIFO queue of pending jobs waiting to be started. 111 // TODO(eroman): Make this priority queue. 112 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; 113 typedef std::vector<scoped_refptr<Executor> > ExecutorList; 114 115 // Asserts that there are no outstanding user-initiated jobs on any of the 116 // worker threads. 117 void CheckNoOutstandingUserRequests() const; 118 119 // Stops and deletes all of the worker threads. 120 void ReleaseAllExecutors(); 121 122 // Returns an idle worker thread which is ready to receive GetProxyForURL() 123 // requests. If all threads are occupied, returns NULL. 124 Executor* FindIdleExecutor(); 125 126 // Creates a new worker thread, and appends it to |executors_|. 127 Executor* AddNewExecutor(); 128 129 // Starts the next job from |pending_jobs_| if possible. 130 void OnExecutorReady(Executor* executor); 131 132 const scoped_ptr<ProxyResolverFactory> resolver_factory_; 133 const size_t max_num_threads_; 134 PendingJobsQueue pending_jobs_; 135 ExecutorList executors_; 136 scoped_refptr<ProxyResolverScriptData> current_script_data_; 137 }; 138 139 } // namespace net 140 141 #endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ 142