Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: webkit/plugins/ppapi/quota_file_io.cc

Issue 7508010: Pepper quota fix: fire callbacks asynchronously to avoid crash in write callback chain (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: '' Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/plugins/ppapi/quota_file_io.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/plugins/ppapi/quota_file_io.h" 5 #include "webkit/plugins/ppapi/quota_file_io.h"
6 6
7 #include "base/stl_util.h" 7 #include "base/stl_util.h"
8 #include "base/message_loop_proxy.h" 8 #include "base/message_loop_proxy.h"
9 #include "base/task.h" 9 #include "base/task.h"
10 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" 10 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 } 76 }
77 virtual ~WriteOperation() {} 77 virtual ~WriteOperation() {}
78 virtual void Run() OVERRIDE { 78 virtual void Run() OVERRIDE {
79 DCHECK(quota_io_); 79 DCHECK(quota_io_);
80 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) { 80 if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
81 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE); 81 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
82 return; 82 return;
83 } 83 }
84 if (is_will_operation_) { 84 if (is_will_operation_) {
85 // Assuming the write will succeed. 85 // Assuming the write will succeed.
86 base::MessageLoopProxy::CreateForCurrentThread()->PostTask( 86 DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
87 FROM_HERE, runnable_factory_.NewRunnableMethod(
88 &WriteOperation::DidFinish,
89 base::PLATFORM_FILE_OK, bytes_to_write_));
90 return; 87 return;
91 } 88 }
92 DCHECK(buffer_.get()); 89 DCHECK(buffer_.get());
93 if (!base::FileUtilProxy::Write( 90 if (!base::FileUtilProxy::Write(
94 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(), 91 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
95 quota_io_->file_, offset_, buffer_.get(), bytes_to_write_, 92 quota_io_->file_, offset_, buffer_.get(), bytes_to_write_,
96 callback_factory_.NewCallback(&WriteOperation::DidFinish))) { 93 callback_factory_.NewCallback(&WriteOperation::DidFinish))) {
97 DidFail(base::PLATFORM_FILE_ERROR_FAILED); 94 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
98 return; 95 return;
99 } 96 }
100 } 97 }
101 98
102 virtual void DidFail(PlatformFileError error) OVERRIDE { 99 virtual void DidFail(PlatformFileError error) OVERRIDE {
103 base::MessageLoopProxy::CreateForCurrentThread()->PostTask( 100 DidFinish(error, 0);
104 FROM_HERE, runnable_factory_.NewRunnableMethod(
105 &WriteOperation::DidFinish, error, 0));
106 } 101 }
107 102
108 bool finished() const { return finished_; } 103 bool finished() const { return finished_; }
109 104
110 void RunCallback() { 105 virtual void WillRunCallback() {
111 DCHECK(callback_.get()); 106 base::MessageLoopProxy::CreateForCurrentThread()->PostTask(
112 callback_->Run(status_, bytes_written_); 107 FROM_HERE, runnable_factory_.NewRunnableMethod(
113 callback_.reset(); 108 &WriteOperation::RunCallback));
114 delete this;
115 } 109 }
116 110
117 private: 111 private:
118 void DidFinish(PlatformFileError status, int bytes_written) { 112 void DidFinish(PlatformFileError status, int bytes_written) {
119 finished_ = true; 113 finished_ = true;
120 status_ = status; 114 status_ = status;
121 bytes_written_ = bytes_written; 115 bytes_written_ = bytes_written;
122 int64_t max_offset = 116 int64_t max_offset =
123 (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written; 117 (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
124 // This may delete itself by calling RunCallback. 118 // This may delete itself by calling RunCallback.
125 quota_io_->DidWrite(this, max_offset); 119 quota_io_->DidWrite(this, max_offset);
126 } 120 }
127 121
122 virtual void RunCallback() {
123 DCHECK(callback_.get());
124 callback_->Run(status_, bytes_written_);
125 callback_.reset();
126 delete this;
127 }
128
128 const int64_t offset_; 129 const int64_t offset_;
129 scoped_array<char> buffer_; 130 scoped_array<char> buffer_;
130 const int32_t bytes_to_write_; 131 const int32_t bytes_to_write_;
131 scoped_ptr<WriteCallback> callback_; 132 scoped_ptr<WriteCallback> callback_;
132 bool finished_; 133 bool finished_;
133 PlatformFileError status_; 134 PlatformFileError status_;
134 int64_t bytes_written_; 135 int64_t bytes_written_;
135 base::ScopedCallbackFactory<QuotaFileIO::WriteOperation> callback_factory_; 136 base::ScopedCallbackFactory<WriteOperation> callback_factory_;
136 ScopedRunnableMethodFactory<QuotaFileIO::WriteOperation> runnable_factory_; 137 ScopedRunnableMethodFactory<WriteOperation> runnable_factory_;
137 }; 138 };
138 139
139 class QuotaFileIO::SetLengthOperation : public PendingOperationBase { 140 class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
140 public: 141 public:
141 SetLengthOperation(QuotaFileIO* quota_io, 142 SetLengthOperation(QuotaFileIO* quota_io,
142 bool is_will_operation, 143 bool is_will_operation,
143 int64_t length, 144 int64_t length,
144 StatusCallback* callback) 145 StatusCallback* callback)
145 : PendingOperationBase(quota_io, is_will_operation), 146 : PendingOperationBase(quota_io, is_will_operation),
146 length_(length), 147 length_(length),
147 callback_(callback), 148 callback_(callback),
148 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), 149 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
149 runnable_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} 150
151 protected:
yzshen1 2011/08/05 20:31:46 Is this 'protected' intended for all the methods b
kinuko 2011/08/08 11:21:12 Oops, this was a remnant of the other (reverted) c
150 virtual ~SetLengthOperation() {} 152 virtual ~SetLengthOperation() {}
151 153
152 virtual void Run() OVERRIDE { 154 virtual void Run() OVERRIDE {
153 DCHECK(quota_io_); 155 DCHECK(quota_io_);
154 if (quota_io_->CheckIfExceedsQuota(length_)) { 156 if (quota_io_->CheckIfExceedsQuota(length_)) {
155 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE); 157 DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
156 return; 158 return;
157 } 159 }
158 if (is_will_operation_) { 160 if (is_will_operation_) {
159 base::MessageLoopProxy::CreateForCurrentThread()->PostTask( 161 DidFinish(base::PLATFORM_FILE_OK);
160 FROM_HERE, runnable_factory_.NewRunnableMethod(
161 &SetLengthOperation::DidFinish,
162 base::PLATFORM_FILE_OK));
163 return; 162 return;
164 } 163 }
165 if (!base::FileUtilProxy::Truncate( 164 if (!base::FileUtilProxy::Truncate(
166 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(), 165 quota_io_->instance_->delegate()->GetFileThreadMessageLoopProxy(),
167 quota_io_->file_, length_, 166 quota_io_->file_, length_,
168 callback_factory_.NewCallback(&SetLengthOperation::DidFinish))) { 167 callback_factory_.NewCallback(&SetLengthOperation::DidFinish))) {
169 DidFail(base::PLATFORM_FILE_ERROR_FAILED); 168 DidFail(base::PLATFORM_FILE_ERROR_FAILED);
170 return; 169 return;
171 } 170 }
172 } 171 }
173 172
174 virtual void DidFail(PlatformFileError error) OVERRIDE { 173 virtual void DidFail(PlatformFileError error) OVERRIDE {
175 base::MessageLoopProxy::CreateForCurrentThread()->PostTask( 174 DidFinish(error);
176 FROM_HERE, runnable_factory_.NewRunnableMethod(
177 &SetLengthOperation::DidFinish, error));
178 } 175 }
179 176
180 private: 177 private:
181 void DidFinish(PlatformFileError status) { 178 void DidFinish(PlatformFileError status) {
182 quota_io_->DidSetLength(status, length_); 179 quota_io_->DidSetLength(status, length_);
183 DCHECK(callback_.get()); 180 DCHECK(callback_.get());
184 callback_->Run(status); 181 callback_->Run(status);
185 callback_.reset(); 182 callback_.reset();
186 delete this; 183 delete this;
187 } 184 }
188 185
189 int64_t length_; 186 int64_t length_;
190 scoped_ptr<StatusCallback> callback_; 187 scoped_ptr<StatusCallback> callback_;
191 base::ScopedCallbackFactory<QuotaFileIO::SetLengthOperation> 188 base::ScopedCallbackFactory<SetLengthOperation> callback_factory_;
192 callback_factory_;
193 ScopedRunnableMethodFactory<QuotaFileIO::SetLengthOperation>
194 runnable_factory_;
195 }; 189 };
196 190
197 // QuotaFileIO -------------------------------------------------------------- 191 // QuotaFileIO --------------------------------------------------------------
198 192
199 QuotaFileIO::QuotaFileIO( 193 QuotaFileIO::QuotaFileIO(
200 PluginInstance* instance, 194 PluginInstance* instance,
201 PlatformFile file, 195 PlatformFile file,
202 const GURL& file_url, 196 const GURL& file_url,
203 PP_FileSystemType type) 197 PP_FileSystemType type)
204 : instance_(instance), 198 : instance_(instance),
205 file_(file), 199 file_(file),
206 file_url_(file_url), 200 file_url_(file_url),
207 storage_type_(PPFileSystemTypeToQuotaStorageType(type)), 201 storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
208 cached_file_size_(0), 202 cached_file_size_(0),
209 cached_available_space_(0), 203 cached_available_space_(0),
210 outstanding_quota_queries_(0), 204 outstanding_quota_queries_(0),
211 outstanding_errors_(0), 205 outstanding_errors_(0),
212 max_written_offset_(0), 206 max_written_offset_(0),
213 inflight_operations_(0), 207 inflight_operations_(0),
214 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { 208 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
215 DCHECK(instance_); 209 DCHECK(instance_);
216 DCHECK_NE(base::kInvalidPlatformFileValue, file_); 210 DCHECK_NE(base::kInvalidPlatformFileValue, file_);
217 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_); 211 DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
218 } 212 }
219 213
220 QuotaFileIO::~QuotaFileIO() { 214 QuotaFileIO::~QuotaFileIO() {
221 // Note that this doesn't dispatch pending callbacks. 215 // Note that this doesn't dispatch pending callbacks.
222 STLDeleteContainerPointers(pending_operations_.begin(), 216 STLDeleteContainerPointers(pending_operations_.begin(),
223 pending_operations_.end()); 217 pending_operations_.end());
218 STLDeleteContainerPointers(pending_callbacks_.begin(),
219 pending_callbacks_.end());
224 } 220 }
225 221
226 bool QuotaFileIO::Write( 222 bool QuotaFileIO::Write(
227 int64_t offset, const char* buffer, int32_t bytes_to_write, 223 int64_t offset, const char* buffer, int32_t bytes_to_write,
228 WriteCallback* callback) { 224 WriteCallback* callback) {
229 WriteOperation* op = new WriteOperation( 225 WriteOperation* op = new WriteOperation(
230 this, false, offset, buffer, bytes_to_write, callback); 226 this, false, offset, buffer, bytes_to_write, callback);
231 return RegisterOperationForQuotaChecks(op); 227 return RegisterOperationForQuotaChecks(op);
232 } 228 }
233 229
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) { 291 void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
296 cached_available_space_ = avail_space; 292 cached_available_space_ = avail_space;
297 DCHECK_GT(outstanding_quota_queries_, 0); 293 DCHECK_GT(outstanding_quota_queries_, 0);
298 if (--outstanding_quota_queries_ == 0) 294 if (--outstanding_quota_queries_ == 0)
299 DidQueryForQuotaCheck(); 295 DidQueryForQuotaCheck();
300 } 296 }
301 297
302 void QuotaFileIO::DidQueryForQuotaCheck() { 298 void QuotaFileIO::DidQueryForQuotaCheck() {
303 DCHECK(!pending_operations_.empty()); 299 DCHECK(!pending_operations_.empty());
304 DCHECK_GT(inflight_operations_, 0); 300 DCHECK_GT(inflight_operations_, 0);
305 for (std::deque<PendingOperationBase*>::iterator iter = 301 while (!pending_operations_.empty()) {
306 pending_operations_.begin(); 302 PendingOperationBase* op = pending_operations_.front();
307 iter != pending_operations_.end(); 303 pending_operations_.pop_front();
308 ++iter) { 304 pending_callbacks_.push_back(op);
309 PendingOperationBase* op = *iter;
310 if (outstanding_errors_ > 0) { 305 if (outstanding_errors_ > 0) {
311 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED); 306 op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
312 continue; 307 continue;
313 } 308 }
314 op->Run(); 309 op->Run();
315 } 310 }
316 } 311 }
317 312
318 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const { 313 bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
319 DCHECK_GE(cached_file_size_, 0); 314 DCHECK_GE(cached_file_size_, 0);
320 DCHECK_GE(cached_available_space_, 0); 315 DCHECK_GE(cached_available_space_, 0);
321 return new_file_size - cached_file_size_ > cached_available_space_; 316 return new_file_size - cached_file_size_ > cached_available_space_;
322 } 317 }
323 318
324 void QuotaFileIO::WillUpdate() { 319 void QuotaFileIO::WillUpdate() {
325 if (inflight_operations_++ == 0) { 320 if (inflight_operations_++ == 0) {
326 instance_->delegate()->WillUpdateFile(file_url_); 321 instance_->delegate()->WillUpdateFile(file_url_);
327 DCHECK_EQ(0, max_written_offset_); 322 DCHECK_EQ(0, max_written_offset_);
328 } 323 }
329 } 324 }
330 325
331 void QuotaFileIO::DidWrite(WriteOperation* op, 326 void QuotaFileIO::DidWrite(WriteOperation* op,
332 int64_t written_offset_end) { 327 int64_t written_offset_end) {
333 max_written_offset_ = std::max(max_written_offset_, written_offset_end); 328 max_written_offset_ = std::max(max_written_offset_, written_offset_end);
334 DCHECK_GT(inflight_operations_, 0); 329 DCHECK_GT(inflight_operations_, 0);
335 DCHECK(!pending_operations_.empty()); 330 DCHECK(!pending_callbacks_.empty());
336 // Fire callbacks for finished operations. 331 // Fire callbacks for finished operations.
337 while (!pending_operations_.empty()) { 332 while (!pending_callbacks_.empty()) {
338 WriteOperation* op = static_cast<WriteOperation*>( 333 WriteOperation* op = static_cast<WriteOperation*>(
339 pending_operations_.front()); 334 pending_callbacks_.front());
340 if (!op->finished()) 335 if (!op->finished())
341 break; 336 break;
342 op->RunCallback(); 337 pending_callbacks_.pop_front();
343 pending_operations_.pop_front(); 338 op->WillRunCallback();
344 } 339 }
345 // If we have no more pending writes, notify the browser that we did 340 // If we have no more pending writes, notify the browser that we did
346 // update the file. 341 // update the file.
347 if (--inflight_operations_ == 0) { 342 if (--inflight_operations_ == 0) {
348 DCHECK(pending_operations_.empty()); 343 DCHECK(pending_operations_.empty());
349 int64_t growth = max_written_offset_ - cached_file_size_; 344 int64_t growth = max_written_offset_ - cached_file_size_;
350 growth = growth < 0 ? 0 : growth; 345 growth = growth < 0 ? 0 : growth;
351 instance_->delegate()->DidUpdateFile(file_url_, growth); 346 instance_->delegate()->DidUpdateFile(file_url_, growth);
352 max_written_offset_ = 0; 347 max_written_offset_ = 0;
353 } 348 }
354 } 349 }
355 350
356 void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) { 351 void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
357 DCHECK_EQ(1, inflight_operations_); 352 DCHECK_EQ(1, inflight_operations_);
358 pending_operations_.pop_front(); 353 pending_callbacks_.pop_front();
359 DCHECK(pending_operations_.empty()); 354 DCHECK(pending_callbacks_.empty());
360 int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 : 355 int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
361 new_file_size - cached_file_size_; 356 new_file_size - cached_file_size_;
362 instance_->delegate()->DidUpdateFile(file_url_, delta); 357 instance_->delegate()->DidUpdateFile(file_url_, delta);
363 inflight_operations_ = 0; 358 inflight_operations_ = 0;
364 } 359 }
365 360
366 } // namespace ppapi 361 } // namespace ppapi
367 } // namespace webkit 362 } // namespace webkit
OLDNEW
« no previous file with comments | « webkit/plugins/ppapi/quota_file_io.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698