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