| 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..97b1975535c0b05fdcdf03cfe5383c937740cda3 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 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() {
 | 
| 
 |