Roll src/third_party/skia f16c00e:f89f60f
[chromium-blink-merge.git] / net / base / file_stream_context_win.cc
blob5ffbde72388293a339e46430846f4be6df62695c
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
3 // found in the LICENSE file.
5 #include "net/base/file_stream_context.h"
7 #include <windows.h>
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/metrics/histogram.h"
14 #include "base/task_runner.h"
15 #include "base/threading/worker_pool.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
19 namespace net {
21 namespace {
23 void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
24 overlapped->Offset = offset.LowPart;
25 overlapped->OffsetHigh = offset.HighPart;
28 void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
29 LARGE_INTEGER offset;
30 offset.LowPart = overlapped->Offset;
31 offset.HighPart = overlapped->OffsetHigh;
32 offset.QuadPart += static_cast<LONGLONG>(count);
33 SetOffset(overlapped, offset);
36 } // namespace
38 FileStream::Context::Context(const scoped_refptr<base::TaskRunner>& task_runner)
39 : io_context_(),
40 async_in_progress_(false),
41 orphaned_(false),
42 task_runner_(task_runner),
43 async_read_initiated_(false),
44 async_read_completed_(false),
45 io_complete_for_read_received_(false),
46 result_(0) {
47 io_context_.handler = this;
48 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
51 FileStream::Context::Context(base::File file,
52 const scoped_refptr<base::TaskRunner>& task_runner)
53 : io_context_(),
54 file_(file.Pass()),
55 async_in_progress_(false),
56 orphaned_(false),
57 task_runner_(task_runner),
58 async_read_initiated_(false),
59 async_read_completed_(false),
60 io_complete_for_read_received_(false),
61 result_(0) {
62 io_context_.handler = this;
63 memset(&io_context_.overlapped, 0, sizeof(io_context_.overlapped));
64 if (file_.IsValid()) {
65 // TODO(hashimoto): Check that file_ is async.
66 OnFileOpened();
70 FileStream::Context::~Context() {
73 int FileStream::Context::Read(IOBuffer* buf,
74 int buf_len,
75 const CompletionCallback& callback) {
76 CHECK(!async_in_progress_);
77 DCHECK(!async_read_initiated_);
78 DCHECK(!async_read_completed_);
79 DCHECK(!io_complete_for_read_received_);
81 IOCompletionIsPending(callback, buf);
83 async_read_initiated_ = true;
85 task_runner_->PostTask(
86 FROM_HERE,
87 base::Bind(&FileStream::Context::ReadAsync, base::Unretained(this),
88 file_.GetPlatformFile(), make_scoped_refptr(buf), buf_len,
89 &io_context_.overlapped,
90 base::MessageLoop::current()->message_loop_proxy()));
91 return ERR_IO_PENDING;
94 int FileStream::Context::Write(IOBuffer* buf,
95 int buf_len,
96 const CompletionCallback& callback) {
97 CHECK(!async_in_progress_);
99 DWORD bytes_written = 0;
100 if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
101 &bytes_written, &io_context_.overlapped)) {
102 IOResult error = IOResult::FromOSError(GetLastError());
103 if (error.os_error == ERROR_IO_PENDING)
104 IOCompletionIsPending(callback, buf);
105 else
106 LOG(WARNING) << "WriteFile failed: " << error.os_error;
107 return static_cast<int>(error.result);
110 IOCompletionIsPending(callback, buf);
111 return ERR_IO_PENDING;
114 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
115 base::File::Whence whence,
116 int64 offset) {
117 LARGE_INTEGER result;
118 result.QuadPart = file_.Seek(whence, offset);
119 if (result.QuadPart >= 0) {
120 SetOffset(&io_context_.overlapped, result);
121 return IOResult(result.QuadPart, 0);
124 return IOResult::FromOSError(GetLastError());
127 void FileStream::Context::OnFileOpened() {
128 base::MessageLoopForIO::current()->RegisterIOHandler(file_.GetPlatformFile(),
129 this);
132 void FileStream::Context::IOCompletionIsPending(
133 const CompletionCallback& callback,
134 IOBuffer* buf) {
135 DCHECK(callback_.is_null());
136 callback_ = callback;
137 in_flight_buf_ = buf; // Hold until the async operation ends.
138 async_in_progress_ = true;
141 void FileStream::Context::OnIOCompleted(
142 base::MessageLoopForIO::IOContext* context,
143 DWORD bytes_read,
144 DWORD error) {
145 DCHECK_EQ(&io_context_, context);
146 DCHECK(!callback_.is_null());
147 DCHECK(async_in_progress_);
149 if (!async_read_initiated_)
150 async_in_progress_ = false;
152 if (orphaned_) {
153 async_in_progress_ = false;
154 callback_.Reset();
155 in_flight_buf_ = NULL;
156 CloseAndDelete();
157 return;
160 if (error == ERROR_HANDLE_EOF) {
161 result_ = 0;
162 } else if (error) {
163 IOResult error_result = IOResult::FromOSError(error);
164 result_ = static_cast<int>(error_result.result);
165 } else {
166 result_ = bytes_read;
167 IncrementOffset(&io_context_.overlapped, bytes_read);
170 if (async_read_initiated_)
171 io_complete_for_read_received_ = true;
173 InvokeUserCallback();
176 void FileStream::Context::InvokeUserCallback() {
177 // For an asynchonous Read operation don't invoke the user callback until
178 // we receive the IO completion notification and the asynchronous Read
179 // completion notification.
180 if (async_read_initiated_) {
181 if (!io_complete_for_read_received_ || !async_read_completed_)
182 return;
183 async_read_initiated_ = false;
184 io_complete_for_read_received_ = false;
185 async_read_completed_ = false;
186 async_in_progress_ = false;
188 CompletionCallback temp_callback = callback_;
189 callback_.Reset();
190 scoped_refptr<IOBuffer> temp_buf = in_flight_buf_;
191 in_flight_buf_ = NULL;
192 temp_callback.Run(result_);
195 // static
196 void FileStream::Context::ReadAsync(
197 FileStream::Context* context,
198 HANDLE file,
199 scoped_refptr<net::IOBuffer> buf,
200 int buf_len,
201 OVERLAPPED* overlapped,
202 scoped_refptr<base::MessageLoopProxy> origin_thread_loop) {
203 DWORD bytes_read = 0;
204 BOOL ret = ::ReadFile(file, buf->data(), buf_len, &bytes_read, overlapped);
205 origin_thread_loop->PostTask(
206 FROM_HERE, base::Bind(&FileStream::Context::ReadAsyncResult,
207 base::Unretained(context), ret ? bytes_read : 0,
208 ret ? 0 : ::GetLastError()));
211 void FileStream::Context::ReadAsyncResult(DWORD bytes_read, DWORD os_error) {
212 if (!os_error)
213 result_ = bytes_read;
215 IOResult error = IOResult::FromOSError(os_error);
216 if (error.os_error == ERROR_HANDLE_EOF) {
217 // Report EOF by returning 0 bytes read.
218 OnIOCompleted(&io_context_, 0, error.os_error);
219 } else if (error.os_error != ERROR_IO_PENDING) {
220 // We don't need to inform the caller about ERROR_PENDING_IO as that was
221 // already done when the ReadFile call was queued to the worker pool.
222 if (error.os_error) {
223 LOG(WARNING) << "ReadFile failed: " << error.os_error;
224 OnIOCompleted(&io_context_, 0, error.os_error);
227 async_read_completed_ = true;
228 InvokeUserCallback();
231 } // namespace net