OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ | 5 #ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |
6 #define NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ | 6 #define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |
7 | 7 |
8 #include <deque> | 8 #include <deque> |
9 #include <string> | 9 #include <string> |
| 10 #include <vector> |
10 | 11 |
| 12 #include "base/basictypes.h" |
| 13 #include "base/non_thread_safe.h" |
11 #include "base/ref_counted.h" | 14 #include "base/ref_counted.h" |
12 #include "base/scoped_ptr.h" | 15 #include "base/scoped_ptr.h" |
13 #include "net/proxy/proxy_resolver.h" | 16 #include "net/proxy/proxy_resolver.h" |
14 | 17 |
15 namespace base { | 18 namespace base { |
16 class Thread; | 19 class Thread; |
17 } // namespace base | 20 } // namespace base |
18 | 21 |
19 namespace net { | 22 namespace net { |
20 | 23 |
21 // ProxyResolver implementation that wraps a synchronous ProxyResolver, and | 24 // ProxyResolverFactory is an interface for creating ProxyResolver instances. |
22 // runs it on a single worker thread. If multiple requests accumulate, they | 25 class ProxyResolverFactory { |
23 // are serviced in FIFO order. | |
24 class SingleThreadedProxyResolver : public ProxyResolver { | |
25 public: | 26 public: |
26 // |resolver| is a synchronous ProxyResolver implementation. It doesn't | 27 explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes) |
27 // have to be thread-safe, since it is run on exactly one thread. The | 28 : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {} |
28 // constructor takes ownership of |resolver|. | |
29 explicit SingleThreadedProxyResolver(ProxyResolver* resolver); | |
30 | 29 |
31 virtual ~SingleThreadedProxyResolver(); | 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, 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(); |
32 | 90 |
33 // ProxyResolver implementation: | 91 // ProxyResolver implementation: |
34 virtual int GetProxyForURL(const GURL& url, | 92 virtual int GetProxyForURL(const GURL& url, |
35 ProxyInfo* results, | 93 ProxyInfo* results, |
36 CompletionCallback* callback, | 94 CompletionCallback* callback, |
37 RequestHandle* request, | 95 RequestHandle* request, |
38 const BoundNetLog& net_log); | 96 const BoundNetLog& net_log); |
39 virtual void CancelRequest(RequestHandle request); | 97 virtual void CancelRequest(RequestHandle request); |
40 virtual void CancelSetPacScript(); | 98 virtual void CancelSetPacScript(); |
41 virtual void PurgeMemory(); | 99 virtual void PurgeMemory(); |
42 | 100 |
43 protected: | |
44 // The wrapped (synchronous) ProxyResolver. | |
45 ProxyResolver* resolver() { return resolver_.get(); } | |
46 | |
47 private: | 101 private: |
48 // Refcounted helper class that bridges between origin thread and worker | 102 class Executor; |
49 // thread. | |
50 class Job; | 103 class Job; |
51 friend class Job; | 104 class SetPacScriptJob; |
52 class SetPacScriptTask; | 105 class GetProxyForURLJob; |
53 friend class SetPacScriptTask; | 106 // FIFO queue of pending jobs waiting to be started. |
54 // FIFO queue that contains the in-progress job, and any pending jobs. | 107 // TODO(eroman): Make this priority queue. |
55 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; | 108 typedef std::deque<scoped_refptr<Job> > PendingJobsQueue; |
56 | 109 typedef std::vector<scoped_refptr<Executor> > ExecutorList; |
57 base::Thread* thread() { return thread_.get(); } | |
58 | 110 |
59 // ProxyResolver implementation: | 111 // ProxyResolver implementation: |
60 virtual int SetPacScript(const GURL& pac_url, | 112 virtual int SetPacScript(const GURL& pac_url, |
61 const string16& pac_script, | 113 const string16& pac_script, |
62 CompletionCallback* callback); | 114 CompletionCallback* callback); |
63 | 115 |
64 // Starts the worker thread if it isn't already running. | 116 // Asserts that there are no outstanding user-initiated jobs on any of the |
65 void EnsureThreadStarted(); | 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(); |
66 | 129 |
67 // Starts the next job from |pending_jobs_| if possible. | 130 // Starts the next job from |pending_jobs_| if possible. |
68 void ProcessPendingJobs(); | 131 void OnExecutorReady(Executor* executor); |
69 | 132 |
70 // Removes the front entry of the jobs queue. |expected_job| is our | 133 const scoped_ptr<ProxyResolverFactory> resolver_factory_; |
71 // expectation of what the front of the job queue is; it is only used by | 134 const size_t max_num_threads_; |
72 // DCHECK for verification purposes. | |
73 void RemoveFrontOfJobsQueueAndStartNext(Job* expected_job); | |
74 | |
75 // Clears |outstanding_set_pac_script_task_|. | |
76 // Called when |task| has just finished. | |
77 void RemoveOutstandingSetPacScriptTask(SetPacScriptTask* task); | |
78 | |
79 // The synchronous resolver implementation. | |
80 scoped_ptr<ProxyResolver> resolver_; | |
81 | |
82 // The thread where |resolver_| is run on. | |
83 // Note that declaration ordering is important here. |thread_| needs to be | |
84 // destroyed *before* |resolver_|, in case |resolver_| is currently | |
85 // executing on |thread_|. | |
86 scoped_ptr<base::Thread> thread_; | |
87 | |
88 PendingJobsQueue pending_jobs_; | 135 PendingJobsQueue pending_jobs_; |
89 scoped_refptr<SetPacScriptTask> outstanding_set_pac_script_task_; | 136 ExecutorList executors_; |
| 137 bool was_set_pac_script_called_; |
| 138 GURL current_pac_url_; |
| 139 string16 current_pac_script_; |
90 }; | 140 }; |
91 | 141 |
92 } // namespace net | 142 } // namespace net |
93 | 143 |
94 #endif // NET_PROXY_SINGLE_THREADED_PROXY_RESOLVER_H_ | 144 #endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_ |
OLD | NEW |