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