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.
5 #ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
6 #define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
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"
24 // ProxyResolverFactory is an interface for creating ProxyResolver instances.
25 class ProxyResolverFactory
{
27 explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes
)
28 : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes
) {}
30 virtual ~ProxyResolverFactory() {}
32 // Creates a new ProxyResolver. The caller is responsible for freeing this
34 virtual ProxyResolver
* CreateProxyResolver() = 0;
36 bool resolvers_expect_pac_bytes() const {
37 return resolvers_expect_pac_bytes_
;
41 bool resolvers_expect_pac_bytes_
;
42 DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory
);
45 // MultiThreadedProxyResolver is a ProxyResolver implementation that runs
46 // synchronous ProxyResolver implementations on worker threads.
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.
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.
56 // For each new thread that we spawn, a corresponding new ProxyResolver is
57 // created using ProxyResolverFactory.
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
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.
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
) {
78 // Creates an asynchronous ProxyResolver that runs requests on up to
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.
87 // The constructor takes ownership of |resolver_factory|.
88 MultiThreadedProxyResolver(ProxyResolverFactory
* resolver_factory
,
89 size_t max_num_threads
);
91 ~MultiThreadedProxyResolver() override
;
93 // ProxyResolver implementation:
94 int GetProxyForURL(const GURL
& url
,
96 const CompletionCallback
& callback
,
97 RequestHandle
* request
,
98 const BoundNetLog
& net_log
) override
;
99 void CancelRequest(RequestHandle request
) override
;
100 LoadState
GetLoadState(RequestHandle request
) const override
;
101 void CancelSetPacScript() override
;
102 int SetPacScript(const scoped_refptr
<ProxyResolverScriptData
>& script_data
,
103 const CompletionCallback
& callback
) override
;
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
;
115 // Asserts that there are no outstanding user-initiated jobs on any of the
117 void CheckNoOutstandingUserRequests() const;
119 // Stops and deletes all of the worker threads.
120 void ReleaseAllExecutors();
122 // Returns an idle worker thread which is ready to receive GetProxyForURL()
123 // requests. If all threads are occupied, returns NULL.
124 Executor
* FindIdleExecutor();
126 // Creates a new worker thread, and appends it to |executors_|.
127 Executor
* AddNewExecutor();
129 // Starts the next job from |pending_jobs_| if possible.
130 void OnExecutorReady(Executor
* executor
);
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_
;
141 #endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_