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