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