Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1006)

Side by Side Diff: net/base/host_resolver_impl.cc

Issue 5710002: Create base::WorkerPoolJob. Use it for HostResolverImpl and DirectoryLister. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minimize the header dependency. Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/base/host_resolver_impl.h" 5 #include "net/base/host_resolver_impl.h"
6 6
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <Winsock2.h> 8 #include <Winsock2.h>
9 #elif defined(OS_POSIX) 9 #elif defined(OS_POSIX)
10 #include <netdb.h> 10 #include <netdb.h>
11 #endif 11 #endif
12 12
13 #include <cmath> 13 #include <cmath>
14 #include <deque> 14 #include <deque>
15 #include <vector> 15 #include <vector>
16 16
17 #include "base/basictypes.h" 17 #include "base/basictypes.h"
18 #include "base/compiler_specific.h" 18 #include "base/compiler_specific.h"
19 #include "base/debug/debugger.h" 19 #include "base/debug/debugger.h"
20 #include "base/debug/stack_trace.h" 20 #include "base/debug/stack_trace.h"
21 #include "base/lock.h" 21 #include "base/lock.h"
22 #include "base/message_loop.h" 22 #include "base/message_loop.h"
23 #include "base/metrics/field_trial.h" 23 #include "base/metrics/field_trial.h"
24 #include "base/metrics/histogram.h" 24 #include "base/metrics/histogram.h"
25 #include "base/stl_util-inl.h" 25 #include "base/stl_util-inl.h"
26 #include "base/string_util.h" 26 #include "base/string_util.h"
27 #include "base/time.h" 27 #include "base/time.h"
28 #include "base/utf_string_conversions.h" 28 #include "base/utf_string_conversions.h"
29 #include "base/values.h" 29 #include "base/values.h"
30 #include "base/worker_pool.h" 30 #include "base/worker_pool_job.h"
31 #include "net/base/address_list.h" 31 #include "net/base/address_list.h"
32 #include "net/base/address_list_net_log_param.h" 32 #include "net/base/address_list_net_log_param.h"
33 #include "net/base/host_port_pair.h" 33 #include "net/base/host_port_pair.h"
34 #include "net/base/host_resolver_proc.h" 34 #include "net/base/host_resolver_proc.h"
35 #include "net/base/net_errors.h" 35 #include "net/base/net_errors.h"
36 #include "net/base/net_log.h" 36 #include "net/base/net_log.h"
37 #include "net/base/net_util.h" 37 #include "net/base/net_util.h"
38 38
39 #if defined(OS_WIN) 39 #if defined(OS_WIN)
40 #include "net/base/winsock_init.h" 40 #include "net/base/winsock_init.h"
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 331
332 //------------------------------------------------------------------------------ 332 //------------------------------------------------------------------------------
333 333
334 // Provide a common macro to simplify code and readability. We must use a 334 // Provide a common macro to simplify code and readability. We must use a
335 // macros as the underlying HISTOGRAM macro creates static varibles. 335 // macros as the underlying HISTOGRAM macro creates static varibles.
336 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 336 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
337 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100) 337 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
338 338
339 // This class represents a request to the worker pool for a "getaddrinfo()" 339 // This class represents a request to the worker pool for a "getaddrinfo()"
340 // call. 340 // call.
341 class HostResolverImpl::Job 341 class HostResolverImpl::Job : public base::WorkerPoolJob {
342 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
343 public: 342 public:
344 Job(int id, 343 Job(int id,
345 HostResolverImpl* resolver, 344 HostResolverImpl* resolver,
346 const Key& key, 345 const Key& key,
347 const BoundNetLog& source_net_log, 346 const BoundNetLog& source_net_log,
348 NetLog* net_log) 347 NetLog* net_log)
349 : id_(id), 348 : WorkerPoolJob(true),
349 id_(id),
350 key_(key), 350 key_(key),
351 resolver_(resolver), 351 resolver_(resolver),
352 origin_loop_(MessageLoop::current()),
353 resolver_proc_(resolver->effective_resolver_proc()), 352 resolver_proc_(resolver->effective_resolver_proc()),
354 error_(OK), 353 error_(OK),
355 os_error_(0), 354 os_error_(0),
356 had_non_speculative_request_(false), 355 had_non_speculative_request_(false),
357 net_log_(BoundNetLog::Make(net_log, 356 net_log_(BoundNetLog::Make(net_log,
358 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { 357 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
359 net_log_.BeginEvent( 358 net_log_.BeginEvent(
360 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 359 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
361 make_scoped_refptr( 360 make_scoped_refptr(
362 new JobCreationParameters(key.hostname, source_net_log.source()))); 361 new JobCreationParameters(key.hostname, source_net_log.source())));
(...skipping 11 matching lines...) Expand all
374 requests_.push_back(req); 373 requests_.push_back(req);
375 374
376 if (!req->info().is_speculative()) 375 if (!req->info().is_speculative())
377 had_non_speculative_request_ = true; 376 had_non_speculative_request_ = true;
378 } 377 }
379 378
380 // Called from origin loop. 379 // Called from origin loop.
381 void Start() { 380 void Start() {
382 start_time_ = base::TimeTicks::Now(); 381 start_time_ = base::TimeTicks::Now();
383 382
384 // Dispatch the job to a worker thread. 383 StartJob();
385 if (!WorkerPool::PostTask(FROM_HERE,
386 NewRunnableMethod(this, &Job::DoLookup), true)) {
387 NOTREACHED();
388
389 // Since we could be running within Resolve() right now, we can't just
390 // call OnLookupComplete(). Instead we must wait until Resolve() has
391 // returned (IO_PENDING).
392 error_ = ERR_UNEXPECTED;
393 MessageLoop::current()->PostTask(
394 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
395 }
396 } 384 }
397 385
398 // Cancels the current job. Callable from origin thread. 386 // Cancels the current job. Callable from origin thread.
399 void Cancel() { 387 void Cancel() {
388 if (canceled())
389 return;
390
391 CancelJob();
392
400 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); 393 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
401 394
402 HostResolver* resolver = resolver_;
403 resolver_ = NULL;
404
405 // Mark the job as cancelled, so when worker thread completes it will
406 // not try to post completion to origin loop.
407 {
408 AutoLock locked(origin_loop_lock_);
409 origin_loop_ = NULL;
410 }
411
412 // End here to prevent issues when a Job outlives the HostResolver that 395 // End here to prevent issues when a Job outlives the HostResolver that
413 // spawned it. 396 // spawned it.
414 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL); 397 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
415 398
416 // We will call HostResolverImpl::CancelRequest(Request*) on each one 399 // We will call HostResolverImpl::CancelRequest(Request*) on each one
417 // in order to notify any observers. 400 // in order to notify any observers.
418 for (RequestsList::const_iterator it = requests_.begin(); 401 for (RequestsList::const_iterator it = requests_.begin();
419 it != requests_.end(); ++it) { 402 it != requests_.end(); ++it) {
420 HostResolverImpl::Request* req = *it; 403 HostResolverImpl::Request* req = *it;
421 if (!req->was_cancelled()) 404 if (!req->was_cancelled())
422 resolver->CancelRequest(req); 405 resolver_->CancelRequest(req);
423 } 406 }
424 } 407 }
425 408
426 // Called from origin thread. 409 // Called from origin thread.
427 bool was_cancelled() const {
428 return resolver_ == NULL;
429 }
430
431 // Called from origin thread.
432 const Key& key() const { 410 const Key& key() const {
433 return key_; 411 return key_;
434 } 412 }
435 413
436 int id() const { 414 int id() const {
437 return id_; 415 return id_;
438 } 416 }
439 417
440 base::TimeTicks start_time() const { 418 base::TimeTicks start_time() const {
441 return start_time_; 419 return start_time_;
442 } 420 }
443 421
444 // Called from origin thread. 422 // Called from origin thread.
445 const RequestsList& requests() const { 423 const RequestsList& requests() const {
446 return requests_; 424 return requests_;
447 } 425 }
448 426
449 // Returns the first request attached to the job. 427 // Returns the first request attached to the job.
450 const Request* initial_request() const { 428 const Request* initial_request() const {
451 DCHECK_EQ(origin_loop_, MessageLoop::current());
452 DCHECK(!requests_.empty()); 429 DCHECK(!requests_.empty());
453 return requests_[0]; 430 return requests_[0];
454 } 431 }
455 432
456 // Returns true if |req_info| can be fulfilled by this job. 433 // Returns true if |req_info| can be fulfilled by this job.
457 bool CanServiceRequest(const RequestInfo& req_info) const { 434 bool CanServiceRequest(const RequestInfo& req_info) const {
458 return key_ == resolver_->GetEffectiveKeyForRequest(req_info); 435 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
459 } 436 }
460 437
438 // TODO(willchan): Eliminate the need for this.
439 using WorkerPoolJob::canceled;
440
461 private: 441 private:
462 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>; 442 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
463 443
464 ~Job() { 444 ~Job() {
465 // Free the requests attached to this job. 445 // Free the requests attached to this job.
466 STLDeleteElements(&requests_); 446 STLDeleteElements(&requests_);
467 } 447 }
468 448
469 // WARNING: This code runs inside a worker pool. The shutdown code cannot 449 // WARNING: This code runs inside a worker pool. The shutdown code cannot
470 // wait for it to finish, so we must be very careful here about using other 450 // wait for it to finish, so we must be very careful here about using other
471 // objects (like MessageLoops, Singletons, etc). During shutdown these objects 451 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
472 // may no longer exist. 452 // may no longer exist.
473 void DoLookup() { 453 virtual void RunJob() {
474 // Running on the worker thread 454 // Running on the worker thread
475 error_ = ResolveAddrInfo(resolver_proc_, 455 error_ = ResolveAddrInfo(resolver_proc_,
476 key_.hostname, 456 key_.hostname,
477 key_.address_family, 457 key_.address_family,
478 key_.host_resolver_flags, 458 key_.host_resolver_flags,
479 &results_, 459 &results_,
480 &os_error_); 460 &os_error_);
481
482 // The origin loop could go away while we are trying to post to it, so we
483 // need to call its PostTask method inside a lock. See ~HostResolver.
484 {
485 AutoLock locked(origin_loop_lock_);
486 if (origin_loop_) {
487 origin_loop_->PostTask(FROM_HERE,
488 NewRunnableMethod(this, &Job::OnLookupComplete));
489 }
490 }
491 } 461 }
492 462
493 // Callback for when DoLookup() completes (runs on origin thread). 463 // Callback for when RunJob() completes (runs on origin thread).
494 void OnLookupComplete() { 464 virtual void CompleteJob() {
495 // Should be running on origin loop.
496 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
497 // because MessageLoop::current() == NULL.
498 //DCHECK_EQ(origin_loop_, MessageLoop::current());
499 DCHECK(error_ || results_.head()); 465 DCHECK(error_ || results_.head());
500 466
501 // Ideally the following code would be part of host_resolver_proc.cc, 467 // Ideally the following code would be part of host_resolver_proc.cc,
502 // however it isn't safe to call NetworkChangeNotifier from worker 468 // however it isn't safe to call NetworkChangeNotifier from worker
503 // threads. So we do it here on the IO thread instead. 469 // threads. So we do it here on the IO thread instead.
504 if (error_ != OK && NetworkChangeNotifier::IsOffline()) 470 if (error_ != OK && NetworkChangeNotifier::IsOffline())
505 error_ = ERR_INTERNET_DISCONNECTED; 471 error_ = ERR_INTERNET_DISCONNECTED;
506 472
507 RecordPerformanceHistograms(); 473 RecordPerformanceHistograms();
508 474
509 if (was_cancelled())
510 return;
511
512 scoped_refptr<NetLog::EventParameters> params; 475 scoped_refptr<NetLog::EventParameters> params;
513 if (error_ != OK) { 476 if (error_ != OK) {
514 params = new HostResolveFailedParams(error_, os_error_); 477 params = new HostResolveFailedParams(error_, os_error_);
515 } else { 478 } else {
516 params = new AddressListNetLogParam(results_); 479 params = new AddressListNetLogParam(results_);
517 } 480 }
518 481
519 // End here to prevent issues when a Job outlives the HostResolver that 482 // End here to prevent issues when a Job outlives the HostResolver that
520 // spawned it. 483 // spawned it.
521 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params); 484 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 UMA_HISTOGRAM_ENUMERATION( 546 UMA_HISTOGRAM_ENUMERATION(
584 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"), 547 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
585 category, RESOLVE_MAX); 548 category, RESOLVE_MAX);
586 if (RESOLVE_SUCCESS == category) { 549 if (RESOLVE_SUCCESS == category) {
587 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess", 550 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
588 "DnsParallelism"), duration); 551 "DnsParallelism"), duration);
589 } 552 }
590 } 553 }
591 } 554 }
592 555
593
594
595 // Immutable. Can be read from either thread, 556 // Immutable. Can be read from either thread,
596 const int id_; 557 const int id_;
597 558
598 // Set on the origin thread, read on the worker thread. 559 // Set on the origin thread, read on the worker thread.
599 Key key_; 560 Key key_;
600 561
601 // Only used on the origin thread (where Resolve was called). 562 // Only used on the origin thread (where Resolve was called).
602 HostResolverImpl* resolver_; 563 HostResolverImpl* resolver_;
603 RequestsList requests_; // The requests waiting on this job. 564 RequestsList requests_; // The requests waiting on this job.
604 565
605 // Used to post ourselves onto the origin thread.
606 Lock origin_loop_lock_;
607 MessageLoop* origin_loop_;
608
609 // Hold an owning reference to the HostResolverProc that we are going to use. 566 // Hold an owning reference to the HostResolverProc that we are going to use.
610 // This may not be the current resolver procedure by the time we call 567 // This may not be the current resolver procedure by the time we call
611 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning 568 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
612 // reference ensures that it remains valid until we are done. 569 // reference ensures that it remains valid until we are done.
613 scoped_refptr<HostResolverProc> resolver_proc_; 570 scoped_refptr<HostResolverProc> resolver_proc_;
614 571
615 // Assigned on the worker thread, read on the origin thread. 572 // Assigned on the worker thread, read on the origin thread.
616 int error_; 573 int error_;
617 int os_error_; 574 int os_error_;
618 575
(...skipping 10 matching lines...) Expand all
629 586
630 BoundNetLog net_log_; 587 BoundNetLog net_log_;
631 588
632 DISALLOW_COPY_AND_ASSIGN(Job); 589 DISALLOW_COPY_AND_ASSIGN(Job);
633 }; 590 };
634 591
635 //----------------------------------------------------------------------------- 592 //-----------------------------------------------------------------------------
636 593
637 // This class represents a request to the worker pool for a "probe for IPv6 594 // This class represents a request to the worker pool for a "probe for IPv6
638 // support" call. 595 // support" call.
639 class HostResolverImpl::IPv6ProbeJob 596 class HostResolverImpl::IPv6ProbeJob : public base::WorkerPoolJob {
640 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
641 public: 597 public:
642 explicit IPv6ProbeJob(HostResolverImpl* resolver) 598 explicit IPv6ProbeJob(HostResolverImpl* resolver)
643 : resolver_(resolver), 599 : WorkerPoolJob(true),
644 origin_loop_(MessageLoop::current()) { 600 resolver_(resolver),
645 DCHECK(!was_cancelled()); 601 address_family_(ADDRESS_FAMILY_UNSPECIFIED) {
602 DCHECK(resolver_);
646 } 603 }
647 604
648 void Start() { 605 void Start() { StartJob(); }
649 if (was_cancelled()) 606 void Cancel() { CancelJob(); }
650 return;
651 DCHECK(IsOnOriginThread());
652 const bool kIsSlow = true;
653 WorkerPool::PostTask(
654 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
655 }
656
657 // Cancels the current job.
658 void Cancel() {
659 if (was_cancelled())
660 return;
661 DCHECK(IsOnOriginThread());
662 resolver_ = NULL; // Read/write ONLY on origin thread.
663 {
664 AutoLock locked(origin_loop_lock_);
665 // Origin loop may be destroyed before we can use it!
666 origin_loop_ = NULL; // Write ONLY on origin thread.
667 }
668 }
669 607
670 private: 608 private:
671 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>; 609 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
672 610
673 ~IPv6ProbeJob() { 611 ~IPv6ProbeJob() {
674 } 612 }
675 613
676 // Should be run on |orgin_thread_|, but that may not be well defined now.
677 bool was_cancelled() const {
678 if (!resolver_ || !origin_loop_) {
679 DCHECK(!resolver_);
680 DCHECK(!origin_loop_);
681 return true;
682 }
683 return false;
684 }
685
686 // Run on worker thread. 614 // Run on worker thread.
687 void DoProbe() { 615 virtual void RunJob() {
688 // Do actual testing on this thread, as it takes 40-100ms. 616 // Do actual testing on this thread, as it takes 40-100ms.
689 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED 617 address_family_ = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
690 : ADDRESS_FAMILY_IPV4; 618 : ADDRESS_FAMILY_IPV4;
691
692 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
693 family);
694
695 // The origin loop could go away while we are trying to post to it, so we
696 // need to call its PostTask method inside a lock. See ~HostResolver.
697 {
698 AutoLock locked(origin_loop_lock_);
699 if (origin_loop_) {
700 origin_loop_->PostTask(FROM_HERE, reply);
701 return;
702 }
703 }
704
705 // We didn't post, so delete the reply.
706 delete reply;
707 } 619 }
708 620
709 // Callback for when DoProbe() completes (runs on origin thread). 621 // Callback for when DoProbe() completes (runs on origin thread).
710 void OnProbeComplete(AddressFamily address_family) { 622 virtual void CompleteJob() {
711 if (was_cancelled()) 623 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family_);
712 return;
713 DCHECK(IsOnOriginThread());
714 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
715 }
716
717 bool IsOnOriginThread() const {
718 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
719 } 624 }
720 625
721 // Used/set only on origin thread. 626 // Used/set only on origin thread.
722 HostResolverImpl* resolver_; 627 HostResolverImpl* const resolver_;
723 628
724 // Used to post ourselves onto the origin thread. 629 AddressFamily address_family_;
725 Lock origin_loop_lock_;
726 MessageLoop* origin_loop_;
727 630
728 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob); 631 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
729 }; 632 };
730 633
731 //----------------------------------------------------------------------------- 634 //-----------------------------------------------------------------------------
732 635
733 // We rely on the priority enum values being sequential having starting at 0, 636 // We rely on the priority enum values being sequential having starting at 0,
734 // and increasing for lower priorities. 637 // and increasing for lower priorities.
735 COMPILE_ASSERT(HIGHEST == 0u && 638 COMPILE_ASSERT(HIGHEST == 0u &&
736 LOWEST > HIGHEST && 639 LOWEST > HIGHEST &&
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after
1219 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL); 1122 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
1220 1123
1221 // Update the net log and notify registered observers. 1124 // Update the net log and notify registered observers.
1222 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(), 1125 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1223 req->info(), net_error, os_error); 1126 req->info(), net_error, os_error);
1224 1127
1225 req->OnComplete(net_error, addrlist); 1128 req->OnComplete(net_error, addrlist);
1226 1129
1227 // Check if the job was cancelled as a result of running the callback. 1130 // Check if the job was cancelled as a result of running the callback.
1228 // (Meaning that |this| was deleted). 1131 // (Meaning that |this| was deleted).
1229 if (job->was_cancelled()) 1132 if (job->canceled())
1230 return; 1133 return;
1231 } 1134 }
1232 } 1135 }
1233 1136
1234 cur_completing_job_ = NULL; 1137 cur_completing_job_ = NULL;
1235 } 1138 }
1236 1139
1237 void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log, 1140 void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1238 const BoundNetLog& request_net_log, 1141 const BoundNetLog& request_net_log,
1239 int request_id, 1142 int request_id,
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
1448 job_pools_[i]->ResetNumOutstandingJobs(); 1351 job_pools_[i]->ResetNumOutstandingJobs();
1449 JobMap jobs; 1352 JobMap jobs;
1450 jobs.swap(jobs_); 1353 jobs.swap(jobs_);
1451 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) { 1354 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1452 AbortJob(it->second); 1355 AbortJob(it->second);
1453 it->second->Cancel(); 1356 it->second->Cancel();
1454 } 1357 }
1455 } 1358 }
1456 1359
1457 } // namespace net 1360 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698