Home | History | Annotate | Download | only in disk_cache
      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 "net/disk_cache/in_flight_io.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/logging.h"
     10 #include "base/threading/thread_restrictions.h"
     11 
     12 namespace disk_cache {
     13 
     14 BackgroundIO::BackgroundIO(InFlightIO* controller)
     15     : result_(-1), io_completed_(true, false), controller_(controller) {
     16 }
     17 
     18 // Runs on the primary thread.
     19 void BackgroundIO::OnIOSignalled() {
     20   if (controller_)
     21     controller_->InvokeCallback(this, false);
     22 }
     23 
     24 void BackgroundIO::Cancel() {
     25   // controller_ may be in use from the background thread at this time.
     26   base::AutoLock lock(controller_lock_);
     27   DCHECK(controller_);
     28   controller_ = NULL;
     29 }
     30 
     31 BackgroundIO::~BackgroundIO() {
     32 }
     33 
     34 // ---------------------------------------------------------------------------
     35 
     36 InFlightIO::InFlightIO()
     37     : callback_thread_(base::MessageLoopProxy::current()),
     38       running_(false), single_thread_(false) {
     39 }
     40 
     41 InFlightIO::~InFlightIO() {
     42 }
     43 
     44 // Runs on the background thread.
     45 void BackgroundIO::NotifyController() {
     46   base::AutoLock lock(controller_lock_);
     47   if (controller_)
     48     controller_->OnIOComplete(this);
     49 }
     50 
     51 void InFlightIO::WaitForPendingIO() {
     52   while (!io_list_.empty()) {
     53     // Block the current thread until all pending IO completes.
     54     IOList::iterator it = io_list_.begin();
     55     InvokeCallback(it->get(), true);
     56   }
     57 }
     58 
     59 void InFlightIO::DropPendingIO() {
     60   while (!io_list_.empty()) {
     61     IOList::iterator it = io_list_.begin();
     62     BackgroundIO* operation = it->get();
     63     operation->Cancel();
     64     DCHECK(io_list_.find(operation) != io_list_.end());
     65     io_list_.erase(make_scoped_refptr(operation));
     66   }
     67 }
     68 
     69 // Runs on a background thread.
     70 void InFlightIO::OnIOComplete(BackgroundIO* operation) {
     71 #ifndef NDEBUG
     72   if (callback_thread_->BelongsToCurrentThread()) {
     73     DCHECK(single_thread_ || !running_);
     74     single_thread_ = true;
     75   }
     76 #endif
     77 
     78   callback_thread_->PostTask(FROM_HERE,
     79                              base::Bind(&BackgroundIO::OnIOSignalled,
     80                                         operation));
     81   operation->io_completed()->Signal();
     82 }
     83 
     84 // Runs on the primary thread.
     85 void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) {
     86   {
     87     // http://crbug.com/74623
     88     base::ThreadRestrictions::ScopedAllowWait allow_wait;
     89     operation->io_completed()->Wait();
     90   }
     91   running_ = true;
     92 
     93   if (cancel_task)
     94     operation->Cancel();
     95 
     96   // Make sure that we remove the operation from the list before invoking the
     97   // callback (so that a subsequent cancel does not invoke the callback again).
     98   DCHECK(io_list_.find(operation) != io_list_.end());
     99   DCHECK(!operation->HasOneRef());
    100   io_list_.erase(make_scoped_refptr(operation));
    101   OnOperationComplete(operation, cancel_task);
    102 }
    103 
    104 // Runs on the primary thread.
    105 void InFlightIO::OnOperationPosted(BackgroundIO* operation) {
    106   DCHECK(callback_thread_->BelongsToCurrentThread());
    107   io_list_.insert(make_scoped_refptr(operation));
    108 }
    109 
    110 }  // namespace disk_cache
    111