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 
     10 #if defined(OS_WIN)
     11 #include "base/message_loop/message_pump_dispatcher.h"
     12 #endif
     13 
     14 namespace base {
     15 
     16 RunLoop::RunLoop()
     17     : loop_(MessageLoop::current()),
     18       previous_run_loop_(NULL),
     19       run_depth_(0),
     20       run_called_(false),
     21       quit_called_(false),
     22       running_(false),
     23       quit_when_idle_received_(false),
     24       weak_factory_(this) {
     25 #if defined(OS_WIN)
     26    dispatcher_ = NULL;
     27 #endif
     28 }
     29 
     30 #if defined(OS_WIN)
     31 RunLoop::RunLoop(MessagePumpDispatcher* dispatcher)
     32     : loop_(MessageLoop::current()),
     33       previous_run_loop_(NULL),
     34       dispatcher_(dispatcher),
     35       run_depth_(0),
     36       run_called_(false),
     37       quit_called_(false),
     38       running_(false),
     39       quit_when_idle_received_(false),
     40       weak_factory_(this) {
     41 }
     42 #endif
     43 
     44 RunLoop::~RunLoop() {
     45 }
     46 
     47 void RunLoop::Run() {
     48   if (!BeforeRun())
     49     return;
     50 
     51   // Use task stopwatch to exclude the loop run time from the current task, if
     52   // any.
     53   tracked_objects::TaskStopwatch stopwatch;
     54   loop_->RunHandler();
     55   stopwatch.Stop();
     56 
     57   AfterRun();
     58 }
     59 
     60 void RunLoop::RunUntilIdle() {
     61   quit_when_idle_received_ = true;
     62   Run();
     63 }
     64 
     65 void RunLoop::Quit() {
     66   quit_called_ = true;
     67   if (running_ && loop_->run_loop_ == this) {
     68     // This is the inner-most RunLoop, so quit now.
     69     loop_->QuitNow();
     70   }
     71 }
     72 
     73 base::Closure RunLoop::QuitClosure() {
     74   return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
     75 }
     76 
     77 bool RunLoop::BeforeRun() {
     78   DCHECK(!run_called_);
     79   run_called_ = true;
     80 
     81   // Allow Quit to be called before Run.
     82   if (quit_called_)
     83     return false;
     84 
     85   // Push RunLoop stack:
     86   previous_run_loop_ = loop_->run_loop_;
     87   run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
     88   loop_->run_loop_ = this;
     89 
     90   running_ = true;
     91   return true;
     92 }
     93 
     94 void RunLoop::AfterRun() {
     95   running_ = false;
     96 
     97   // Pop RunLoop stack:
     98   loop_->run_loop_ = previous_run_loop_;
     99 
    100   // Execute deferred QuitNow, if any:
    101   if (previous_run_loop_ && previous_run_loop_->quit_called_)
    102     loop_->QuitNow();
    103 }
    104 
    105 }  // namespace base
    106