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