OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // LICENSE file. |
4 | 4 |
5 #include "net/base/file_stream.h" | 5 #include "net/base/file_stream.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 43 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; |
44 return ERR_FAILED; | 44 return ERR_FAILED; |
45 } | 45 } |
46 } | 46 } |
47 | 47 |
48 // FileStream::AsyncContext ---------------------------------------------- | 48 // FileStream::AsyncContext ---------------------------------------------- |
49 | 49 |
50 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { | 50 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { |
51 public: | 51 public: |
52 AsyncContext(FileStream* owner) | 52 AsyncContext(FileStream* owner) |
53 : owner_(owner), overlapped_(), callback_(NULL) { | 53 : owner_(owner), context_(), callback_(NULL) { |
54 overlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | 54 context_.handler = this; |
55 } | 55 } |
56 | 56 ~AsyncContext(); |
57 ~AsyncContext() { | |
58 if (callback_) | |
59 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL); | |
60 CloseHandle(overlapped_.hEvent); | |
61 } | |
62 | 57 |
63 void IOCompletionIsPending(CompletionCallback* callback); | 58 void IOCompletionIsPending(CompletionCallback* callback); |
64 | 59 |
65 OVERLAPPED* overlapped() { return &overlapped_; } | 60 OVERLAPPED* overlapped() { return &context_.overlapped; } |
66 CompletionCallback* callback() const { return callback_; } | 61 CompletionCallback* callback() const { return callback_; } |
67 | 62 |
68 private: | 63 private: |
69 // MessageLoopForIO::IOHandler implementation: | 64 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, |
70 virtual void OnIOCompleted(OVERLAPPED* context, DWORD num_bytes, | 65 DWORD bytes_read, DWORD error); |
71 DWORD error); | |
72 | 66 |
73 FileStream* owner_; | 67 FileStream* owner_; |
74 OVERLAPPED overlapped_; | 68 MessageLoopForIO::IOContext context_; |
75 CompletionCallback* callback_; | 69 CompletionCallback* callback_; |
76 }; | 70 }; |
77 | 71 |
| 72 FileStream::AsyncContext::~AsyncContext() { |
| 73 bool waited = false; |
| 74 base::Time start = base::Time::Now(); |
| 75 while (callback_) { |
| 76 waited = true; |
| 77 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); |
| 78 } |
| 79 if (waited) { |
| 80 // We want to see if we block the message loop for too long. |
| 81 UMA_HISTOGRAM_TIMES(L"AsyncIO.FileStreamClose", base::Time::Now() - start); |
| 82 } |
| 83 } |
| 84 |
78 void FileStream::AsyncContext::IOCompletionIsPending( | 85 void FileStream::AsyncContext::IOCompletionIsPending( |
79 CompletionCallback* callback) { | 86 CompletionCallback* callback) { |
80 DCHECK(!callback_); | 87 DCHECK(!callback_); |
81 callback_ = callback; | 88 callback_ = callback; |
82 | |
83 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, this); | |
84 } | 89 } |
85 | 90 |
86 void FileStream::AsyncContext::OnIOCompleted(OVERLAPPED* context, | 91 void FileStream::AsyncContext::OnIOCompleted( |
87 DWORD num_bytes, | 92 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) { |
88 DWORD error) { | 93 DCHECK(&context_ == context); |
89 DCHECK(&overlapped_ == context); | |
90 DCHECK(callback_); | 94 DCHECK(callback_); |
91 | 95 |
92 MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL); | 96 int result = static_cast<int>(bytes_read); |
93 | |
94 HANDLE handle = owner_->file_; | |
95 | |
96 int result = static_cast<int>(num_bytes); | |
97 if (error && error != ERROR_HANDLE_EOF) | 97 if (error && error != ERROR_HANDLE_EOF) |
98 result = MapErrorCode(error); | 98 result = MapErrorCode(error); |
99 | 99 |
100 if (num_bytes) | 100 if (bytes_read) |
101 IncrementOffset(&overlapped_, num_bytes); | 101 IncrementOffset(&context->overlapped, bytes_read); |
102 | 102 |
103 CompletionCallback* temp = NULL; | 103 CompletionCallback* temp = NULL; |
104 std::swap(temp, callback_); | 104 std::swap(temp, callback_); |
105 temp->Run(result); | 105 temp->Run(result); |
106 } | 106 } |
107 | 107 |
108 // FileStream ------------------------------------------------------------ | 108 // FileStream ------------------------------------------------------------ |
109 | 109 |
110 FileStream::FileStream() : file_(INVALID_HANDLE_VALUE) { | 110 FileStream::FileStream() : file_(INVALID_HANDLE_VALUE) { |
111 } | 111 } |
112 | 112 |
113 FileStream::~FileStream() { | 113 FileStream::~FileStream() { |
114 Close(); | 114 Close(); |
115 } | 115 } |
116 | 116 |
117 void FileStream::Close() { | 117 void FileStream::Close() { |
| 118 if (file_ != INVALID_HANDLE_VALUE) |
| 119 CancelIo(file_); |
| 120 |
| 121 async_context_.reset(); |
118 if (file_ != INVALID_HANDLE_VALUE) { | 122 if (file_ != INVALID_HANDLE_VALUE) { |
119 CloseHandle(file_); | 123 CloseHandle(file_); |
120 file_ = INVALID_HANDLE_VALUE; | 124 file_ = INVALID_HANDLE_VALUE; |
121 } | 125 } |
122 async_context_.reset(); | |
123 } | 126 } |
124 | 127 |
125 int FileStream::Open(const std::wstring& path, int open_flags) { | 128 int FileStream::Open(const std::wstring& path, int open_flags) { |
126 if (IsOpen()) { | 129 if (IsOpen()) { |
127 DLOG(FATAL) << "File is already open!"; | 130 DLOG(FATAL) << "File is already open!"; |
128 return ERR_UNEXPECTED; | 131 return ERR_UNEXPECTED; |
129 } | 132 } |
130 | 133 |
131 open_flags_ = open_flags; | 134 open_flags_ = open_flags; |
132 file_ = base::CreatePlatformFile(path, open_flags_, NULL); | 135 file_ = base::CreatePlatformFile(path, open_flags_, NULL); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 DWORD error = GetLastError(); | 207 DWORD error = GetLastError(); |
205 if (async_context_.get() && error == ERROR_IO_PENDING) { | 208 if (async_context_.get() && error == ERROR_IO_PENDING) { |
206 async_context_->IOCompletionIsPending(callback); | 209 async_context_->IOCompletionIsPending(callback); |
207 rv = ERR_IO_PENDING; | 210 rv = ERR_IO_PENDING; |
208 } else if (error == ERROR_HANDLE_EOF) { | 211 } else if (error == ERROR_HANDLE_EOF) { |
209 rv = 0; // Report EOF by returning 0 bytes read. | 212 rv = 0; // Report EOF by returning 0 bytes read. |
210 } else { | 213 } else { |
211 LOG(WARNING) << "ReadFile failed: " << error; | 214 LOG(WARNING) << "ReadFile failed: " << error; |
212 rv = MapErrorCode(error); | 215 rv = MapErrorCode(error); |
213 } | 216 } |
| 217 } else if (overlapped) { |
| 218 async_context_->IOCompletionIsPending(callback); |
| 219 rv = ERR_IO_PENDING; |
214 } else { | 220 } else { |
215 if (overlapped) | |
216 IncrementOffset(overlapped, bytes_read); | |
217 rv = static_cast<int>(bytes_read); | 221 rv = static_cast<int>(bytes_read); |
218 } | 222 } |
219 return rv; | 223 return rv; |
220 } | 224 } |
221 | 225 |
222 int FileStream::Write( | 226 int FileStream::Write( |
223 const char* buf, int buf_len, CompletionCallback* callback) { | 227 const char* buf, int buf_len, CompletionCallback* callback) { |
224 if (!IsOpen()) | 228 if (!IsOpen()) |
225 return ERR_UNEXPECTED; | 229 return ERR_UNEXPECTED; |
226 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 230 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
227 | 231 |
228 OVERLAPPED* overlapped = NULL; | 232 OVERLAPPED* overlapped = NULL; |
229 if (async_context_.get()) { | 233 if (async_context_.get()) { |
230 DCHECK(!async_context_->callback()); | 234 DCHECK(!async_context_->callback()); |
231 overlapped = async_context_->overlapped(); | 235 overlapped = async_context_->overlapped(); |
232 } | 236 } |
233 | 237 |
234 int rv; | 238 int rv; |
235 DWORD bytes_written; | 239 DWORD bytes_written; |
236 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { | 240 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { |
237 DWORD error = GetLastError(); | 241 DWORD error = GetLastError(); |
238 if (async_context_.get() && error == ERROR_IO_PENDING) { | 242 if (async_context_.get() && error == ERROR_IO_PENDING) { |
239 async_context_->IOCompletionIsPending(callback); | 243 async_context_->IOCompletionIsPending(callback); |
240 rv = ERR_IO_PENDING; | 244 rv = ERR_IO_PENDING; |
241 } else { | 245 } else { |
242 LOG(WARNING) << "WriteFile failed: " << error; | 246 LOG(WARNING) << "WriteFile failed: " << error; |
243 rv = MapErrorCode(error); | 247 rv = MapErrorCode(error); |
244 } | 248 } |
| 249 } else if (overlapped) { |
| 250 async_context_->IOCompletionIsPending(callback); |
| 251 rv = ERR_IO_PENDING; |
245 } else { | 252 } else { |
246 if (overlapped) | |
247 IncrementOffset(overlapped, bytes_written); | |
248 rv = static_cast<int>(bytes_written); | 253 rv = static_cast<int>(bytes_written); |
249 } | 254 } |
250 return rv; | 255 return rv; |
251 } | 256 } |
252 | 257 |
253 } // namespace net | 258 } // namespace net |
254 | 259 |
OLD | NEW |