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