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