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

Unified Diff: net/base/file_stream_posix.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, 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 side-by-side diff with in-line comments
Download patch
Index: net/base/file_stream_posix.cc
===================================================================
--- net/base/file_stream_posix.cc (revision 151422)
+++ net/base/file_stream_posix.cc (working copy)
@@ -5,7 +5,7 @@
// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64
-#include "net/base/file_stream.h"
+#include "net/base/file_stream_posix.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -20,13 +20,13 @@
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
+#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
+#include "base/task_runner_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
-#include "base/synchronization/waitable_event.h"
-#include "net/base/file_stream_metrics.h"
#include "net/base/file_stream_net_log_parameters.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -49,599 +49,339 @@
FROM_CURRENT == SEEK_CUR &&
FROM_END == SEEK_END, whence_matches_system);
-namespace {
-
-int RecordAndMapError(int error,
- FileErrorSource source,
- bool record_uma,
- const net::BoundNetLog& bound_net_log) {
- net::Error net_error = MapSystemError(error);
-
- bound_net_log.AddEvent(
- net::NetLog::TYPE_FILE_STREAM_ERROR,
- base::Bind(&NetLogFileStreamErrorCallback,
- source, error, net_error));
-
- RecordFileError(error, source, record_uma);
-
- return net_error;
+FileStream::AsyncContext::AsyncContext(const BoundNetLog& bound_net_log)
+ : file_(base::kInvalidPlatformFileValue),
+ record_uma_(false),
+ async_in_progress_(false),
+ destroyed_(false),
+ bound_net_log_(bound_net_log) {
}
-// Opens a file with some network logging.
-// The opened file and the result code are written to |file| and |result|.
-void OpenFile(const FilePath& path,
- int open_flags,
- bool record_uma,
- base::PlatformFile* file,
- int* result,
- const net::BoundNetLog& bound_net_log) {
- std::string file_name = path.AsUTF8Unsafe();
- bound_net_log.BeginEvent(
- net::NetLog::TYPE_FILE_STREAM_OPEN,
- NetLog::StringCallback("file_name", &file_name));
-
- *result = OK;
- *file = base::CreatePlatformFile(path, open_flags, NULL, NULL);
- if (*file == base::kInvalidPlatformFileValue) {
- bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
- *result = RecordAndMapError(errno, FILE_ERROR_SOURCE_OPEN, record_uma,
- bound_net_log);
- }
+FileStream::AsyncContext::AsyncContext(base::PlatformFile file,
+ const BoundNetLog& bound_net_log,
+ int /* open_flags */)
+ : file_(file),
+ record_uma_(false),
+ async_in_progress_(false),
+ destroyed_(false),
+ bound_net_log_(bound_net_log) {
}
-// Opens a file using OpenFile() and then signals the completion.
-void OpenFileAndSignal(const FilePath& path,
- int open_flags,
- bool record_uma,
- base::PlatformFile* file,
- int* result,
- base::WaitableEvent* on_io_complete,
- const net::BoundNetLog& bound_net_log) {
- OpenFile(path, open_flags, record_uma, file, result, bound_net_log);
- on_io_complete->Signal();
+void FileStream::AsyncContext::Destroy() {
willchan no longer on Chromium 2012/08/27 06:59:10 Oops, earlier I neglected to mention how this bit
+ destroyed_ = true;
+ if (!async_in_progress_)
+ DeleteAbandoned();
}
-// Closes a file with some network logging.
-void CloseFile(base::PlatformFile file,
- const net::BoundNetLog& bound_net_log) {
- bound_net_log.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE);
- if (file == base::kInvalidPlatformFileValue)
- return;
+void FileStream::AsyncContext::OpenAsync(
+ const FilePath& path,
+ int open_flags,
+ const CompletionCallback& callback) {
+ DCHECK(!async_in_progress_);
- if (!base::ClosePlatformFile(file))
- NOTREACHED();
- bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
-}
+ BeginOpenEvent(path);
-// Closes a file with CloseFile() and signals the completion.
-void CloseFileAndSignal(base::PlatformFile* file,
- base::WaitableEvent* on_io_complete,
- const net::BoundNetLog& bound_net_log) {
- CloseFile(*file, bound_net_log);
- *file = base::kInvalidPlatformFileValue;
- on_io_complete->Signal();
-}
+ const bool posted = base::PostTaskAndReplyWithResult(
+ base::WorkerPool::GetTaskRunner(true /* task_is_slow */),
+ FROM_HERE,
+ base::Bind(&AsyncContext::OpenFileImpl,
+ base::Unretained(this), path, open_flags),
+ base::Bind(&AsyncContext::OnOpenCompleted,
+ base::Unretained(this), callback));
+ DCHECK(posted);
-// Adjusts the position from where the data is read.
-void SeekFile(base::PlatformFile file,
- Whence whence,
- int64 offset,
- int64* result,
- bool record_uma,
- const net::BoundNetLog& bound_net_log) {
- off_t res = lseek(file, static_cast<off_t>(offset),
- static_cast<int>(whence));
- if (res == static_cast<off_t>(-1)) {
- *result = RecordAndMapError(errno,
- FILE_ERROR_SOURCE_SEEK,
- record_uma,
- bound_net_log);
- return;
- }
- *result = res;
+ async_in_progress_ = true;
}
-// Seeks a file by calling SeekSync() and signals the completion.
-void SeekFileAndSignal(base::PlatformFile file,
- Whence whence,
- int64 offset,
- int64* result,
- bool record_uma,
- base::WaitableEvent* on_io_complete,
- const net::BoundNetLog& bound_net_log) {
- SeekFile(file, whence, offset, result, record_uma, bound_net_log);
- on_io_complete->Signal();
+int FileStream::AsyncContext::OpenSync(const FilePath& path, int open_flags) {
+ BeginOpenEvent(path);
+ int result = OpenFileImpl(path, open_flags);
+ CheckForOpenError(&result);
+ return result;
}
-// ReadFile() is a simple wrapper around read() that handles EINTR signals and
-// calls MapSystemError() to map errno to net error codes.
-void ReadFile(base::PlatformFile file,
- char* buf,
- int buf_len,
- bool record_uma,
- int* result,
- const net::BoundNetLog& bound_net_log) {
- base::ThreadRestrictions::AssertIOAllowed();
- // read(..., 0) returns 0 to indicate end-of-file.
+void FileStream::AsyncContext::CloseAsync(const CompletionCallback& callback) {
+ DCHECK(!async_in_progress_);
- // Loop in the case of getting interrupted by a signal.
- ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
- if (res == -1) {
- res = RecordAndMapError(errno, FILE_ERROR_SOURCE_READ,
- record_uma, bound_net_log);
- }
- *result = res;
-}
+ bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE);
-// Reads a file using ReadFile() and signals the completion.
-void ReadFileAndSignal(base::PlatformFile file,
- scoped_refptr<IOBuffer> buf,
- int buf_len,
- bool record_uma,
- int* result,
- base::WaitableEvent* on_io_complete,
- const net::BoundNetLog& bound_net_log) {
- ReadFile(file, buf->data(), buf_len, record_uma, result, bound_net_log);
- on_io_complete->Signal();
-}
+ if (file_ == base::kInvalidPlatformFileValue) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AsyncContext::OnAsyncCompleted<int>,
+ base::Unretained(this), callback, OK));
+ } else {
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&AsyncContext::CloseFileImpl,
+ base::Unretained(this)),
+ base::Bind(&AsyncContext::OnCloseCompleted,
+ base::Unretained(this), callback),
+ true /* task_is_slow */);
+ DCHECK(posted);
-// WriteFile() is a simple wrapper around write() that handles EINTR signals and
-// calls MapSystemError() to map errno to net error codes. It tries to write to
-// completion.
-void WriteFile(base::PlatformFile file,
- const char* buf,
- int buf_len,
- bool record_uma,
- int* result,
- const net::BoundNetLog& bound_net_log) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
- if (res == -1) {
- res = RecordAndMapError(errno, FILE_ERROR_SOURCE_WRITE, record_uma,
- bound_net_log);
+ async_in_progress_ = true;
}
- *result = res;
}
-// Writes a file using WriteFile() and signals the completion.
-void WriteFileAndSignal(base::PlatformFile file,
- scoped_refptr<IOBuffer> buf,
- int buf_len,
- bool record_uma,
- int* result,
- base::WaitableEvent* on_io_complete,
- const net::BoundNetLog& bound_net_log) {
- WriteFile(file, buf->data(), buf_len, record_uma, result, bound_net_log);
- on_io_complete->Signal();
-}
-
-// FlushFile() is a simple wrapper around fsync() that handles EINTR signals and
-// calls MapSystemError() to map errno to net error codes. It tries to flush to
-// completion.
-int FlushFile(base::PlatformFile file,
- bool record_uma,
- const net::BoundNetLog& bound_net_log) {
- base::ThreadRestrictions::AssertIOAllowed();
- ssize_t res = HANDLE_EINTR(fsync(file));
- if (res == -1) {
- res = RecordAndMapError(errno, FILE_ERROR_SOURCE_FLUSH, record_uma,
- bound_net_log);
+void FileStream::AsyncContext::CloseSync() {
+ DCHECK(!async_in_progress_);
+ bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE);
+ if (file_ != base::kInvalidPlatformFileValue) {
+ CloseFileImpl();
+ bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
}
- return res;
}
-// Called when Read(), Write() or Seek() is completed.
-// |result| contains the result or a network error code.
-template <typename R>
-void OnIOComplete(const base::WeakPtr<FileStreamPosix>& stream,
- const base::Callback<void(R)>& callback,
- R* result) {
- if (!stream.get())
- return;
+void FileStream::AsyncContext::SeekAsync(
+ Whence whence,
+ int64 offset,
+ const Int64CompletionCallback& callback) {
+ DCHECK(!async_in_progress_);
- // Reset this before Run() as Run() may issue a new async operation.
- stream->ResetOnIOComplete();
- callback.Run(*result);
-}
+ const bool posted = base::PostTaskAndReplyWithResult(
+ base::WorkerPool::GetTaskRunner(true /* task is slow */),
+ FROM_HERE,
+ base::Bind(&AsyncContext::SeekFileImpl,
+ base::Unretained(this), whence, offset),
+ base::Bind(&AsyncContext::OnIOCompleted<int64>,
+ base::Unretained(this), callback, FILE_ERROR_SOURCE_SEEK));
+ DCHECK(posted);
-} // namespace
-
-// FileStreamPosix ------------------------------------------------------------
-
-FileStreamPosix::FileStreamPosix(net::NetLog* net_log)
- : file_(base::kInvalidPlatformFileValue),
- open_flags_(0),
- auto_closed_(true),
- record_uma_(false),
- bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)),
- weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
- bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
+ async_in_progress_ = true;
}
-FileStreamPosix::FileStreamPosix(
- base::PlatformFile file, int flags, net::NetLog* net_log)
- : file_(file),
- open_flags_(flags),
- auto_closed_(false),
- record_uma_(false),
- bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)),
- weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
- bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
+int64 FileStream::AsyncContext::SeekSync(Whence whence, int64 offset) {
+ off_t result = SeekFileImpl(whence, offset);
+ CheckForIOError(&result, FILE_ERROR_SOURCE_SEEK);
+ return result;
}
-FileStreamPosix::~FileStreamPosix() {
- if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
- // Block until the last open/close/read/write operation is complete.
- // TODO(satorux): Ideally we should not block. crbug.com/115067
- WaitForIOCompletion();
- }
+int64 FileStream::AsyncContext::GetFileSize() {
+ struct stat info;
+ if (fstat(file_, &info) != 0)
+ return RecordAndMapError(errno, FILE_ERROR_SOURCE_GET_SIZE);
- if (auto_closed_) {
- if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
- // Close the file in the background.
- if (IsOpen()) {
- const bool posted = base::WorkerPool::PostTask(
- FROM_HERE,
- base::Bind(&CloseFile, file_, bound_net_log_),
- true /* task_is_slow */);
- DCHECK(posted);
- }
- } else {
- CloseSync();
- }
- }
-
- bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE);
+ return static_cast<int64>(info.st_size);
}
-void FileStreamPosix::Close(const CompletionCallback& callback) {
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
+int FileStream::AsyncContext::ReadAsync(
+ IOBuffer* in_buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(!async_in_progress_);
- DCHECK(!weak_ptr_factory_.HasWeakPtrs());
- DCHECK(!on_io_complete_.get());
- on_io_complete_.reset(new base::WaitableEvent(
- false /* manual_reset */, false /* initially_signaled */));
-
- // Passing &file_ to a thread pool looks unsafe but it's safe here as the
- // destructor ensures that the close operation is complete with
- // WaitForIOCompletion(). See also the destructor.
- const bool posted = base::WorkerPool::PostTaskAndReply(
+ scoped_refptr<IOBuffer> buf = in_buf;
+ const bool posted = base::PostTaskAndReplyWithResult(
+ base::WorkerPool::GetTaskRunner(true /* task is slow */),
FROM_HERE,
- base::Bind(&CloseFileAndSignal, &file_, on_io_complete_.get(),
- bound_net_log_),
- base::Bind(&FileStreamPosix::OnClosed,
- weak_ptr_factory_.GetWeakPtr(),
- callback),
- true /* task_is_slow */);
-
+ base::Bind(&AsyncContext::ReadFileImpl,
+ base::Unretained(this), buf, buf_len),
+ base::Bind(&AsyncContext::OnIOCompleted<int>,
+ base::Unretained(this), callback, FILE_ERROR_SOURCE_READ));
DCHECK(posted);
+
+ async_in_progress_ = true;
+ return ERR_IO_PENDING;
}
-void FileStreamPosix::CloseSync() {
- // TODO(satorux): Replace the following async stuff with a
- // DCHECK(open_flags & ASYNC) once once all async clients are migrated to
- // use Close(). crbug.com/114783
-
- // Abort any existing asynchronous operations.
- weak_ptr_factory_.InvalidateWeakPtrs();
- // Block until the last open/read/write operation is complete.
- // TODO(satorux): Ideally we should not block. crbug.com/115067
- WaitForIOCompletion();
-
- CloseFile(file_, bound_net_log_);
- file_ = base::kInvalidPlatformFileValue;
+int FileStream::AsyncContext::ReadSync(char* in_buf, int buf_len) {
+ scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf);
+ int result = ReadFileImpl(buf, buf_len);
+ CheckForIOError(&result, FILE_ERROR_SOURCE_READ);
+ return result;
}
-int FileStreamPosix::Open(const FilePath& path, int open_flags,
- const CompletionCallback& callback) {
- if (IsOpen()) {
- DLOG(FATAL) << "File is already open!";
- return ERR_UNEXPECTED;
- }
+int FileStream::AsyncContext::WriteAsync(
+ IOBuffer* in_buf,
+ int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(!async_in_progress_);
- open_flags_ = open_flags;
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
-
- DCHECK(!weak_ptr_factory_.HasWeakPtrs());
- DCHECK(!on_io_complete_.get());
- on_io_complete_.reset(new base::WaitableEvent(
- false /* manual_reset */, false /* initially_signaled */));
-
- // Passing &file_ to a thread pool looks unsafe but it's safe here as the
- // destructor ensures that the open operation is complete with
- // WaitForIOCompletion(). See also the destructor.
- int* result = new int(OK);
- const bool posted = base::WorkerPool::PostTaskAndReply(
+ scoped_refptr<IOBuffer> buf = in_buf;
+ const bool posted = base::PostTaskAndReplyWithResult(
+ base::WorkerPool::GetTaskRunner(true /* task is slow */),
FROM_HERE,
- base::Bind(&OpenFileAndSignal,
- path, open_flags, record_uma_, &file_, result,
- on_io_complete_.get(), bound_net_log_),
- base::Bind(&OnIOComplete<int>, weak_ptr_factory_.GetWeakPtr(),
- callback, base::Owned(result)),
- true /* task_is_slow */);
+ base::Bind(&AsyncContext::WriteFileImpl,
+ base::Unretained(this), buf, buf_len),
+ base::Bind(&AsyncContext::OnIOCompleted<int>,
+ base::Unretained(this), callback, FILE_ERROR_SOURCE_WRITE));
DCHECK(posted);
+
+ async_in_progress_ = true;
return ERR_IO_PENDING;
}
-int FileStreamPosix::OpenSync(const FilePath& path, int open_flags) {
- if (IsOpen()) {
- DLOG(FATAL) << "File is already open!";
- return ERR_UNEXPECTED;
- }
-
- open_flags_ = open_flags;
- // TODO(satorux): Put a DCHECK once once all async clients are migrated
- // to use Open(). crbug.com/114783
- //
- // DCHECK(!(open_flags_ & base::PLATFORM_FILE_ASYNC));
-
- int result = OK;
- OpenFile(path, open_flags_, record_uma_, &file_, &result, bound_net_log_);
+int FileStream::AsyncContext::WriteSync(const char* in_buf, int buf_len) {
+ scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf);
+ int result = WriteFileImpl(buf, buf_len);
+ CheckForIOError(&result, FILE_ERROR_SOURCE_WRITE);
return result;
}
-bool FileStreamPosix::IsOpen() const {
- return file_ != base::kInvalidPlatformFileValue;
+int FileStream::AsyncContext::Flush() {
+ ssize_t res = HANDLE_EINTR(fsync(file_));
+ if (res == -1)
+ res = RecordAndMapError(errno, FILE_ERROR_SOURCE_FLUSH);
+ return res;
}
-int FileStreamPosix::Seek(Whence whence, int64 offset,
- const Int64CompletionCallback& callback) {
- if (!IsOpen())
- return ERR_UNEXPECTED;
+int FileStream::AsyncContext::Truncate(int64 bytes) {
+ int result = ftruncate(file_, bytes);
+ if (result == 0)
+ return bytes;
- // Make sure we're async and we have no other in-flight async operations.
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
- DCHECK(!weak_ptr_factory_.HasWeakPtrs());
- DCHECK(!on_io_complete_.get());
+ return RecordAndMapError(errno, FILE_ERROR_SOURCE_SET_EOF);
+}
- on_io_complete_.reset(new base::WaitableEvent(
- false /* manual_reset */, false /* initially_signaled */));
+int FileStream::AsyncContext::RecordAndMapError(int error,
+ FileErrorSource source) {
+ // The following check is against incorrect use or bug. File descriptor
+ // shouldn't ever be closed outside of FileStream while it still tries to do
+ // something with it.
+ DCHECK(error != EBADF);
+ net::Error net_error = MapSystemError(error);
- int64* result = new int64(-1);
- const bool posted = base::WorkerPool::PostTaskAndReply(
- FROM_HERE,
- base::Bind(&SeekFileAndSignal, file_, whence, offset, result,
- record_uma_, on_io_complete_.get(), bound_net_log_),
- base::Bind(&OnIOComplete<int64>,
- weak_ptr_factory_.GetWeakPtr(),
- callback, base::Owned(result)),
- true /* task is slow */);
- DCHECK(posted);
- return ERR_IO_PENDING;
+ if (!destroyed_) {
+ bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_ERROR,
+ base::Bind(&NetLogFileStreamErrorCallback,
+ source, error, net_error));
+ }
+ RecordFileError(error, source, record_uma_);
+ return net_error;
}
-int64 FileStreamPosix::SeekSync(Whence whence, int64 offset) {
- base::ThreadRestrictions::AssertIOAllowed();
+void FileStream::AsyncContext::BeginOpenEvent(const FilePath& path) {
+ std::string file_name = path.AsUTF8Unsafe();
+ bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_OPEN,
+ NetLog::StringCallback("file_name", &file_name));
+}
- if (!IsOpen())
- return ERR_UNEXPECTED;
+int FileStream::AsyncContext::OpenFileImpl(const FilePath& path,
+ int open_flags) {
+ if (destroyed_)
willchan no longer on Chromium 2012/08/27 06:24:06 Remove this. It's arguably a benign race, but as H
+ return OK;
- // If we're in async, make sure we don't have a request in flight.
- DCHECK(!(open_flags_ & base::PLATFORM_FILE_ASYNC) ||
- !on_io_complete_.get());
+ file_ = base::CreatePlatformFile(path, open_flags, NULL, NULL);
+ if (file_ == base::kInvalidPlatformFileValue)
+ return errno;
- off_t result = -1;
- SeekFile(file_, whence, offset, &result, record_uma_, bound_net_log_);
- return result;
+ return OK;
}
-int64 FileStreamPosix::Available() {
- base::ThreadRestrictions::AssertIOAllowed();
-
- if (!IsOpen())
- return ERR_UNEXPECTED;
-
- int64 cur_pos = SeekSync(FROM_CURRENT, 0);
- if (cur_pos < 0)
- return cur_pos;
-
- struct stat info;
- if (fstat(file_, &info) != 0) {
- return RecordAndMapError(errno,
- FILE_ERROR_SOURCE_GET_SIZE,
- record_uma_,
- bound_net_log_);
+void FileStream::AsyncContext::CheckForOpenError(int* result) {
+ if (file_ == base::kInvalidPlatformFileValue) {
+ bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
+ *result = RecordAndMapError(*result, FILE_ERROR_SOURCE_OPEN);
}
+}
- int64 size = static_cast<int64>(info.st_size);
- DCHECK_GT(size, cur_pos);
-
- return size - cur_pos;
+void FileStream::AsyncContext::OnOpenCompleted(
+ const CompletionCallback& callback,
+ int result) {
+ CheckForOpenError(&result);
+ OnAsyncCompleted(callback, result);
}
-int FileStreamPosix::Read(
- IOBuffer* in_buf, int buf_len, const CompletionCallback& callback) {
- if (!IsOpen())
- return ERR_UNEXPECTED;
-
- // read(..., 0) will return 0, which indicates end-of-file.
- DCHECK_GT(buf_len, 0);
- DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
-
- // Make sure we don't have a request in flight.
- DCHECK(!weak_ptr_factory_.HasWeakPtrs());
- DCHECK(!on_io_complete_.get());
-
- on_io_complete_.reset(new base::WaitableEvent(
- false /* manual_reset */, false /* initially_signaled */));
-
- int* result = new int(OK);
- scoped_refptr<IOBuffer> buf = in_buf;
- const bool posted = base::WorkerPool::PostTaskAndReply(
- FROM_HERE,
- base::Bind(&ReadFileAndSignal, file_, buf, buf_len,
- record_uma_, result, on_io_complete_.get(), bound_net_log_),
- base::Bind(&OnIOComplete<int>,
- weak_ptr_factory_.GetWeakPtr(),
- callback, base::Owned(result)),
- true /* task is slow */);
- DCHECK(posted);
- return ERR_IO_PENDING;
+void FileStream::AsyncContext::CloseFileImpl() {
+ if (!base::ClosePlatformFile(file_))
+ NOTREACHED();
+ file_ = base::kInvalidPlatformFileValue;
}
-int FileStreamPosix::ReadSync(char* buf, int buf_len) {
- if (!IsOpen())
- return ERR_UNEXPECTED;
-
- DCHECK(!(open_flags_ & base::PLATFORM_FILE_ASYNC));
- // read(..., 0) will return 0, which indicates end-of-file.
- DCHECK_GT(buf_len, 0);
- DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
-
- int result = OK;
- ReadFile(file_, buf, buf_len, record_uma_, &result, bound_net_log_);
- return result;
+void FileStream::AsyncContext::OnCloseCompleted(
+ const CompletionCallback& callback) {
+ if (!destroyed_)
+ bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN);
+ OnAsyncCompleted(callback, static_cast<int>(OK));
}
-int FileStreamPosix::ReadUntilComplete(char *buf, int buf_len) {
- int to_read = buf_len;
- int bytes_total = 0;
+int64 FileStream::AsyncContext::SeekFileImpl(Whence whence, int64 offset) {
+ base::ThreadRestrictions::AssertIOAllowed();
- do {
- int bytes_read = ReadSync(buf, to_read);
- if (bytes_read <= 0) {
- if (bytes_total == 0)
- return bytes_read;
+ // If context has been already destroyed nobody waits for operation results.
+ if (destroyed_)
+ return 0;
- return bytes_total;
- }
+ off_t res = lseek(file_, static_cast<off_t>(offset),
+ static_cast<int>(whence));
+ if (res == static_cast<off_t>(-1))
+ return errno;
- bytes_total += bytes_read;
- buf += bytes_read;
- to_read -= bytes_read;
- } while (bytes_total < buf_len);
-
- return bytes_total;
+ return res;
}
-int FileStreamPosix::Write(
- IOBuffer* in_buf, int buf_len, const CompletionCallback& callback) {
- if (!IsOpen())
- return ERR_UNEXPECTED;
+int FileStream::AsyncContext::ReadFileImpl(scoped_refptr<IOBuffer> buf,
+ int buf_len) {
+ base::ThreadRestrictions::AssertIOAllowed();
- DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
- DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
- // write(..., 0) will return 0, which indicates end-of-file.
- DCHECK_GT(buf_len, 0);
+ // If context has been already destroyed nobody waits for operation results.
+ if (destroyed_)
+ return OK;
- // Make sure we don't have a request in flight.
- DCHECK(!weak_ptr_factory_.HasWeakPtrs());
- DCHECK(!on_io_complete_.get());
- on_io_complete_.reset(new base::WaitableEvent(
- false /* manual_reset */, false /* initially_signaled */));
+ // Loop in the case of getting interrupted by a signal.
+ ssize_t res = HANDLE_EINTR(read(file_, buf->data(),
+ static_cast<size_t>(buf_len)));
+ if (res == -1)
+ return errno;
- int* result = new int(OK);
- scoped_refptr<IOBuffer> buf = in_buf;
- const bool posted = base::WorkerPool::PostTaskAndReply(
- FROM_HERE,
- base::Bind(&WriteFileAndSignal, file_, buf, buf_len,
- record_uma_, result, on_io_complete_.get(), bound_net_log_),
- base::Bind(&OnIOComplete<int>,
- weak_ptr_factory_.GetWeakPtr(),
- callback, base::Owned(result)),
- true /* task is slow */);
- DCHECK(posted);
- return ERR_IO_PENDING;
+ return res;
}
-int FileStreamPosix::WriteSync(
- const char* buf, int buf_len) {
- if (!IsOpen())
- return ERR_UNEXPECTED;
-
- DCHECK(!(open_flags_ & base::PLATFORM_FILE_ASYNC));
- DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
- // write(..., 0) will return 0, which indicates end-of-file.
- DCHECK_GT(buf_len, 0);
-
- int result = OK;
- WriteFile(file_, buf, buf_len, record_uma_, &result, bound_net_log_);
- return result;
-}
-
-int64 FileStreamPosix::Truncate(int64 bytes) {
+int FileStream::AsyncContext::WriteFileImpl(scoped_refptr<IOBuffer> buf,
+ int buf_len) {
base::ThreadRestrictions::AssertIOAllowed();
- if (!IsOpen())
- return ERR_UNEXPECTED;
+ // If context has been already destroyed nobody waits for operation results.
+ if (destroyed_)
+ return OK;
- // We'd better be open for writing.
- DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
+ ssize_t res = HANDLE_EINTR(write(file_, buf->data(), buf_len));
+ if (res == -1)
+ return errno;
- // Seek to the position to truncate from.
- int64 seek_position = SeekSync(FROM_BEGIN, bytes);
- if (seek_position != bytes)
- return ERR_UNEXPECTED;
-
- // And truncate the file.
- int result = ftruncate(file_, bytes);
- if (result == 0)
- return seek_position;
-
- return RecordAndMapError(errno,
- FILE_ERROR_SOURCE_SET_EOF,
- record_uma_,
- bound_net_log_);
+ return res;
}
-int FileStreamPosix::Flush() {
- if (!IsOpen())
- return ERR_UNEXPECTED;
-
- return FlushFile(file_, record_uma_, bound_net_log_);
+template <typename R>
+void FileStream::AsyncContext::CheckForIOError(R* result,
+ FileErrorSource source) {
+ if (*result < 0)
+ *result = RecordAndMapError(static_cast<int>(*result), source);
}
-void FileStreamPosix::EnableErrorStatistics() {
- record_uma_ = true;
+template <typename R>
+void FileStream::AsyncContext::OnIOCompleted(
+ const base::Callback<void(R)>& callback,
+ FileErrorSource source,
+ R result) {
+ CheckForIOError(&result, source);
+ OnAsyncCompleted(callback, result);
}
-void FileStreamPosix::SetBoundNetLogSource(
- const net::BoundNetLog& owner_bound_net_log) {
- if ((owner_bound_net_log.source().id == net::NetLog::Source::kInvalidId) &&
- (bound_net_log_.source().id == net::NetLog::Source::kInvalidId)) {
- // Both |BoundNetLog|s are invalid.
- return;
+template <typename R>
+void FileStream::AsyncContext::OnAsyncCompleted(
+ const base::Callback<void(R)>& callback,
+ R result) {
+ if (destroyed_) {
willchan no longer on Chromium 2012/08/27 06:24:06 Change this to: if (orphaned_) { delete this; }
+ DeleteAbandoned();
+ } else {
+ // Reset this before Run() as Run() may issue a new async operation.
+ async_in_progress_ = false;
+ callback.Run(result);
}
-
- // Should never connect to itself.
- DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);
-
- bound_net_log_.AddEvent(
- net::NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
- owner_bound_net_log.source().ToEventParametersCallback());
-
- owner_bound_net_log.AddEvent(
- net::NetLog::TYPE_FILE_STREAM_SOURCE,
- bound_net_log_.source().ToEventParametersCallback());
}
-base::PlatformFile FileStreamPosix::GetPlatformFileForTesting() {
- return file_;
-}
-
-void FileStreamPosix::ResetOnIOComplete() {
- on_io_complete_.reset();
- weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
-void FileStreamPosix::OnClosed(const CompletionCallback& callback) {
- file_ = base::kInvalidPlatformFileValue;
-
- // Reset this before Run() as Run() may issue a new async operation.
- ResetOnIOComplete();
- callback.Run(OK);
-}
-
-void FileStreamPosix::WaitForIOCompletion() {
- // http://crbug.com/115067
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- if (on_io_complete_.get()) {
- on_io_complete_->Wait();
- on_io_complete_.reset();
+void FileStream::AsyncContext::DeleteAbandoned() {
willchan no longer on Chromium 2012/08/27 06:24:06 One good thing about removing DeleteAbandoned is t
pivanof 2012/08/27 08:43:31 I don't follow. There are DCHECKs everywhere to en
willchan no longer on Chromium 2012/09/05 00:03:38 You're right, there should not be multiple async o
+ if (file_ != base::kInvalidPlatformFileValue) {
+ const bool posted = base::WorkerPool::PostTask(
+ FROM_HERE,
+ // Context should be deleted after closing, thus Owned().
+ base::Bind(&AsyncContext::CloseFileImpl, base::Owned(this)),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ } else {
+ delete this;
}
}

Powered by Google App Engine
This is Rietveld 408576698