blob: aedba35303805a0d2be7e99ef3fc17821904fb47 [file] [log] [blame]
[email protected]72b4a772010-07-14 01:29:301// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]61b84d52010-07-09 03:32:002// 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_
[email protected]32b76ef2010-07-26 23:08:247#pragma once
[email protected]61b84d52010-07-09 03:32:008
9#include <deque>
10#include <string>
11#include <vector>
12
13#include "base/basictypes.h"
14#include "base/non_thread_safe.h"
15#include "base/ref_counted.h"
16#include "base/scoped_ptr.h"
17#include "net/proxy/proxy_resolver.h"
18
19namespace base {
20class Thread;
21} // namespace base
22
23namespace net {
24
25// ProxyResolverFactory is an interface for creating ProxyResolver instances.
26class ProxyResolverFactory {
27 public:
28 explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes)
29 : resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {}
30
31 virtual ~ProxyResolverFactory() {}
32
33 // Creates a new ProxyResolver. The caller is responsible for freeing this
34 // object.
35 virtual ProxyResolver* CreateProxyResolver() = 0;
36
37 bool resolvers_expect_pac_bytes() const {
38 return resolvers_expect_pac_bytes_;
39 }
40
41 private:
42 bool resolvers_expect_pac_bytes_;
43 DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory);
44};
45
46// MultiThreadedProxyResolver is a ProxyResolver implementation that runs
47// synchronous ProxyResolver implementations on worker threads.
48//
49// Threads are created lazily on demand, up to a maximum total. The advantage
50// of having a pool of threads, is faster performance. In particular, being
51// able to keep servicing PAC requests even if one blocks its execution.
52//
53// During initialization (SetPacScript), a single thread is spun up to test
54// the script. If this succeeds, we cache the input script, and will re-use
55// this to lazily provision any new threads as needed.
56//
57// For each new thread that we spawn, a corresponding new ProxyResolver is
58// created using ProxyResolverFactory.
59//
60// Because we are creating multiple ProxyResolver instances, this means we
61// are duplicating script contexts for what is ordinarily seen as being a
62// single script. This can affect compatibility on some classes of PAC
63// script:
64//
65// (a) Scripts whose initialization has external dependencies on network or
66// time may end up successfully initializing on some threads, but not
67// others. So depending on what thread services the request, the result
68// may jump between several possibilities.
69//
70// (b) Scripts whose FindProxyForURL() depends on side-effects may now
71// work differently. For example, a PAC script which was incrementing
72// a global counter and using that to make a decision. In the
73// multi-threaded model, each thread may have a different value for this
74// counter, so it won't globally be seen as monotonically increasing!
75class MultiThreadedProxyResolver : public ProxyResolver, public 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();
[email protected]24476402010-07-20 20:55:17101 virtual int SetPacScript(
102 const scoped_refptr<ProxyResolverScriptData>& script_data,
103 CompletionCallback* callback);
[email protected]61b84d52010-07-09 03:32:00104
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
[email protected]61b84d52010-07-09 03:32:00115 // 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_;
[email protected]24476402010-07-20 20:55:17136 scoped_refptr<ProxyResolverScriptData> current_script_data_;
[email protected]61b84d52010-07-09 03:32:00137};
138
139} // namespace net
140
141#endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_