Chromium Code Reviews| Index: net/base/file_stream_win.cc | 
| diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc | 
| index 713e4885a5931c8d1799b820ecf41ea5e5fb83d0..9f771fdea1f74a0c73d97db1db55e01646737c40 100644 | 
| --- a/net/base/file_stream_win.cc | 
| +++ b/net/base/file_stream_win.cc | 
| @@ -10,6 +10,7 @@ | 
| #include "base/logging.h" | 
| #include "base/message_loop.h" | 
| #include "base/metrics/histogram.h" | 
| +#include "base/synchronization/waitable_event.h" | 
| #include "base/threading/thread_restrictions.h" | 
| #include "base/threading/worker_pool.h" | 
| #include "net/base/file_stream_metrics.h" | 
| @@ -24,12 +25,14 @@ COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); | 
| COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); | 
| COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); | 
| -static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { | 
| +namespace { | 
| + | 
| +void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { | 
| overlapped->Offset = offset.LowPart; | 
| overlapped->OffsetHigh = offset.HighPart; | 
| } | 
| -static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { | 
| +void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { | 
| LARGE_INTEGER offset; | 
| offset.LowPart = overlapped->Offset; | 
| offset.HighPart = overlapped->OffsetHigh; | 
| @@ -37,8 +40,6 @@ static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { | 
| SetOffset(overlapped, offset); | 
| } | 
| -namespace { | 
| - | 
| int RecordAndMapError(int error, | 
| FileErrorSource source, | 
| bool record_uma, | 
| @@ -84,18 +85,6 @@ void OpenFile(const FilePath& path, | 
| } | 
| } | 
| -// Opens a file using OpenFile() and 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(); | 
| -} | 
| - | 
| // Closes a file with some network logging. | 
| void CloseFile(base::PlatformFile file, | 
| const net::BoundNetLog& bound_net_log) { | 
| @@ -119,6 +108,13 @@ void CloseFileAndSignal(base::PlatformFile* file, | 
| on_io_complete->Signal(); | 
| } | 
| +// Invokes a given closure and signals the completion. | 
| +void InvokeAndSignal(const base::Closure& closure, | 
| + base::WaitableEvent* on_io_complete) { | 
| + closure.Run(); | 
| + on_io_complete->Signal(); | 
| +} | 
| + | 
| } // namespace | 
| // FileStreamWin::AsyncContext ---------------------------------------------- | 
| @@ -270,11 +266,8 @@ FileStreamWin::~FileStreamWin() { | 
| } | 
| void FileStreamWin::Close(const CompletionCallback& callback) { | 
| - DCHECK(callback_.is_null()); | 
| - callback_ = callback; | 
| - | 
| 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 */)); | 
| @@ -286,7 +279,9 @@ void FileStreamWin::Close(const CompletionCallback& callback) { | 
| FROM_HERE, | 
| base::Bind(&CloseFileAndSignal, &file_, on_io_complete_.get(), | 
| bound_net_log_), | 
| - base::Bind(&FileStreamWin::OnClosed, weak_ptr_factory_.GetWeakPtr()), | 
| + base::Bind(&FileStreamWin::OnClosed, | 
| + weak_ptr_factory_.GetWeakPtr(), | 
| + callback), | 
| true /* task_is_slow */); | 
| DCHECK(posted); | 
| } | 
| @@ -323,12 +318,9 @@ int FileStreamWin::Open(const FilePath& path, int open_flags, | 
| return ERR_UNEXPECTED; | 
| } | 
| - DCHECK(callback_.is_null()); | 
| - callback_ = callback; | 
| - | 
| 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 */)); | 
| @@ -339,12 +331,13 @@ int FileStreamWin::Open(const FilePath& path, int open_flags, | 
| int* result = new int(OK); | 
| const bool posted = base::WorkerPool::PostTaskAndReply( | 
| FROM_HERE, | 
| - base::Bind(&OpenFileAndSignal, | 
| - path, open_flags, record_uma_, &file_, result, | 
| - on_io_complete_.get(), bound_net_log_), | 
| + base::Bind(&InvokeAndSignal, | 
| + base::Bind(&OpenFile, path, open_flags, record_uma_, &file_, | 
| + result, bound_net_log_), | 
| + on_io_complete_.get()), | 
| base::Bind(&FileStreamWin::OnOpened, | 
| weak_ptr_factory_.GetWeakPtr(), | 
| - base::Owned(result)), | 
| + callback, base::Owned(result)), | 
| true /* task_is_slow */); | 
| DCHECK(posted); | 
| return ERR_IO_PENDING; | 
| @@ -380,28 +373,44 @@ bool FileStreamWin::IsOpen() const { | 
| return file_ != base::kInvalidPlatformFileValue; | 
| } | 
| -int64 FileStreamWin::Seek(Whence whence, int64 offset) { | 
| +int FileStreamWin::Seek(Whence whence, int64 offset, | 
| + const Int64CompletionCallback& callback) { | 
| if (!IsOpen()) | 
| return ERR_UNEXPECTED; | 
| - DCHECK(!async_context_.get() || async_context_->callback().is_null()); | 
| + // 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()); | 
| - LARGE_INTEGER distance, result; | 
| - distance.QuadPart = offset; | 
| - DWORD move_method = static_cast<DWORD>(whence); | 
| - if (!SetFilePointerEx(file_, distance, &result, move_method)) { | 
| - DWORD error = GetLastError(); | 
| - LOG(WARNING) << "SetFilePointerEx failed: " << error; | 
| - return RecordAndMapError(error, | 
| - FILE_ERROR_SOURCE_SEEK, | 
| - record_uma_, | 
| - bound_net_log_); | 
| - } | 
| - if (async_context_.get()) { | 
| - async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK); | 
| - SetOffset(async_context_->overlapped(), result); | 
| - } | 
| - return result.QuadPart; | 
| + int64* result = new int64(-1); | 
| + on_io_complete_.reset(new base::WaitableEvent( | 
| + false /* manual_reset */, false /* initially_signaled */)); | 
| + | 
| + const bool posted = base::WorkerPool::PostTaskAndReply( | 
| + FROM_HERE, | 
| + base::Bind(&InvokeAndSignal, | 
| + // Unretained should be fine as we wait signal on | 
| 
 
willchan no longer on Chromium
2012/04/10 06:48:33
Nit: s/we wait signal on/we wait for a signal on/
 
 | 
| + // on_io_complete_ at the destructor. | 
| + base::Bind(&FileStreamWin::SeekFile, base::Unretained(this), | 
| + whence, offset, result), | 
| + on_io_complete_.get()), | 
| + base::Bind(&FileStreamWin::OnSeeked, | 
| + weak_ptr_factory_.GetWeakPtr(), | 
| + callback, base::Owned(result)), | 
| + true /* task is slow */); | 
| + DCHECK(posted); | 
| + return ERR_IO_PENDING; | 
| +} | 
| + | 
| +int64 FileStreamWin::SeekSync(Whence whence, int64 offset) { | 
| + if (!IsOpen()) | 
| + return ERR_UNEXPECTED; | 
| + | 
| + DCHECK(!async_context_.get() || async_context_->callback().is_null()); | 
| + int64 result = -1; | 
| + SeekFile(whence, offset, &result); | 
| + return result; | 
| } | 
| int64 FileStreamWin::Available() { | 
| @@ -410,7 +419,7 @@ int64 FileStreamWin::Available() { | 
| if (!IsOpen()) | 
| return ERR_UNEXPECTED; | 
| - int64 cur_pos = Seek(FROM_CURRENT, 0); | 
| + int64 cur_pos = SeekSync(FROM_CURRENT, 0); | 
| if (cur_pos < 0) | 
| return cur_pos; | 
| @@ -608,7 +617,7 @@ int64 FileStreamWin::Truncate(int64 bytes) { | 
| DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 
| // Seek to the position to truncate from. | 
| - int64 seek_position = Seek(FROM_BEGIN, bytes); | 
| + int64 seek_position = SeekSync(FROM_BEGIN, bytes); | 
| if (seek_position != bytes) | 
| return ERR_UNEXPECTED; | 
| @@ -662,19 +671,35 @@ base::PlatformFile FileStreamWin::GetPlatformFileForTesting() { | 
| return file_; | 
| } | 
| -void FileStreamWin::OnClosed() { | 
| +void FileStreamWin::OnClosed(const CompletionCallback& callback) { | 
| file_ = base::kInvalidPlatformFileValue; | 
| - CompletionCallback temp = callback_; | 
| - callback_.Reset(); | 
| + // Reset this before Run() as Run() may issue a new async operation. | 
| + ResetOnIOComplete(); | 
| + callback.Run(OK); | 
| +} | 
| - // Reset this before Run(). Run() should not issue a new async operation | 
| - // here, but just to keep it consistent with OnOpened(). | 
| - on_io_complete_.reset(); | 
| - temp.Run(OK); | 
| +void FileStreamWin::SeekFile(Whence whence, int64 offset, int64* result) { | 
| + LARGE_INTEGER distance, res; | 
| + distance.QuadPart = offset; | 
| + DWORD move_method = static_cast<DWORD>(whence); | 
| + if (!SetFilePointerEx(file_, distance, &res, move_method)) { | 
| + DWORD error = GetLastError(); | 
| + LOG(WARNING) << "SetFilePointerEx failed: " << error; | 
| + *result = RecordAndMapError(error, | 
| + FILE_ERROR_SOURCE_SEEK, | 
| + record_uma_, | 
| + bound_net_log_); | 
| + return; | 
| + } | 
| + if (async_context_.get()) { | 
| + async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK); | 
| + SetOffset(async_context_->overlapped(), res); | 
| + } | 
| + *result = res.QuadPart; | 
| } | 
| -void FileStreamWin::OnOpened(int* result) { | 
| +void FileStreamWin::OnOpened(const CompletionCallback& callback, int* result) { | 
| if (*result == OK) { | 
| async_context_.reset(new AsyncContext(bound_net_log_)); | 
| if (record_uma_) | 
| @@ -683,12 +708,22 @@ void FileStreamWin::OnOpened(int* result) { | 
| async_context_.get()); | 
| } | 
| - CompletionCallback temp = callback_; | 
| - callback_.Reset(); | 
| + // Reset this before Run() as Run() may issue a new async operation. | 
| + ResetOnIOComplete(); | 
| + callback.Run(*result); | 
| +} | 
| +void FileStreamWin::OnSeeked( | 
| + const Int64CompletionCallback& callback, | 
| + int64* result) { | 
| // Reset this before Run() as Run() may issue a new async operation. | 
| + ResetOnIOComplete(); | 
| + callback.Run(*result); | 
| +} | 
| + | 
| +void FileStreamWin::ResetOnIOComplete() { | 
| on_io_complete_.reset(); | 
| - temp.Run(*result); | 
| + weak_ptr_factory_.InvalidateWeakPtrs(); | 
| } | 
| void FileStreamWin::WaitForIOCompletion() { |