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