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 
RunLoop()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)
RunLoop(MessagePumpDispatcher * dispatcher)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 
~RunLoop()45 RunLoop::~RunLoop() {
46 }
47 
Run()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 
RunUntilIdle()62 void RunLoop::RunUntilIdle() {
63   quit_when_idle_received_ = true;
64   Run();
65 }
66 
Quit()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 
QuitClosure()75 base::Closure RunLoop::QuitClosure() {
76   return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
77 }
78 
BeforeRun()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 
AfterRun()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