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

Side by Side Diff: net/base/file_stream.cc

Issue 10701050: net: Implement canceling of all async operations in FileStream. (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 3 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "net/base/file_stream.h" 5 #include "net/base/file_stream.h"
6 6
7 #include "base/location.h"
8 #include "base/message_loop_proxy.h"
9 #include "base/task_runner_util.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "base/threading/worker_pool.h"
12 #include "net/base/file_stream_net_log_parameters.h"
13 #include "net/base/net_errors.h"
14
15 #if defined(OS_WIN)
16 #include "net/base/file_stream_win.h"
17 #elif defined(OS_POSIX)
18 #include "net/base/file_stream_posix.h"
19 #endif
20
21 namespace {
22
23 void CallInt64ToInt(const net::CompletionCallback& callback, int64 result) {
24 callback.Run(static_cast<int>(result));
25 }
26
27 }
28
7 namespace net { 29 namespace net {
8 30
31 void FileStream::Context::Orphan() {
32 DCHECK(!orphaned_);
33
34 orphaned_ = true;
35 if (async_in_progress_) {
36 // Do we need this here? It can race with CloseAsync() and result in
37 // calling CancelIo() on the file handle that was already closed and
38 // reopened again.
39 //if (file_ != base::kInvalidPlatformFileValue)
40 // CancelIo(file_);
41 } else {
42 CloseAsync(CompletionCallback());
43 }
44 }
45
46 void FileStream::Context::OpenAsync(const FilePath& path,
47 int open_flags,
48 const CompletionCallback& callback) {
49 DCHECK(!async_in_progress_);
50
51 BeginOpenEvent(path);
52
53 const bool posted = base::PostTaskAndReplyWithResult(
54 base::WorkerPool::GetTaskRunner(true /* task_is_slow */),
55 FROM_HERE,
56 base::Bind(&Context::OpenFileImpl,
57 base::Unretained(this), path, open_flags),
58 base::Bind(&Context::OnOpenCompleted,
59 base::Unretained(this), callback));
60 DCHECK(posted);
61
62 async_in_progress_ = true;
63 }
64
65 int FileStream::Context::OpenSync(const FilePath& path, int open_flags) {
66 DCHECK(!async_in_progress_);
67
68 BeginOpenEvent(path);
69 OpenResult result = OpenFileImpl(path, open_flags);
70 file_ = result.file;
71 if (file_ == base::kInvalidPlatformFileValue) {
72 result.error_code = ProcessOpenError(result.error_code);
73 } else {
74 // TODO(satorux): Remove this once all async clients are migrated to use
75 // Open(). crbug.com/114783
76 if (open_flags & base::PLATFORM_FILE_ASYNC)
77 OnAsyncFileOpened();
78 }
79 return result.error_code;
80 }
81
82 void FileStream::Context::CloseAsync(const CompletionCallback& callback) {
83 DCHECK(!async_in_progress_);
84
85 bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE);
86
87 if (file_ == base::kInvalidPlatformFileValue) {
88 base::MessageLoopProxy::current()->PostTask(
89 FROM_HERE,
90 base::Bind(&Context::OnCloseCompleted,
91 base::Unretained(this), callback));
92 } else {
93 const bool posted = base::WorkerPool::PostTaskAndReply(
94 FROM_HERE,
95 base::Bind(base::IgnoreResult(&base::ClosePlatformFile), file_),
96 base::Bind(&Context::OnCloseCompleted,
97 base::Unretained(this), callback),
98 true /* task_is_slow */);
99 DCHECK(posted);
100
101 async_in_progress_ = true;
102 }
103 }
104
105 void FileStream::Context::CloseSync() {
106 DCHECK(!async_in_progress_);
107 bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE);
108 if (file_ != base::kInvalidPlatformFileValue) {
109 base::ClosePlatformFile(file_);
110 file_ = base::kInvalidPlatformFileValue;
111 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
112 }
113 }
114
115 void FileStream::Context::SeekAsync(Whence whence,
116 int64 offset,
117 const Int64CompletionCallback& callback) {
118 DCHECK(!async_in_progress_);
119
120 const bool posted = base::PostTaskAndReplyWithResult(
121 base::WorkerPool::GetTaskRunner(true /* task is slow */),
122 FROM_HERE,
123 base::Bind(&Context::SeekFileImpl,
124 base::Unretained(this), whence, offset),
125 base::Bind(&Context::ProcessAsyncResult,
126 base::Unretained(this), callback, FILE_ERROR_SOURCE_SEEK));
127 DCHECK(posted);
128
129 async_in_progress_ = true;
130 }
131
132 int64 FileStream::Context::SeekSync(Whence whence, int64 offset) {
133 int64 result = SeekFileImpl(whence, offset);
134 CheckForIOError(&result, FILE_ERROR_SOURCE_SEEK);
135 return result;
136 }
137
138 int FileStream::Context::RecordAndMapError(int error,
139 FileErrorSource source) const {
140 // The following check is against incorrect use or bug. File descriptor
141 // shouldn't ever be closed outside of FileStream while it still tries to do
142 // something with it.
143 DCHECK(error != kErrorBadFile);
144 net::Error net_error = MapSystemError(error);
145
146 if (!orphaned_) {
147 bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_ERROR,
148 base::Bind(&NetLogFileStreamErrorCallback,
149 source, error, net_error));
150 }
151 RecordFileError(error, source, record_uma_);
152 return net_error;
153 }
154
155 void FileStream::Context::BeginOpenEvent(const FilePath& path) {
156 std::string file_name = path.AsUTF8Unsafe();
157 bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_OPEN,
158 NetLog::StringCallback("file_name", &file_name));
159 }
160
161 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
162 const FilePath& path, int open_flags) {
163 OpenResult result;
164 result.error_code = OK;
165 result.file = base::CreatePlatformFile(path, open_flags, NULL, NULL);
166 if (result.file == base::kInvalidPlatformFileValue)
167 result.error_code = GetLastErrno();
168
169 return result;
170 }
171
172 int FileStream::Context::ProcessOpenError(int error_code) {
173 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
174 return RecordAndMapError(error_code, FILE_ERROR_SOURCE_OPEN);
175 }
176
177 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
178 OpenResult result) {
179 file_ = result.file;
180 if (file_ == base::kInvalidPlatformFileValue)
181 result.error_code = ProcessOpenError(result.error_code);
182 else if (!orphaned_)
183 OnAsyncFileOpened();
184 OnAsyncCompleted(IntToInt64(callback), result.error_code);
185 }
186
187 void FileStream::Context::OnCloseCompleted(const CompletionCallback& callback) {
188 file_ = base::kInvalidPlatformFileValue;
189 if (!orphaned_) {
190 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
191 // Reset this before Run() as Run() may issue a new async operation.
192 async_in_progress_ = false;
193 callback.Run(OK);
194 } else {
195 delete this;
196 }
197 }
198
199 Int64CompletionCallback FileStream::Context::IntToInt64(
200 const CompletionCallback& callback) {
201 return base::Bind(&CallInt64ToInt, callback);
202 }
203
204 void FileStream::Context::CheckForIOError(int64* result,
205 FileErrorSource source) {
206 if (*result < 0)
207 *result = RecordAndMapError(static_cast<int>(*result), source);
208 }
209
210 void FileStream::Context::ProcessAsyncResult(
211 const Int64CompletionCallback& callback,
212 FileErrorSource source,
213 int64 result) {
214 CheckForIOError(&result, source);
215 OnAsyncCompleted(callback, result);
216 }
217
218 void FileStream::Context::OnAsyncCompleted(
219 const Int64CompletionCallback& callback,
220 int64 result) {
221 // Reset this before Run() as Run() may issue a new async operation. Also it
222 // should be reset before CloseAsync() because it shouldn't run if any async
223 // operation is in progress.
224 async_in_progress_ = false;
225 if (orphaned_)
226 CloseAsync(CompletionCallback());
227 else
228 callback.Run(result);
229 }
230
9 FileStream::FileStream(net::NetLog* net_log) 231 FileStream::FileStream(net::NetLog* net_log)
10 : impl_(net_log) { 232 : open_flags_(0),
11 } 233 bound_net_log_(net::BoundNetLog::Make(net_log,
12 234 net::NetLog::SOURCE_FILESTREAM)),
13 FileStream::FileStream( 235 context_(new Context(bound_net_log_)) {
14 base::PlatformFile file, int flags, net::NetLog* net_log) 236 bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
15 : impl_(file, flags, net_log) { 237 }
238
239 FileStream::FileStream(base::PlatformFile file, int flags, net::NetLog* net_log)
240 : open_flags_(flags),
241 bound_net_log_(net::BoundNetLog::Make(net_log,
242 net::NetLog::SOURCE_FILESTREAM)),
243 context_(new Context(file, bound_net_log_, open_flags_)) {
244 bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
16 } 245 }
17 246
18 FileStream::~FileStream() { 247 FileStream::~FileStream() {
248 if (IsOpen() && !is_async()) {
249 CloseSync();
250 context_.reset();
251 } else {
252 context_.release()->Orphan();
253 }
254
255 bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
19 } 256 }
20 257
21 void FileStream::Close(const CompletionCallback& callback) { 258 void FileStream::Close(const CompletionCallback& callback) {
22 impl_.Close(callback); 259 DCHECK(is_async());
260 context_->CloseAsync(callback);
23 } 261 }
24 262
25 void FileStream::CloseSync() { 263 void FileStream::CloseSync() {
26 impl_.CloseSync(); 264 base::ThreadRestrictions::AssertIOAllowed();
265
266 // TODO(satorux): Replace the following async stuff with a
267 // DCHECK(is_async()) once all async clients are migrated to
268 // use Close(). crbug.com/114783
269 if (!context_->async_in_progress()) {
270 context_->CloseSync();
271 } else {
272 Context* old_context = context_.release();
273 context_.reset(new Context(bound_net_log_));
274 context_->set_record_uma(old_context->record_uma());
275 old_context->Orphan();
276 }
27 } 277 }
28 278
29 int FileStream::Open(const FilePath& path, int open_flags, 279 int FileStream::Open(const FilePath& path, int open_flags,
30 const CompletionCallback& callback) { 280 const CompletionCallback& callback) {
31 return impl_.Open(path, open_flags, callback); 281 if (IsOpen()) {
282 DLOG(FATAL) << "File is already open!";
283 return ERR_UNEXPECTED;
284 }
285
286 open_flags_ = open_flags;
287 DCHECK(is_async());
288 context_->OpenAsync(path, open_flags, callback);
289 return ERR_IO_PENDING;
32 } 290 }
33 291
34 int FileStream::OpenSync(const FilePath& path, int open_flags) { 292 int FileStream::OpenSync(const FilePath& path, int open_flags) {
35 return impl_.OpenSync(path, open_flags); 293 base::ThreadRestrictions::AssertIOAllowed();
294
295 if (IsOpen()) {
296 DLOG(FATAL) << "File is already open!";
297 return ERR_UNEXPECTED;
298 }
299
300 open_flags_ = open_flags;
301 // TODO(satorux): Put a DCHECK once all async clients are migrated
302 // to use Open(). crbug.com/114783
303 //
304 // DCHECK(!is_async());
305 return context_->OpenSync(path, open_flags_);
36 } 306 }
37 307
38 bool FileStream::IsOpen() const { 308 bool FileStream::IsOpen() const {
39 return impl_.IsOpen(); 309 return context_->file() != base::kInvalidPlatformFileValue;
40 } 310 }
41 311
42 int FileStream::Seek(Whence whence, int64 offset, 312 int FileStream::Seek(Whence whence,
313 int64 offset,
43 const Int64CompletionCallback& callback) { 314 const Int64CompletionCallback& callback) {
44 return impl_.Seek(whence, offset, callback); 315 if (!IsOpen())
316 return ERR_UNEXPECTED;
317
318 // Make sure we're async.
319 DCHECK(is_async());
320 context_->SeekAsync(whence, offset, callback);
321 return ERR_IO_PENDING;
45 } 322 }
46 323
47 int64 FileStream::SeekSync(Whence whence, int64 offset) { 324 int64 FileStream::SeekSync(Whence whence, int64 offset) {
48 return impl_.SeekSync(whence, offset); 325 base::ThreadRestrictions::AssertIOAllowed();
326
327 if (!IsOpen())
328 return ERR_UNEXPECTED;
329
330 // If we're in async, make sure we don't have a request in flight.
331 DCHECK(!is_async() || !context_->async_in_progress());
332 return context_->SeekSync(whence, offset);
49 } 333 }
50 334
51 int64 FileStream::Available() { 335 int64 FileStream::Available() {
52 return impl_.Available(); 336 base::ThreadRestrictions::AssertIOAllowed();
53 } 337
54 338 if (!IsOpen())
55 int FileStream::Read( 339 return ERR_UNEXPECTED;
56 IOBuffer* in_buf, int buf_len, const CompletionCallback& callback) { 340
57 return impl_.Read(in_buf, buf_len, callback); 341 int64 cur_pos = SeekSync(FROM_CURRENT, 0);
342 if (cur_pos < 0)
343 return cur_pos;
344
345 int64 size = context_->GetFileSize();
346 if (size < 0)
347 return size;
348
349 DCHECK_GT(size, cur_pos);
350 return size - cur_pos;
351 }
352
353 int FileStream::Read(IOBuffer* buf,
354 int buf_len,
355 const CompletionCallback& callback) {
356 if (!IsOpen())
357 return ERR_UNEXPECTED;
358
359 // read(..., 0) will return 0, which indicates end-of-file.
360 DCHECK_GT(buf_len, 0);
361 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
362 DCHECK(is_async());
363
364 return context_->ReadAsync(buf, buf_len, callback);
58 } 365 }
59 366
60 int FileStream::ReadSync(char* buf, int buf_len) { 367 int FileStream::ReadSync(char* buf, int buf_len) {
61 return impl_.ReadSync(buf, buf_len); 368 base::ThreadRestrictions::AssertIOAllowed();
369
370 if (!IsOpen())
371 return ERR_UNEXPECTED;
372
373 DCHECK(!is_async());
374 // read(..., 0) will return 0, which indicates end-of-file.
375 DCHECK_GT(buf_len, 0);
376 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
377
378 return context_->ReadSync(buf, buf_len);
62 } 379 }
63 380
64 int FileStream::ReadUntilComplete(char *buf, int buf_len) { 381 int FileStream::ReadUntilComplete(char *buf, int buf_len) {
65 return impl_.ReadUntilComplete(buf, buf_len); 382 base::ThreadRestrictions::AssertIOAllowed();
66 } 383
67 384 int to_read = buf_len;
68 int FileStream::Write( 385 int bytes_total = 0;
69 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { 386
70 return impl_.Write(buf, buf_len, callback); 387 do {
388 int bytes_read = ReadSync(buf, to_read);
389 if (bytes_read <= 0) {
390 if (bytes_total == 0)
391 return bytes_read;
392
393 return bytes_total;
394 }
395
396 bytes_total += bytes_read;
397 buf += bytes_read;
398 to_read -= bytes_read;
399 } while (bytes_total < buf_len);
400
401 return bytes_total;
402 }
403
404 int FileStream::Write(IOBuffer* buf,
405 int buf_len,
406 const CompletionCallback& callback) {
407 if (!IsOpen())
408 return ERR_UNEXPECTED;
409
410 DCHECK(is_async());
411 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
412 // write(..., 0) will return 0, which indicates end-of-file.
413 DCHECK_GT(buf_len, 0);
414
415 return context_->WriteAsync(buf, buf_len, callback);
71 } 416 }
72 417
73 int FileStream::WriteSync(const char* buf, int buf_len) { 418 int FileStream::WriteSync(const char* buf, int buf_len) {
74 return impl_.WriteSync(buf, buf_len); 419 base::ThreadRestrictions::AssertIOAllowed();
420
421 if (!IsOpen())
422 return ERR_UNEXPECTED;
423
424 DCHECK(!is_async());
425 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
426 // write(..., 0) will return 0, which indicates end-of-file.
427 DCHECK_GT(buf_len, 0);
428
429 return context_->WriteSync(buf, buf_len);
75 } 430 }
76 431
77 int64 FileStream::Truncate(int64 bytes) { 432 int64 FileStream::Truncate(int64 bytes) {
78 return impl_.Truncate(bytes); 433 base::ThreadRestrictions::AssertIOAllowed();
434
435 if (!IsOpen())
436 return ERR_UNEXPECTED;
437
438 // We'd better be open for writing.
439 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
440
441 // Seek to the position to truncate from.
442 int64 seek_position = SeekSync(FROM_BEGIN, bytes);
443 if (seek_position != bytes)
444 return ERR_UNEXPECTED;
445
446 // And truncate the file.
447 return context_->Truncate(bytes);
79 } 448 }
80 449
81 int FileStream::Flush() { 450 int FileStream::Flush() {
82 return impl_.Flush(); 451 base::ThreadRestrictions::AssertIOAllowed();
452
453 if (!IsOpen())
454 return ERR_UNEXPECTED;
455
456 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
457 return context_->Flush();
83 } 458 }
84 459
85 void FileStream::EnableErrorStatistics() { 460 void FileStream::EnableErrorStatistics() {
86 impl_.EnableErrorStatistics(); 461 context_->set_record_uma(true);
87 } 462 }
88 463
89 void FileStream::SetBoundNetLogSource( 464 void FileStream::SetBoundNetLogSource(
90 const net::BoundNetLog& owner_bound_net_log) { 465 const net::BoundNetLog& owner_bound_net_log) {
91 impl_.SetBoundNetLogSource(owner_bound_net_log); 466 if ((owner_bound_net_log.source().id == net::NetLog::Source::kInvalidId) &&
467 (bound_net_log_.source().id == net::NetLog::Source::kInvalidId)) {
468 // Both |BoundNetLog|s are invalid.
469 return;
470 }
471
472 // Should never connect to itself.
473 DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);
474
475 bound_net_log_.AddEvent(
476 net::NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
477 owner_bound_net_log.source().ToEventParametersCallback());
478
479 owner_bound_net_log.AddEvent(
480 net::NetLog::TYPE_FILE_STREAM_SOURCE,
481 bound_net_log_.source().ToEventParametersCallback());
92 } 482 }
93 483
94 base::PlatformFile FileStream::GetPlatformFileForTesting() { 484 base::PlatformFile FileStream::GetPlatformFileForTesting() {
95 return impl_.GetPlatformFileForTesting(); 485 return context_->file();
96 } 486 }
97 487
98 } // namespace net 488 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698