• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
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 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