1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
#define NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
#include <deque>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/non_thread_safe.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "net/proxy/proxy_resolver.h"
namespace base {
class Thread;
} // namespace base
namespace net {
// ProxyResolverFactory is an interface for creating ProxyResolver instances.
class ProxyResolverFactory {
public:
explicit ProxyResolverFactory(bool resolvers_expect_pac_bytes)
: resolvers_expect_pac_bytes_(resolvers_expect_pac_bytes) {}
virtual ~ProxyResolverFactory() {}
// Creates a new ProxyResolver. The caller is responsible for freeing this
// object.
virtual ProxyResolver* CreateProxyResolver() = 0;
bool resolvers_expect_pac_bytes() const {
return resolvers_expect_pac_bytes_;
}
private:
bool resolvers_expect_pac_bytes_;
DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactory);
};
// MultiThreadedProxyResolver is a ProxyResolver implementation that runs
// synchronous ProxyResolver implementations on worker threads.
//
// Threads are created lazily on demand, up to a maximum total. The advantage
// of having a pool of threads, is faster performance. In particular, being
// able to keep servicing PAC requests even if one blocks its execution.
//
// During initialization (SetPacScript), a single thread is spun up to test
// the script. If this succeeds, we cache the input script, and will re-use
// this to lazily provision any new threads as needed.
//
// For each new thread that we spawn, a corresponding new ProxyResolver is
// created using ProxyResolverFactory.
//
// Because we are creating multiple ProxyResolver instances, this means we
// are duplicating script contexts for what is ordinarily seen as being a
// single script. This can affect compatibility on some classes of PAC
// script:
//
// (a) Scripts whose initialization has external dependencies on network or
// time may end up successfully initializing on some threads, but not
// others. So depending on what thread services the request, the result
// may jump between several possibilities.
//
// (b) Scripts whose FindProxyForURL() depends on side-effects may now
// work differently. For example, a PAC script which was incrementing
// a global counter and using that to make a decision. In the
// multi-threaded model, each thread may have a different value for this
// counter, so it won't globally be seen as monotonically increasing!
class MultiThreadedProxyResolver : public ProxyResolver, public NonThreadSafe {
public:
// Creates an asynchronous ProxyResolver that runs requests on up to
// |max_num_threads|.
//
// For each thread that is created, an accompanying synchronous ProxyResolver
// will be provisioned using |resolver_factory|. All methods on these
// ProxyResolvers will be called on the one thread, with the exception of
// ProxyResolver::Shutdown() which will be called from the origin thread
// prior to destruction.
//
// The constructor takes ownership of |resolver_factory|.
MultiThreadedProxyResolver(ProxyResolverFactory* resolver_factory,
size_t max_num_threads);
virtual ~MultiThreadedProxyResolver();
// ProxyResolver implementation:
virtual int GetProxyForURL(const GURL& url,
ProxyInfo* results,
CompletionCallback* callback,
RequestHandle* request,
const BoundNetLog& net_log);
virtual void CancelRequest(RequestHandle request);
virtual void CancelSetPacScript();
virtual void PurgeMemory();
virtual int SetPacScript(
const scoped_refptr<ProxyResolverScriptData>& script_data,
CompletionCallback* callback);
private:
class Executor;
class Job;
class SetPacScriptJob;
class GetProxyForURLJob;
// FIFO queue of pending jobs waiting to be started.
// TODO(eroman): Make this priority queue.
typedef std::deque<scoped_refptr<Job> > PendingJobsQueue;
typedef std::vector<scoped_refptr<Executor> > ExecutorList;
// Asserts that there are no outstanding user-initiated jobs on any of the
// worker threads.
void CheckNoOutstandingUserRequests() const;
// Stops and deletes all of the worker threads.
void ReleaseAllExecutors();
// Returns an idle worker thread which is ready to receive GetProxyForURL()
// requests. If all threads are occupied, returns NULL.
Executor* FindIdleExecutor();
// Creates a new worker thread, and appends it to |executors_|.
Executor* AddNewExecutor();
// Starts the next job from |pending_jobs_| if possible.
void OnExecutorReady(Executor* executor);
const scoped_ptr<ProxyResolverFactory> resolver_factory_;
const size_t max_num_threads_;
PendingJobsQueue pending_jobs_;
ExecutorList executors_;
scoped_refptr<ProxyResolverScriptData> current_script_data_;
};
} // namespace net
#endif // NET_PROXY_MULTI_THREADED_PROXY_RESOLVER_H_
|