Index: net/disk_cache/sparse_control.cc |
=================================================================== |
--- net/disk_cache/sparse_control.cc (revision 28049) |
+++ net/disk_cache/sparse_control.cc (working copy) |
@@ -192,6 +192,7 @@ |
result_ = 0; |
pending_ = false; |
finished_ = false; |
+ abort_ = false; |
DoChildrenIO(); |
@@ -226,6 +227,24 @@ |
return result < 0 ? result : 0; // Don't mask error codes to the caller. |
} |
+void SparseControl::CancelIO() { |
+ if (operation_ == kNoOperation) |
+ return; |
+ abort_ = true; |
+} |
+ |
+int SparseControl::ReadyToUse(net::CompletionCallback* completion_callback) { |
+ if (!abort_) |
+ return net::OK; |
+ |
+ // We'll grab another reference to keep this object alive because we just have |
+ // one extra reference due to the pending IO operation itself, but we'll |
+ // release that one before invoking user_callback_. |
+ entry_->AddRef(); // Balanced in DoAbortCallbacks. |
+ abort_callbacks_.push_back(completion_callback); |
+ return net::ERR_IO_PENDING; |
+} |
+ |
// Static |
void SparseControl::DeleteChildren(EntryImpl* entry) { |
DCHECK(entry->GetEntryFlags() & PARENT_ENTRY); |
@@ -601,7 +620,7 @@ |
// progress. However, this entry can still be closed, and that would not |
// be a good thing for us, so we increase the refcount until we're |
// finished doing sparse stuff. |
- entry_->AddRef(); |
+ entry_->AddRef(); // Balanced in DoUserCallback. |
} |
return false; |
} |
@@ -681,6 +700,14 @@ |
DCHECK_NE(net::ERR_IO_PENDING, result); |
DoChildIOCompleted(result); |
+ if (abort_) { |
+ // We'll return the current result of the operation, which may be less than |
+ // the bytes to read or write, but the user cancelled the operation. |
+ abort_ = false; |
+ DoUserCallback(); |
+ return DoAbortCallbacks(); |
+ } |
+ |
// We are running a callback from the message loop. It's time to restart what |
// we were doing before. |
DoChildrenIO(); |
@@ -697,4 +724,17 @@ |
c->Run(result_); |
} |
+void SparseControl::DoAbortCallbacks() { |
+ for (size_t i = 0; i < abort_callbacks_.size(); i++) { |
+ // Releasing all references to entry_ may result in the destruction of this |
+ // object so we should not be touching it after the last Release(). |
+ net::CompletionCallback* c = abort_callbacks_[i]; |
+ if (i == abort_callbacks_.size() - 1) |
+ abort_callbacks_.clear(); |
+ |
+ entry_->Release(); // Don't touch object after this line. |
+ c->Run(net::OK); |
+ } |
+} |
+ |
} // namespace disk_cache |