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

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

Powered by Google App Engine
This is Rietveld 408576698