OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "net/proxy/multi_threaded_proxy_resolver.h" | 5 #include "net/proxy/multi_threaded_proxy_resolver.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
13 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
14 #include "base/threading/thread_restrictions.h" | 14 #include "base/threading/thread_restrictions.h" |
15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
16 #include "net/base/net_log.h" | 16 #include "net/base/net_log.h" |
17 #include "net/proxy/proxy_info.h" | 17 #include "net/proxy/proxy_info.h" |
18 | 18 |
19 // TODO(eroman): Have the MultiThreadedProxyResolver clear its PAC script | 19 // TODO(eroman): Have the MultiThreadedProxyResolver clear its PAC script |
20 // data when SetPacScript fails. That will reclaim memory when | 20 // data when SetPacScript fails. That will reclaim memory when |
21 // testing bogus scripts. | 21 // testing bogus scripts. |
22 | 22 |
23 namespace net { | 23 namespace net { |
24 | 24 |
25 // An "executor" is a job-runner for PAC requests. It encapsulates a worker | 25 // An "executor" is a job-runner for PAC requests. It encapsulates a worker |
26 // thread and a synchronous ProxyResolver (which will be operated on said | 26 // thread and a synchronous ProxyResolver (which will be operated on said |
27 // thread.) | 27 // thread.) |
28 class MultiThreadedProxyResolver::Executor | 28 class MultiThreadedProxyResolver::Executor |
29 : public base::RefCountedThreadSafe<MultiThreadedProxyResolver::Executor > { | 29 : public base::RefCountedThreadSafe<MultiThreadedProxyResolver::Executor> { |
30 public: | 30 public: |
31 // |coordinator| must remain valid throughout our lifetime. It is used to | 31 // |coordinator| must remain valid throughout our lifetime. It is used to |
32 // signal when the executor is ready to receive work by calling | 32 // signal when the executor is ready to receive work by calling |
33 // |coordinator->OnExecutorReady()|. | 33 // |coordinator->OnExecutorReady()|. |
34 // The constructor takes ownership of |resolver|. | 34 // The constructor takes ownership of |resolver|. |
35 // |thread_number| is an identifier used when naming the worker thread. | 35 // |thread_number| is an identifier used when naming the worker thread. |
36 Executor(MultiThreadedProxyResolver* coordinator, | 36 Executor(MultiThreadedProxyResolver* coordinator, |
37 ProxyResolver* resolver, | 37 ProxyResolver* resolver, |
38 int thread_number); | 38 int thread_number); |
39 | 39 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 enum Type { | 84 enum Type { |
85 TYPE_GET_PROXY_FOR_URL, | 85 TYPE_GET_PROXY_FOR_URL, |
86 TYPE_SET_PAC_SCRIPT, | 86 TYPE_SET_PAC_SCRIPT, |
87 TYPE_SET_PAC_SCRIPT_INTERNAL, | 87 TYPE_SET_PAC_SCRIPT_INTERNAL, |
88 }; | 88 }; |
89 | 89 |
90 Job(Type type, const CompletionCallback& callback) | 90 Job(Type type, const CompletionCallback& callback) |
91 : type_(type), | 91 : type_(type), |
92 callback_(callback), | 92 callback_(callback), |
93 executor_(NULL), | 93 executor_(NULL), |
94 was_cancelled_(false) { | 94 was_cancelled_(false) {} |
95 } | |
96 | 95 |
97 void set_executor(Executor* executor) { | 96 void set_executor(Executor* executor) { executor_ = executor; } |
98 executor_ = executor; | |
99 } | |
100 | 97 |
101 // The "executor" is the job runner that is scheduling this job. If | 98 // The "executor" is the job runner that is scheduling this job. If |
102 // this job has not been submitted to an executor yet, this will be | 99 // this job has not been submitted to an executor yet, this will be |
103 // NULL (and we know it hasn't started yet). | 100 // NULL (and we know it hasn't started yet). |
104 Executor* executor() { | 101 Executor* executor() { return executor_; } |
105 return executor_; | |
106 } | |
107 | 102 |
108 // Mark the job as having been cancelled. | 103 // Mark the job as having been cancelled. |
109 void Cancel() { | 104 void Cancel() { was_cancelled_ = true; } |
110 was_cancelled_ = true; | |
111 } | |
112 | 105 |
113 // Returns true if Cancel() has been called. | 106 // Returns true if Cancel() has been called. |
114 bool was_cancelled() const { return was_cancelled_; } | 107 bool was_cancelled() const { return was_cancelled_; } |
115 | 108 |
116 Type type() const { return type_; } | 109 Type type() const { return type_; } |
117 | 110 |
118 // Returns true if this job still has a user callback. Some jobs | 111 // Returns true if this job still has a user callback. Some jobs |
119 // do not have a user callback, because they were helper jobs | 112 // do not have a user callback, because they were helper jobs |
120 // scheduled internally (for example TYPE_SET_PAC_SCRIPT_INTERNAL). | 113 // scheduled internally (for example TYPE_SET_PAC_SCRIPT_INTERNAL). |
121 // | 114 // |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 }; | 155 }; |
163 | 156 |
164 // MultiThreadedProxyResolver::SetPacScriptJob --------------------------------- | 157 // MultiThreadedProxyResolver::SetPacScriptJob --------------------------------- |
165 | 158 |
166 // Runs on the worker thread to call ProxyResolver::SetPacScript. | 159 // Runs on the worker thread to call ProxyResolver::SetPacScript. |
167 class MultiThreadedProxyResolver::SetPacScriptJob | 160 class MultiThreadedProxyResolver::SetPacScriptJob |
168 : public MultiThreadedProxyResolver::Job { | 161 : public MultiThreadedProxyResolver::Job { |
169 public: | 162 public: |
170 SetPacScriptJob(const scoped_refptr<ProxyResolverScriptData>& script_data, | 163 SetPacScriptJob(const scoped_refptr<ProxyResolverScriptData>& script_data, |
171 const CompletionCallback& callback) | 164 const CompletionCallback& callback) |
172 : Job(!callback.is_null() ? TYPE_SET_PAC_SCRIPT : | 165 : Job(!callback.is_null() ? TYPE_SET_PAC_SCRIPT |
173 TYPE_SET_PAC_SCRIPT_INTERNAL, | 166 : TYPE_SET_PAC_SCRIPT_INTERNAL, |
174 callback), | 167 callback), |
175 script_data_(script_data) { | 168 script_data_(script_data) {} |
176 } | |
177 | 169 |
178 // Runs on the worker thread. | 170 // Runs on the worker thread. |
179 virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { | 171 virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { |
180 ProxyResolver* resolver = executor()->resolver(); | 172 ProxyResolver* resolver = executor()->resolver(); |
181 int rv = resolver->SetPacScript(script_data_, CompletionCallback()); | 173 int rv = resolver->SetPacScript(script_data_, CompletionCallback()); |
182 | 174 |
183 DCHECK_NE(rv, ERR_IO_PENDING); | 175 DCHECK_NE(rv, ERR_IO_PENDING); |
184 origin_loop->PostTask( | 176 origin_loop->PostTask( |
185 FROM_HERE, | 177 FROM_HERE, base::Bind(&SetPacScriptJob::RequestComplete, this, rv)); |
186 base::Bind(&SetPacScriptJob::RequestComplete, this, rv)); | |
187 } | 178 } |
188 | 179 |
189 protected: | 180 protected: |
190 virtual ~SetPacScriptJob() {} | 181 virtual ~SetPacScriptJob() {} |
191 | 182 |
192 private: | 183 private: |
193 // Runs the completion callback on the origin thread. | 184 // Runs the completion callback on the origin thread. |
194 void RequestComplete(int result_code) { | 185 void RequestComplete(int result_code) { |
195 // The task may have been cancelled after it was started. | 186 // The task may have been cancelled after it was started. |
196 if (!was_cancelled() && has_user_callback()) { | 187 if (!was_cancelled() && has_user_callback()) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 } | 235 } |
245 | 236 |
246 // Runs on the worker thread. | 237 // Runs on the worker thread. |
247 virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { | 238 virtual void Run(scoped_refptr<base::MessageLoopProxy> origin_loop) OVERRIDE { |
248 ProxyResolver* resolver = executor()->resolver(); | 239 ProxyResolver* resolver = executor()->resolver(); |
249 int rv = resolver->GetProxyForURL( | 240 int rv = resolver->GetProxyForURL( |
250 url_, &results_buf_, CompletionCallback(), NULL, net_log_); | 241 url_, &results_buf_, CompletionCallback(), NULL, net_log_); |
251 DCHECK_NE(rv, ERR_IO_PENDING); | 242 DCHECK_NE(rv, ERR_IO_PENDING); |
252 | 243 |
253 origin_loop->PostTask( | 244 origin_loop->PostTask( |
254 FROM_HERE, | 245 FROM_HERE, base::Bind(&GetProxyForURLJob::QueryComplete, this, rv)); |
255 base::Bind(&GetProxyForURLJob::QueryComplete, this, rv)); | |
256 } | 246 } |
257 | 247 |
258 protected: | 248 protected: |
259 virtual ~GetProxyForURLJob() {} | 249 virtual ~GetProxyForURLJob() {} |
260 | 250 |
261 private: | 251 private: |
262 // Runs the completion callback on the origin thread. | 252 // Runs the completion callback on the origin thread. |
263 void QueryComplete(int result_code) { | 253 void QueryComplete(int result_code) { |
264 // The Job may have been cancelled after it was started. | 254 // The Job may have been cancelled after it was started. |
265 if (!was_cancelled()) { | 255 if (!was_cancelled()) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 MultiThreadedProxyResolver::Executor::Executor( | 297 MultiThreadedProxyResolver::Executor::Executor( |
308 MultiThreadedProxyResolver* coordinator, | 298 MultiThreadedProxyResolver* coordinator, |
309 ProxyResolver* resolver, | 299 ProxyResolver* resolver, |
310 int thread_number) | 300 int thread_number) |
311 : coordinator_(coordinator), | 301 : coordinator_(coordinator), |
312 thread_number_(thread_number), | 302 thread_number_(thread_number), |
313 resolver_(resolver) { | 303 resolver_(resolver) { |
314 DCHECK(coordinator); | 304 DCHECK(coordinator); |
315 DCHECK(resolver); | 305 DCHECK(resolver); |
316 // Start up the thread. | 306 // Start up the thread. |
317 thread_.reset(new base::Thread(base::StringPrintf("PAC thread #%d", | 307 thread_.reset( |
318 thread_number))); | 308 new base::Thread(base::StringPrintf("PAC thread #%d", thread_number))); |
319 CHECK(thread_->Start()); | 309 CHECK(thread_->Start()); |
320 } | 310 } |
321 | 311 |
322 void MultiThreadedProxyResolver::Executor::StartJob(Job* job) { | 312 void MultiThreadedProxyResolver::Executor::StartJob(Job* job) { |
323 DCHECK(!outstanding_job_.get()); | 313 DCHECK(!outstanding_job_.get()); |
324 outstanding_job_ = job; | 314 outstanding_job_ = job; |
325 | 315 |
326 // Run the job. Once it has completed (regardless of whether it was | 316 // Run the job. Once it has completed (regardless of whether it was |
327 // cancelled), it will invoke OnJobCompleted() on this thread. | 317 // cancelled), it will invoke OnJobCompleted() on this thread. |
328 job->set_executor(this); | 318 job->set_executor(this); |
329 job->FinishedWaitingForThread(); | 319 job->FinishedWaitingForThread(); |
330 thread_->message_loop()->PostTask( | 320 thread_->message_loop()->PostTask( |
331 FROM_HERE, | 321 FROM_HERE, base::Bind(&Job::Run, job, base::MessageLoopProxy::current())); |
332 base::Bind(&Job::Run, job, base::MessageLoopProxy::current())); | |
333 } | 322 } |
334 | 323 |
335 void MultiThreadedProxyResolver::Executor::OnJobCompleted(Job* job) { | 324 void MultiThreadedProxyResolver::Executor::OnJobCompleted(Job* job) { |
336 DCHECK_EQ(job, outstanding_job_.get()); | 325 DCHECK_EQ(job, outstanding_job_.get()); |
337 outstanding_job_ = NULL; | 326 outstanding_job_ = NULL; |
338 coordinator_->OnExecutorReady(this); | 327 coordinator_->OnExecutorReady(this); |
339 } | 328 } |
340 | 329 |
341 void MultiThreadedProxyResolver::Executor::Destroy() { | 330 void MultiThreadedProxyResolver::Executor::Destroy() { |
342 DCHECK(coordinator_); | 331 DCHECK(coordinator_); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 DCHECK_GE(max_num_threads, 1u); | 374 DCHECK_GE(max_num_threads, 1u); |
386 } | 375 } |
387 | 376 |
388 MultiThreadedProxyResolver::~MultiThreadedProxyResolver() { | 377 MultiThreadedProxyResolver::~MultiThreadedProxyResolver() { |
389 // We will cancel all outstanding requests. | 378 // We will cancel all outstanding requests. |
390 pending_jobs_.clear(); | 379 pending_jobs_.clear(); |
391 ReleaseAllExecutors(); | 380 ReleaseAllExecutors(); |
392 } | 381 } |
393 | 382 |
394 int MultiThreadedProxyResolver::GetProxyForURL( | 383 int MultiThreadedProxyResolver::GetProxyForURL( |
395 const GURL& url, ProxyInfo* results, const CompletionCallback& callback, | 384 const GURL& url, |
396 RequestHandle* request, const BoundNetLog& net_log) { | 385 ProxyInfo* results, |
| 386 const CompletionCallback& callback, |
| 387 RequestHandle* request, |
| 388 const BoundNetLog& net_log) { |
397 DCHECK(CalledOnValidThread()); | 389 DCHECK(CalledOnValidThread()); |
398 DCHECK(!callback.is_null()); | 390 DCHECK(!callback.is_null()); |
399 DCHECK(current_script_data_.get()) | 391 DCHECK(current_script_data_.get()) |
400 << "Resolver is un-initialized. Must call SetPacScript() first!"; | 392 << "Resolver is un-initialized. Must call SetPacScript() first!"; |
401 | 393 |
402 scoped_refptr<GetProxyForURLJob> job( | 394 scoped_refptr<GetProxyForURLJob> job( |
403 new GetProxyForURLJob(url, results, callback, net_log)); | 395 new GetProxyForURLJob(url, results, callback, net_log)); |
404 | 396 |
405 // Completion will be notified through |callback|, unless the caller cancels | 397 // Completion will be notified through |callback|, unless the caller cancels |
406 // the request using |request|. | 398 // the request using |request|. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 LoadState MultiThreadedProxyResolver::GetLoadState(RequestHandle req) const { | 446 LoadState MultiThreadedProxyResolver::GetLoadState(RequestHandle req) const { |
455 DCHECK(CalledOnValidThread()); | 447 DCHECK(CalledOnValidThread()); |
456 DCHECK(req); | 448 DCHECK(req); |
457 return LOAD_STATE_RESOLVING_PROXY_FOR_URL; | 449 return LOAD_STATE_RESOLVING_PROXY_FOR_URL; |
458 } | 450 } |
459 | 451 |
460 void MultiThreadedProxyResolver::CancelSetPacScript() { | 452 void MultiThreadedProxyResolver::CancelSetPacScript() { |
461 DCHECK(CalledOnValidThread()); | 453 DCHECK(CalledOnValidThread()); |
462 DCHECK_EQ(0u, pending_jobs_.size()); | 454 DCHECK_EQ(0u, pending_jobs_.size()); |
463 DCHECK_EQ(1u, executors_.size()); | 455 DCHECK_EQ(1u, executors_.size()); |
464 DCHECK_EQ(Job::TYPE_SET_PAC_SCRIPT, | 456 DCHECK_EQ(Job::TYPE_SET_PAC_SCRIPT, executors_[0]->outstanding_job()->type()); |
465 executors_[0]->outstanding_job()->type()); | |
466 | 457 |
467 // Defensively clear some data which shouldn't be getting used | 458 // Defensively clear some data which shouldn't be getting used |
468 // anymore. | 459 // anymore. |
469 current_script_data_ = NULL; | 460 current_script_data_ = NULL; |
470 | 461 |
471 ReleaseAllExecutors(); | 462 ReleaseAllExecutors(); |
472 } | 463 } |
473 | 464 |
474 int MultiThreadedProxyResolver::SetPacScript( | 465 int MultiThreadedProxyResolver::SetPacScript( |
475 const scoped_refptr<ProxyResolverScriptData>& script_data, | 466 const scoped_refptr<ProxyResolverScriptData>& script_data, |
476 const CompletionCallback&callback) { | 467 const CompletionCallback& callback) { |
477 DCHECK(CalledOnValidThread()); | 468 DCHECK(CalledOnValidThread()); |
478 DCHECK(!callback.is_null()); | 469 DCHECK(!callback.is_null()); |
479 | 470 |
480 // Save the script details, so we can provision new executors later. | 471 // Save the script details, so we can provision new executors later. |
481 current_script_data_ = script_data; | 472 current_script_data_ = script_data; |
482 | 473 |
483 // The user should not have any outstanding requests when they call | 474 // The user should not have any outstanding requests when they call |
484 // SetPacScript(). | 475 // SetPacScript(). |
485 CheckNoOutstandingUserRequests(); | 476 CheckNoOutstandingUserRequests(); |
486 | 477 |
487 // Destroy all of the current threads and their proxy resolvers. | 478 // Destroy all of the current threads and their proxy resolvers. |
488 ReleaseAllExecutors(); | 479 ReleaseAllExecutors(); |
489 | 480 |
490 // Provision a new executor, and run the SetPacScript request. On completion | 481 // Provision a new executor, and run the SetPacScript request. On completion |
491 // notification will be sent through |callback|. | 482 // notification will be sent through |callback|. |
492 Executor* executor = AddNewExecutor(); | 483 Executor* executor = AddNewExecutor(); |
493 executor->StartJob(new SetPacScriptJob(script_data, callback)); | 484 executor->StartJob(new SetPacScriptJob(script_data, callback)); |
494 return ERR_IO_PENDING; | 485 return ERR_IO_PENDING; |
495 } | 486 } |
496 | 487 |
497 void MultiThreadedProxyResolver::CheckNoOutstandingUserRequests() const { | 488 void MultiThreadedProxyResolver::CheckNoOutstandingUserRequests() const { |
498 DCHECK(CalledOnValidThread()); | 489 DCHECK(CalledOnValidThread()); |
499 CHECK_EQ(0u, pending_jobs_.size()); | 490 CHECK_EQ(0u, pending_jobs_.size()); |
500 | 491 |
501 for (ExecutorList::const_iterator it = executors_.begin(); | 492 for (ExecutorList::const_iterator it = executors_.begin(); |
502 it != executors_.end(); ++it) { | 493 it != executors_.end(); |
| 494 ++it) { |
503 const Executor* executor = it->get(); | 495 const Executor* executor = it->get(); |
504 Job* job = executor->outstanding_job(); | 496 Job* job = executor->outstanding_job(); |
505 // The "has_user_callback()" is to exclude jobs for which the callback | 497 // The "has_user_callback()" is to exclude jobs for which the callback |
506 // has already been invoked, or was not user-initiated (as in the case of | 498 // has already been invoked, or was not user-initiated (as in the case of |
507 // lazy thread provisions). User-initiated jobs may !has_user_callback() | 499 // lazy thread provisions). User-initiated jobs may !has_user_callback() |
508 // when the callback has already been run. (Since we only clear the | 500 // when the callback has already been run. (Since we only clear the |
509 // outstanding job AFTER the callback has been invoked, it is possible | 501 // outstanding job AFTER the callback has been invoked, it is possible |
510 // for a new request to be started from within the callback). | 502 // for a new request to be started from within the callback). |
511 CHECK(!job || job->was_cancelled() || !job->has_user_callback()); | 503 CHECK(!job || job->was_cancelled() || !job->has_user_callback()); |
512 } | 504 } |
513 } | 505 } |
514 | 506 |
515 void MultiThreadedProxyResolver::ReleaseAllExecutors() { | 507 void MultiThreadedProxyResolver::ReleaseAllExecutors() { |
516 DCHECK(CalledOnValidThread()); | 508 DCHECK(CalledOnValidThread()); |
517 for (ExecutorList::iterator it = executors_.begin(); | 509 for (ExecutorList::iterator it = executors_.begin(); it != executors_.end(); |
518 it != executors_.end(); ++it) { | 510 ++it) { |
519 Executor* executor = it->get(); | 511 Executor* executor = it->get(); |
520 executor->Destroy(); | 512 executor->Destroy(); |
521 } | 513 } |
522 executors_.clear(); | 514 executors_.clear(); |
523 } | 515 } |
524 | 516 |
525 MultiThreadedProxyResolver::Executor* | 517 MultiThreadedProxyResolver::Executor* |
526 MultiThreadedProxyResolver::FindIdleExecutor() { | 518 MultiThreadedProxyResolver::FindIdleExecutor() { |
527 DCHECK(CalledOnValidThread()); | 519 DCHECK(CalledOnValidThread()); |
528 for (ExecutorList::iterator it = executors_.begin(); | 520 for (ExecutorList::iterator it = executors_.begin(); it != executors_.end(); |
529 it != executors_.end(); ++it) { | 521 ++it) { |
530 Executor* executor = it->get(); | 522 Executor* executor = it->get(); |
531 if (!executor->outstanding_job()) | 523 if (!executor->outstanding_job()) |
532 return executor; | 524 return executor; |
533 } | 525 } |
534 return NULL; | 526 return NULL; |
535 } | 527 } |
536 | 528 |
537 MultiThreadedProxyResolver::Executor* | 529 MultiThreadedProxyResolver::Executor* |
538 MultiThreadedProxyResolver::AddNewExecutor() { | 530 MultiThreadedProxyResolver::AddNewExecutor() { |
539 DCHECK(CalledOnValidThread()); | 531 DCHECK(CalledOnValidThread()); |
540 DCHECK_LT(executors_.size(), max_num_threads_); | 532 DCHECK_LT(executors_.size(), max_num_threads_); |
541 // The "thread number" is used to give the thread a unique name. | 533 // The "thread number" is used to give the thread a unique name. |
542 int thread_number = executors_.size(); | 534 int thread_number = executors_.size(); |
543 ProxyResolver* resolver = resolver_factory_->CreateProxyResolver(); | 535 ProxyResolver* resolver = resolver_factory_->CreateProxyResolver(); |
544 Executor* executor = new Executor( | 536 Executor* executor = new Executor(this, resolver, thread_number); |
545 this, resolver, thread_number); | |
546 executors_.push_back(make_scoped_refptr(executor)); | 537 executors_.push_back(make_scoped_refptr(executor)); |
547 return executor; | 538 return executor; |
548 } | 539 } |
549 | 540 |
550 void MultiThreadedProxyResolver::OnExecutorReady(Executor* executor) { | 541 void MultiThreadedProxyResolver::OnExecutorReady(Executor* executor) { |
551 DCHECK(CalledOnValidThread()); | 542 DCHECK(CalledOnValidThread()); |
552 if (pending_jobs_.empty()) | 543 if (pending_jobs_.empty()) |
553 return; | 544 return; |
554 | 545 |
555 // Get the next job to process (FIFO). Transfer it from the pending queue | 546 // Get the next job to process (FIFO). Transfer it from the pending queue |
556 // to the executor. | 547 // to the executor. |
557 scoped_refptr<Job> job = pending_jobs_.front(); | 548 scoped_refptr<Job> job = pending_jobs_.front(); |
558 pending_jobs_.pop_front(); | 549 pending_jobs_.pop_front(); |
559 executor->StartJob(job.get()); | 550 executor->StartJob(job.get()); |
560 } | 551 } |
561 | 552 |
562 } // namespace net | 553 } // namespace net |
OLD | NEW |