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 3 // found in the LICENSE file. 4 5 #include "base/run_loop.h" 6 7 #include "base/bind.h" 8 #include "base/tracked_objects.h" 9 #include "build/build_config.h" 10 11 namespace base { 12 13 RunLoop::RunLoop() 14 : loop_(MessageLoop::current()), 15 previous_run_loop_(NULL), 16 run_depth_(0), 17 run_called_(false), 18 quit_called_(false), 19 running_(false), 20 quit_when_idle_received_(false), 21 weak_factory_(this) { 22 DCHECK(loop_); 23 } 24 25 RunLoop::~RunLoop() { 26 } 27 28 void RunLoop::Run() { 29 DCHECK(thread_checker_.CalledOnValidThread()); 30 if (!BeforeRun()) 31 return; 32 33 // Use task stopwatch to exclude the loop run time from the current task, if 34 // any. 35 tracked_objects::TaskStopwatch stopwatch; 36 stopwatch.Start(); 37 loop_->RunHandler(); 38 stopwatch.Stop(); 39 40 AfterRun(); 41 } 42 43 void RunLoop::RunUntilIdle() { 44 quit_when_idle_received_ = true; 45 Run(); 46 } 47 48 void RunLoop::Quit() { 49 DCHECK(thread_checker_.CalledOnValidThread()); 50 quit_called_ = true; 51 if (running_ && loop_->run_loop_ == this) { 52 // This is the inner-most RunLoop, so quit now. 53 loop_->QuitNow(); 54 } 55 } 56 57 void RunLoop::QuitWhenIdle() { 58 DCHECK(thread_checker_.CalledOnValidThread()); 59 quit_when_idle_received_ = true; 60 } 61 62 base::Closure RunLoop::QuitClosure() { 63 return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); 64 } 65 66 base::Closure RunLoop::QuitWhenIdleClosure() { 67 return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); 68 } 69 70 bool RunLoop::BeforeRun() { 71 DCHECK(!run_called_); 72 run_called_ = true; 73 74 // Allow Quit to be called before Run. 75 if (quit_called_) 76 return false; 77 78 // Push RunLoop stack: 79 previous_run_loop_ = loop_->run_loop_; 80 run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1; 81 loop_->run_loop_ = this; 82 83 if (run_depth_ > 1) 84 loop_->NotifyBeginNestedLoop(); 85 86 running_ = true; 87 return true; 88 } 89 90 void RunLoop::AfterRun() { 91 running_ = false; 92 93 // Pop RunLoop stack: 94 loop_->run_loop_ = previous_run_loop_; 95 96 // Execute deferred QuitNow, if any: 97 if (previous_run_loop_ && previous_run_loop_->quit_called_) 98 loop_->QuitNow(); 99 } 100 101 } // namespace base 102