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   DCHECK(loop_);
     23 }
     24 
     25 RunLoop::~RunLoop() {
     26 }
     27 
     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 
     43 void RunLoop::RunUntilIdle() {
     44   quit_when_idle_received_ = true;
     45   Run();
     46 }
     47 
     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 
     57 void RunLoop::QuitWhenIdle() {
     58   DCHECK(thread_checker_.CalledOnValidThread());
     59   quit_when_idle_received_ = true;
     60 }
     61 
     62 base::Closure RunLoop::QuitClosure() {
     63   return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
     64 }
     65 
     66 base::Closure RunLoop::QuitWhenIdleClosure() {
     67   return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
     68 }
     69 
     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 
     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