| OLD | NEW |
| 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 // For 64-bit file access (off_t = off64_t, lseek64, etc). | 5 // For 64-bit file access (off_t = off64_t, lseek64, etc). |
| 6 #define _FILE_OFFSET_BITS 64 | 6 #define _FILE_OFFSET_BITS 64 |
| 7 | 7 |
| 8 #include "net/base/file_stream.h" | 8 #include "net/base/file_stream.h" |
| 9 | 9 |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "base/file_path.h" | 21 #include "base/file_path.h" |
| 22 #include "base/logging.h" | 22 #include "base/logging.h" |
| 23 #include "base/message_loop.h" | 23 #include "base/message_loop.h" |
| 24 #include "base/metrics/histogram.h" | 24 #include "base/metrics/histogram.h" |
| 25 #include "base/string_util.h" | 25 #include "base/string_util.h" |
| 26 #include "base/threading/thread_restrictions.h" | 26 #include "base/threading/thread_restrictions.h" |
| 27 #include "base/threading/worker_pool.h" | 27 #include "base/threading/worker_pool.h" |
| 28 #include "base/synchronization/waitable_event.h" | 28 #include "base/synchronization/waitable_event.h" |
| 29 #include "net/base/file_stream_metrics.h" | 29 #include "net/base/file_stream_metrics.h" |
| 30 #include "net/base/file_stream_net_log_parameters.h" | 30 #include "net/base/file_stream_net_log_parameters.h" |
| 31 #include "net/base/io_buffer.h" |
| 31 #include "net/base/net_errors.h" | 32 #include "net/base/net_errors.h" |
| 32 | 33 |
| 33 #if defined(OS_ANDROID) | 34 #if defined(OS_ANDROID) |
| 34 // Android's bionic libc only supports the LFS transitional API. | 35 // Android's bionic libc only supports the LFS transitional API. |
| 35 #define off_t off64_t | 36 #define off_t off64_t |
| 36 #define lseek lseek64 | 37 #define lseek lseek64 |
| 37 #define stat stat64 | 38 #define stat stat64 |
| 38 #define fstat fstat64 | 39 #define fstat fstat64 |
| 39 #endif | 40 #endif |
| 40 | 41 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 | 161 |
| 161 // FileStream::AsyncContext ---------------------------------------------- | 162 // FileStream::AsyncContext ---------------------------------------------- |
| 162 | 163 |
| 163 class FileStream::AsyncContext { | 164 class FileStream::AsyncContext { |
| 164 public: | 165 public: |
| 165 AsyncContext(); | 166 AsyncContext(); |
| 166 ~AsyncContext(); | 167 ~AsyncContext(); |
| 167 | 168 |
| 168 // These methods post synchronous read() and write() calls to a WorkerThread. | 169 // These methods post synchronous read() and write() calls to a WorkerThread. |
| 169 void InitiateAsyncRead( | 170 void InitiateAsyncRead( |
| 170 base::PlatformFile file, char* buf, int buf_len, | 171 base::PlatformFile file, IOBuffer* buf, int buf_len, |
| 171 const net::BoundNetLog& bound_net_log, | 172 const net::BoundNetLog& bound_net_log, |
| 172 const CompletionCallback& callback); | 173 const CompletionCallback& callback); |
| 173 void InitiateAsyncWrite( | 174 void InitiateAsyncWrite( |
| 174 base::PlatformFile file, const char* buf, int buf_len, | 175 base::PlatformFile file, IOBuffer* buf, int buf_len, |
| 175 const net::BoundNetLog& bound_net_log, | 176 const net::BoundNetLog& bound_net_log, |
| 176 const CompletionCallback& callback); | 177 const CompletionCallback& callback); |
| 177 | 178 |
| 178 const CompletionCallback& callback() const { return callback_; } | 179 const CompletionCallback& callback() const { return callback_; } |
| 179 | 180 |
| 180 // Called by the WorkerPool thread executing the IO after the IO completes. | 181 // Called by the WorkerPool thread executing the IO after the IO completes. |
| 181 // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 182 // This method queues RunAsynchronousCallback() on the MessageLoop and signals |
| 182 // |background_io_completed_callback_|, in case the destructor is waiting. In | 183 // |background_io_completed_callback_|, in case the destructor is waiting. In |
| 183 // that case, the destructor will call RunAsynchronousCallback() instead, and | 184 // that case, the destructor will call RunAsynchronousCallback() instead, and |
| 184 // cancel |message_loop_task_|. | 185 // cancel |message_loop_task_|. |
| 185 // |result| is the result of the Read/Write task. | 186 // |result| is the result of the Read/Write task. |
| 186 void OnBackgroundIOCompleted(int result); | 187 void OnBackgroundIOCompleted(int result); |
| 187 | 188 |
| 188 void EnableErrorStatistics() { | 189 void EnableErrorStatistics() { |
| 189 record_uma_ = true; | 190 record_uma_ = true; |
| 190 } | 191 } |
| 191 | 192 |
| 192 private: | 193 private: |
| 193 // Always called on the IO thread, either directly by a task on the | 194 // Always called on the IO thread, either directly by a task on the |
| 194 // MessageLoop or by ~AsyncContext(). | 195 // MessageLoop or by ~AsyncContext(). |
| 195 void RunAsynchronousCallback(); | 196 void RunAsynchronousCallback(); |
| 196 | 197 |
| 197 // The MessageLoopForIO that this AsyncContext is running on. | 198 // The MessageLoopForIO that this AsyncContext is running on. |
| 198 MessageLoopForIO* const message_loop_; | 199 MessageLoopForIO* const message_loop_; |
| 199 CompletionCallback callback_; // The user provided callback. | 200 CompletionCallback callback_; // The user provided callback. |
| 201 scoped_refptr<IOBuffer> in_flight_buf_; |
| 200 | 202 |
| 201 // This is used to synchronize between the AsyncContext destructor (which runs | 203 // This is used to synchronize between the AsyncContext destructor (which runs |
| 202 // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool | 204 // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool |
| 203 // thread. | 205 // thread. |
| 204 base::WaitableEvent background_io_completed_; | 206 base::WaitableEvent background_io_completed_; |
| 205 | 207 |
| 206 // These variables are only valid when background_io_completed is signaled. | 208 // These variables are only valid when background_io_completed is signaled. |
| 207 int result_; | 209 int result_; |
| 208 CancelableCallback* message_loop_task_; | 210 CancelableCallback* message_loop_task_; |
| 209 | 211 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 231 RunAsynchronousCallback(); | 233 RunAsynchronousCallback(); |
| 232 if (need_to_wait) { | 234 if (need_to_wait) { |
| 233 // We want to see if we block the message loop for too long. | 235 // We want to see if we block the message loop for too long. |
| 234 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 236 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", |
| 235 base::TimeTicks::Now() - start); | 237 base::TimeTicks::Now() - start); |
| 236 } | 238 } |
| 237 } | 239 } |
| 238 } | 240 } |
| 239 | 241 |
| 240 void FileStream::AsyncContext::InitiateAsyncRead( | 242 void FileStream::AsyncContext::InitiateAsyncRead( |
| 241 base::PlatformFile file, char* buf, int buf_len, | 243 base::PlatformFile file, IOBuffer* buf, int buf_len, |
| 242 const net::BoundNetLog& bound_net_log, | 244 const net::BoundNetLog& bound_net_log, |
| 243 const CompletionCallback& callback) { | 245 const CompletionCallback& callback) { |
| 244 DCHECK(callback_.is_null()); | 246 DCHECK(callback_.is_null()); |
| 247 DCHECK(!in_flight_buf_); |
| 245 callback_ = callback; | 248 callback_ = callback; |
| 249 in_flight_buf_ = buf; // Hold until the async operation ends. |
| 246 | 250 |
| 247 base::WorkerPool::PostTask( | 251 base::WorkerPool::PostTask( |
| 248 FROM_HERE, | 252 FROM_HERE, |
| 249 base::Bind(&ReadFileTask, | 253 base::Bind(&ReadFileTask, |
| 250 file, | 254 file, |
| 251 buf, | 255 buf->data(), |
| 252 buf_len, | 256 buf_len, |
| 253 record_uma_, | 257 record_uma_, |
| 254 bound_net_log, | 258 bound_net_log, |
| 255 base::Bind(&AsyncContext::OnBackgroundIOCompleted, | 259 base::Bind(&AsyncContext::OnBackgroundIOCompleted, |
| 256 base::Unretained(this))), | 260 base::Unretained(this))), |
| 257 true /* task_is_slow */); | 261 true /* task_is_slow */); |
| 258 } | 262 } |
| 259 | 263 |
| 260 void FileStream::AsyncContext::InitiateAsyncWrite( | 264 void FileStream::AsyncContext::InitiateAsyncWrite( |
| 261 base::PlatformFile file, const char* buf, int buf_len, | 265 base::PlatformFile file, IOBuffer* buf, int buf_len, |
| 262 const net::BoundNetLog& bound_net_log, | 266 const net::BoundNetLog& bound_net_log, |
| 263 const CompletionCallback& callback) { | 267 const CompletionCallback& callback) { |
| 264 DCHECK(callback_.is_null()); | 268 DCHECK(callback_.is_null()); |
| 269 DCHECK(!in_flight_buf_); |
| 265 callback_ = callback; | 270 callback_ = callback; |
| 271 in_flight_buf_ = buf; // Hold until the async operation ends. |
| 266 | 272 |
| 267 base::WorkerPool::PostTask( | 273 base::WorkerPool::PostTask( |
| 268 FROM_HERE, | 274 FROM_HERE, |
| 269 base::Bind(&WriteFileTask, | 275 base::Bind(&WriteFileTask, |
| 270 file, | 276 file, |
| 271 buf, | 277 buf->data(), |
| 272 buf_len, | 278 buf_len, |
| 273 record_uma_, | 279 record_uma_, |
| 274 bound_net_log, | 280 bound_net_log, |
| 275 base::Bind(&AsyncContext::OnBackgroundIOCompleted, | 281 base::Bind(&AsyncContext::OnBackgroundIOCompleted, |
| 276 base::Unretained(this))), | 282 base::Unretained(this))), |
| 277 true /* task_is_slow */); | 283 true /* task_is_slow */); |
| 278 } | 284 } |
| 279 | 285 |
| 280 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 286 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { |
| 281 result_ = result; | 287 result_ = result; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 294 background_io_completed_.Wait(); | 300 background_io_completed_.Wait(); |
| 295 | 301 |
| 296 // Either we're in the MessageLoop's task, in which case Cancel() doesn't do | 302 // Either we're in the MessageLoop's task, in which case Cancel() doesn't do |
| 297 // anything, or we're in ~AsyncContext(), in which case this prevents the call | 303 // anything, or we're in ~AsyncContext(), in which case this prevents the call |
| 298 // from happening again. Must do it here after calling Wait(). | 304 // from happening again. Must do it here after calling Wait(). |
| 299 message_loop_task_->Cancel(); | 305 message_loop_task_->Cancel(); |
| 300 message_loop_task_ = NULL; // lifetime handled by base::Owned | 306 message_loop_task_ = NULL; // lifetime handled by base::Owned |
| 301 | 307 |
| 302 if (is_closing_) { | 308 if (is_closing_) { |
| 303 callback_.Reset(); | 309 callback_.Reset(); |
| 310 in_flight_buf_ = NULL; |
| 304 return; | 311 return; |
| 305 } | 312 } |
| 306 | 313 |
| 307 DCHECK(!callback_.is_null()); | 314 DCHECK(!callback_.is_null()); |
| 308 CompletionCallback temp; | 315 CompletionCallback temp_callback = callback_; |
| 309 std::swap(temp, callback_); | 316 callback_.Reset(); |
| 317 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_; |
| 318 in_flight_buf_ = NULL; |
| 310 background_io_completed_.Reset(); | 319 background_io_completed_.Reset(); |
| 311 temp.Run(result_); | 320 temp_callback.Run(result_); |
| 312 } | 321 } |
| 313 | 322 |
| 314 // FileStream ------------------------------------------------------------ | 323 // FileStream ------------------------------------------------------------ |
| 315 | 324 |
| 316 FileStream::FileStream(net::NetLog* net_log) | 325 FileStream::FileStream(net::NetLog* net_log) |
| 317 : file_(base::kInvalidPlatformFileValue), | 326 : file_(base::kInvalidPlatformFileValue), |
| 318 open_flags_(0), | 327 open_flags_(0), |
| 319 auto_closed_(true), | 328 auto_closed_(true), |
| 320 record_uma_(false), | 329 record_uma_(false), |
| 321 bound_net_log_(net::BoundNetLog::Make(net_log, | 330 bound_net_log_(net::BoundNetLog::Make(net_log, |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 bound_net_log_); | 442 bound_net_log_); |
| 434 } | 443 } |
| 435 | 444 |
| 436 int64 size = static_cast<int64>(info.st_size); | 445 int64 size = static_cast<int64>(info.st_size); |
| 437 DCHECK_GT(size, cur_pos); | 446 DCHECK_GT(size, cur_pos); |
| 438 | 447 |
| 439 return size - cur_pos; | 448 return size - cur_pos; |
| 440 } | 449 } |
| 441 | 450 |
| 442 int FileStream::Read( | 451 int FileStream::Read( |
| 443 char* buf, int buf_len, const CompletionCallback& callback) { | 452 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
| 444 DCHECK(async_context_.get()); | 453 DCHECK(async_context_.get()); |
| 445 return ReadInternal(buf, buf_len, callback); | 454 |
| 455 if (!IsOpen()) |
| 456 return ERR_UNEXPECTED; |
| 457 |
| 458 // read(..., 0) will return 0, which indicates end-of-file. |
| 459 DCHECK_GT(buf_len, 0); |
| 460 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); |
| 461 |
| 462 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 463 // Make sure we don't have a request in flight. |
| 464 DCHECK(async_context_->callback().is_null()); |
| 465 if (record_uma_) |
| 466 async_context_->EnableErrorStatistics(); |
| 467 async_context_->InitiateAsyncRead(file_, buf, buf_len, bound_net_log_, |
| 468 callback); |
| 469 return ERR_IO_PENDING; |
| 446 } | 470 } |
| 447 | 471 |
| 448 int FileStream::ReadSync(char* buf, int buf_len) { | 472 int FileStream::ReadSync(char* buf, int buf_len) { |
| 449 DCHECK(!async_context_.get()); | 473 DCHECK(!async_context_.get()); |
| 450 return ReadInternal(buf, buf_len, CompletionCallback()); | |
| 451 } | |
| 452 | 474 |
| 453 int FileStream::ReadInternal( | |
| 454 char* buf, int buf_len, const CompletionCallback& callback) { | |
| 455 if (!IsOpen()) | 475 if (!IsOpen()) |
| 456 return ERR_UNEXPECTED; | 476 return ERR_UNEXPECTED; |
| 457 | 477 |
| 458 // read(..., 0) will return 0, which indicates end-of-file. | 478 // read(..., 0) will return 0, which indicates end-of-file. |
| 459 DCHECK_GT(buf_len, 0); | 479 DCHECK_GT(buf_len, 0); |
| 460 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 480 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); |
| 461 | 481 |
| 462 if (async_context_.get()) { | 482 return ReadFile(file_, buf, buf_len, record_uma_, bound_net_log_); |
| 463 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | |
| 464 // If we're in async, make sure we don't have a request in flight. | |
| 465 DCHECK(async_context_->callback().is_null()); | |
| 466 if (record_uma_) | |
| 467 async_context_->EnableErrorStatistics(); | |
| 468 async_context_->InitiateAsyncRead(file_, buf, buf_len, bound_net_log_, | |
| 469 callback); | |
| 470 return ERR_IO_PENDING; | |
| 471 } else { | |
| 472 return ReadFile(file_, buf, buf_len, record_uma_, bound_net_log_); | |
| 473 } | |
| 474 } | 483 } |
| 475 | 484 |
| 476 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 485 int FileStream::ReadUntilComplete(char *buf, int buf_len) { |
| 477 int to_read = buf_len; | 486 int to_read = buf_len; |
| 478 int bytes_total = 0; | 487 int bytes_total = 0; |
| 479 | 488 |
| 480 do { | 489 do { |
| 481 int bytes_read = ReadSync(buf, to_read); | 490 int bytes_read = ReadSync(buf, to_read); |
| 482 if (bytes_read <= 0) { | 491 if (bytes_read <= 0) { |
| 483 if (bytes_total == 0) | 492 if (bytes_total == 0) |
| 484 return bytes_read; | 493 return bytes_read; |
| 485 | 494 |
| 486 return bytes_total; | 495 return bytes_total; |
| 487 } | 496 } |
| 488 | 497 |
| 489 bytes_total += bytes_read; | 498 bytes_total += bytes_read; |
| 490 buf += bytes_read; | 499 buf += bytes_read; |
| 491 to_read -= bytes_read; | 500 to_read -= bytes_read; |
| 492 } while (bytes_total < buf_len); | 501 } while (bytes_total < buf_len); |
| 493 | 502 |
| 494 return bytes_total; | 503 return bytes_total; |
| 495 } | 504 } |
| 496 | 505 |
| 497 int FileStream::Write( | 506 int FileStream::Write( |
| 498 const char* buf, int buf_len, const CompletionCallback& callback) { | 507 IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
| 499 DCHECK(async_context_.get()); | 508 DCHECK(async_context_.get()); |
| 500 return WriteInternal(buf, buf_len, callback); | |
| 501 } | |
| 502 | 509 |
| 503 int FileStream::WriteSync( | |
| 504 const char* buf, int buf_len) { | |
| 505 DCHECK(!async_context_.get()); | |
| 506 return WriteInternal(buf, buf_len, CompletionCallback()); | |
| 507 } | |
| 508 | |
| 509 int FileStream::WriteInternal( | |
| 510 const char* buf, int buf_len, const CompletionCallback& callback) { | |
| 511 // write(..., 0) will return 0, which indicates end-of-file. | 510 // write(..., 0) will return 0, which indicates end-of-file. |
| 512 DCHECK_GT(buf_len, 0); | 511 DCHECK_GT(buf_len, 0); |
| 513 | 512 |
| 514 if (!IsOpen()) | 513 if (!IsOpen()) |
| 515 return ERR_UNEXPECTED; | 514 return ERR_UNEXPECTED; |
| 516 | 515 |
| 517 if (async_context_.get()) { | 516 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); |
| 518 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 517 // Make sure we don't have a request in flight. |
| 519 // If we're in async, make sure we don't have a request in flight. | 518 DCHECK(async_context_->callback().is_null()); |
| 520 DCHECK(async_context_->callback().is_null()); | 519 if (record_uma_) |
| 521 if (record_uma_) | 520 async_context_->EnableErrorStatistics(); |
| 522 async_context_->EnableErrorStatistics(); | 521 async_context_->InitiateAsyncWrite(file_, buf, buf_len, bound_net_log_, |
| 523 async_context_->InitiateAsyncWrite(file_, buf, buf_len, bound_net_log_, | 522 callback); |
| 524 callback); | 523 return ERR_IO_PENDING; |
| 525 return ERR_IO_PENDING; | 524 } |
| 526 } else { | 525 |
| 527 return WriteFile(file_, buf, buf_len, record_uma_, bound_net_log_); | 526 int FileStream::WriteSync( |
| 528 } | 527 const char* buf, int buf_len) { |
| 528 DCHECK(!async_context_.get()); |
| 529 |
| 530 // write(..., 0) will return 0, which indicates end-of-file. |
| 531 DCHECK_GT(buf_len, 0); |
| 532 |
| 533 if (!IsOpen()) |
| 534 return ERR_UNEXPECTED; |
| 535 |
| 536 return WriteFile(file_, buf, buf_len, record_uma_, bound_net_log_); |
| 529 } | 537 } |
| 530 | 538 |
| 531 int64 FileStream::Truncate(int64 bytes) { | 539 int64 FileStream::Truncate(int64 bytes) { |
| 532 base::ThreadRestrictions::AssertIOAllowed(); | 540 base::ThreadRestrictions::AssertIOAllowed(); |
| 533 | 541 |
| 534 if (!IsOpen()) | 542 if (!IsOpen()) |
| 535 return ERR_UNEXPECTED; | 543 return ERR_UNEXPECTED; |
| 536 | 544 |
| 537 // We'd better be open for writing. | 545 // We'd better be open for writing. |
| 538 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 546 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 owner_bound_net_log.source()))); | 590 owner_bound_net_log.source()))); |
| 583 | 591 |
| 584 owner_bound_net_log.AddEvent( | 592 owner_bound_net_log.AddEvent( |
| 585 net::NetLog::TYPE_FILE_STREAM_SOURCE, | 593 net::NetLog::TYPE_FILE_STREAM_SOURCE, |
| 586 make_scoped_refptr( | 594 make_scoped_refptr( |
| 587 new net::NetLogSourceParameter("source_dependency", | 595 new net::NetLogSourceParameter("source_dependency", |
| 588 bound_net_log_.source()))); | 596 bound_net_log_.source()))); |
| 589 } | 597 } |
| 590 | 598 |
| 591 } // namespace net | 599 } // namespace net |
| OLD | NEW |