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