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

Side by Side Diff: net/disk_cache/file_win.cc

Issue 8156: Switch MessagePumpForIO to use completion ports on Windows.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/disk_cache/entry_impl.cc ('k') | net/disk_cache/mapped_file_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/disk_cache/file.h" 5 #include "net/disk_cache/file.h"
6 6
7 #include "base/message_loop.h"
8 #include "base/singleton.h"
7 #include "net/disk_cache/disk_cache.h" 9 #include "net/disk_cache/disk_cache.h"
8 10
9 namespace { 11 namespace {
10 12
11 // This class implements FileIOCallback to perform IO operations 13 // Structure used for asynchronous operations.
12 // when the callback parameter of the operation is NULL. 14 struct MyOverlapped {
13 class SyncCallback: public disk_cache::FileIOCallback { 15 MyOverlapped(disk_cache::File* file, size_t offset,
14 public: 16 disk_cache::FileIOCallback* callback);
15 SyncCallback() : called_(false) {} 17 ~MyOverlapped();
16 ~SyncCallback() {} 18 OVERLAPPED* overlapped() {
19 return &context_.overlapped;
20 }
17 21
18 virtual void OnFileIOComplete(int bytes_copied); 22 MessageLoopForIO::IOContext context_;
19 void WaitForResult(int* bytes_copied); 23 scoped_refptr<disk_cache::File> file_;
20 private: 24 disk_cache::FileIOCallback* callback_;
21 bool called_; 25 const void* buffer_;
22 int actual_; 26 bool delete_buffer_; // Delete the user buffer at completion.
23 }; 27 };
24 28
25 void SyncCallback::OnFileIOComplete(int bytes_copied) { 29 COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
26 actual_ = bytes_copied;
27 called_ = true;
28 }
29 30
30 // Waits for the IO operation to complete. 31 // Helper class to handle the IO completion notifications from the message loop.
31 void SyncCallback::WaitForResult(int* bytes_copied) { 32 class CompletionHandler : public MessageLoopForIO::IOHandler {
32 for (;;) { 33 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
33 SleepEx(INFINITE, TRUE); 34 DWORD actual_bytes, DWORD error);
34 if (called_)
35 break;
36 }
37 *bytes_copied = actual_;
38 }
39
40 // Structure used for asynchronous operations.
41 struct MyOverlapped {
42 OVERLAPPED overlapped;
43 disk_cache::File* file;
44 disk_cache::FileIOCallback* callback;
45 const void* buffer;
46 DWORD actual_bytes;
47 bool async; // Invoke the callback form the completion.
48 bool called; // Completion received.
49 bool delete_buffer; // Delete the user buffer at completion.
50 }; 35 };
51 36
52 COMPILE_ASSERT(!offsetof(MyOverlapped, overlapped), starts_with_overlapped); 37 void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
53 38 DWORD actual_bytes, DWORD error) {
54 } // namespace 39 MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
55
56 namespace disk_cache {
57
58 // SyncCallback to be invoked as an APC when the asynchronous operation
59 // completes.
60 void CALLBACK IoCompletion(DWORD error, DWORD actual_bytes,
61 OVERLAPPED* overlapped) {
62 MyOverlapped* data = reinterpret_cast<MyOverlapped*>(overlapped);
63 40
64 if (error) { 41 if (error) {
65 DCHECK(!actual_bytes); 42 DCHECK(!actual_bytes);
66 actual_bytes = static_cast<DWORD>(-1); 43 actual_bytes = static_cast<DWORD>(-1);
67 NOTREACHED(); 44 NOTREACHED();
68 } 45 }
69 46
70 if (data->delete_buffer) { 47 if (data->callback_)
71 DCHECK(!data->callback); 48 data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
72 data->file->Release();
73 delete data->buffer;
74 delete data;
75 return;
76 }
77 49
78 if (data->async) { 50 delete data;
79 data->callback->OnFileIOComplete(static_cast<int>(actual_bytes)); 51 }
80 data->file->Release(); 52
81 delete data; 53 MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
82 } else { 54 disk_cache::FileIOCallback* callback) {
83 // Somebody is waiting for this so don't delete data and instead notify 55 memset(this, 0, sizeof(*this));
84 // that we were called. 56 context_.handler = Singleton<CompletionHandler>::get();
85 data->actual_bytes = actual_bytes; 57 context_.overlapped.Offset = static_cast<DWORD>(offset);
86 data->file->Release(); 58 file_ = file;
87 data->called = true; 59 callback_ = callback;
60 }
61
62 MyOverlapped::~MyOverlapped() {
63 if (delete_buffer_) {
64 DCHECK(!callback_);
65 delete buffer_;
88 } 66 }
89 } 67 }
90 68
69 } // namespace
70
71 namespace disk_cache {
72
73 // Used from WaitForPendingIO() when the cache is being destroyed.
74 MessageLoopForIO::IOHandler* GetFileIOHandler() {
75 return Singleton<CompletionHandler>::get();
76 }
77
91 File::File(base::PlatformFile file) 78 File::File(base::PlatformFile file)
92 : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE), 79 : init_(true), platform_file_(INVALID_HANDLE_VALUE),
93 sync_platform_file_(file) { 80 sync_platform_file_(file) {
94 } 81 }
95 82
96 bool File::Init(const std::wstring& name) { 83 bool File::Init(const std::wstring& name) {
97 DCHECK(!init_); 84 DCHECK(!init_);
98 if (init_) 85 if (init_)
99 return false; 86 return false;
100 87
101 platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE, 88 platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
102 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 89 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
103 FILE_FLAG_OVERLAPPED, NULL); 90 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
104 91
105 if (INVALID_HANDLE_VALUE == platform_file_) 92 if (INVALID_HANDLE_VALUE == platform_file_)
106 return false; 93 return false;
107 94
95 MessageLoopForIO::current()->RegisterIOHandler(
96 platform_file_, Singleton<CompletionHandler>::get());
97
108 init_ = true; 98 init_ = true;
109 if (mixed_) { 99 sync_platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
110 sync_platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE, 100 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
111 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 101 OPEN_EXISTING, 0, NULL);
112 OPEN_EXISTING, 0, NULL);
113 102
114 if (INVALID_HANDLE_VALUE == sync_platform_file_) 103 if (INVALID_HANDLE_VALUE == sync_platform_file_)
115 return false; 104 return false;
116 } else {
117 sync_platform_file_ = INVALID_HANDLE_VALUE;
118 }
119 105
120 return true; 106 return true;
121 } 107 }
122 108
123 File::~File() { 109 File::~File() {
124 if (!init_) 110 if (!init_)
125 return; 111 return;
126 112
127 if (INVALID_HANDLE_VALUE != platform_file_) 113 if (INVALID_HANDLE_VALUE != platform_file_)
128 CloseHandle(platform_file_); 114 CloseHandle(platform_file_);
129 if (mixed_ && INVALID_HANDLE_VALUE != sync_platform_file_) 115 if (INVALID_HANDLE_VALUE != sync_platform_file_)
130 CloseHandle(sync_platform_file_); 116 CloseHandle(sync_platform_file_);
131 } 117 }
132 118
133 base::PlatformFile File::platform_file() const { 119 base::PlatformFile File::platform_file() const {
134 DCHECK(init_); 120 DCHECK(init_);
135 return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ : 121 return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
136 platform_file_; 122 platform_file_;
137 } 123 }
138 124
139 bool File::IsValid() const { 125 bool File::IsValid() const {
140 if (!init_) 126 if (!init_)
141 return false; 127 return false;
142 return (INVALID_HANDLE_VALUE != platform_file_ || 128 return (INVALID_HANDLE_VALUE != platform_file_ ||
143 INVALID_HANDLE_VALUE != sync_platform_file_); 129 INVALID_HANDLE_VALUE != sync_platform_file_);
144 } 130 }
145 131
146 bool File::Read(void* buffer, size_t buffer_len, size_t offset) { 132 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
147 DCHECK(init_); 133 DCHECK(init_);
148 if (!mixed_ || buffer_len > ULONG_MAX || offset > LONG_MAX) 134 if (buffer_len > ULONG_MAX || offset > LONG_MAX)
149 return false; 135 return false;
150 136
151 DWORD ret = SetFilePointer(sync_platform_file_, 137 DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
152 static_cast<LONG>(offset), 138 NULL, FILE_BEGIN);
153 NULL,
154 FILE_BEGIN);
155 if (INVALID_SET_FILE_POINTER == ret) 139 if (INVALID_SET_FILE_POINTER == ret)
156 return false; 140 return false;
157 141
158 DWORD actual; 142 DWORD actual;
159 DWORD size = static_cast<DWORD>(buffer_len); 143 DWORD size = static_cast<DWORD>(buffer_len);
160 if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL)) 144 if (!ReadFile(sync_platform_file_, buffer, size, &actual, NULL))
161 return false; 145 return false;
162 return actual == size; 146 return actual == size;
163 } 147 }
164 148
165 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) { 149 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
166 DCHECK(init_); 150 DCHECK(init_);
167 if (!mixed_ || buffer_len > ULONG_MAX || offset > ULONG_MAX) 151 if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
168 return false; 152 return false;
169 153
170 DWORD ret = SetFilePointer(sync_platform_file_, 154 DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
171 static_cast<LONG>(offset), 155 NULL, FILE_BEGIN);
172 NULL,
173 FILE_BEGIN);
174 if (INVALID_SET_FILE_POINTER == ret) 156 if (INVALID_SET_FILE_POINTER == ret)
175 return false; 157 return false;
176 158
177 DWORD actual; 159 DWORD actual;
178 DWORD size = static_cast<DWORD>(buffer_len); 160 DWORD size = static_cast<DWORD>(buffer_len);
179 if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL)) 161 if (!WriteFile(sync_platform_file_, buffer, size, &actual, NULL))
180 return false; 162 return false;
181 return actual == size; 163 return actual == size;
182 } 164 }
183 165
184 // We have to increase the ref counter of the file before performing the IO to 166 // We have to increase the ref counter of the file before performing the IO to
185 // prevent the completion to happen with an invalid handle (if the file is 167 // prevent the completion to happen with an invalid handle (if the file is
186 // closed while the IO is in flight). 168 // closed while the IO is in flight).
187 bool File::Read(void* buffer, size_t buffer_len, size_t offset, 169 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
188 FileIOCallback* callback, bool* completed) { 170 FileIOCallback* callback, bool* completed) {
189 DCHECK(init_); 171 DCHECK(init_);
172 if (!callback)
173 return Read(buffer, buffer_len, offset);
174
190 if (buffer_len > ULONG_MAX || offset > ULONG_MAX) 175 if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
191 return false; 176 return false;
192 177
193 MyOverlapped* data = new MyOverlapped; 178 MyOverlapped* data = new MyOverlapped(this, offset, callback);
194 memset(data, 0, sizeof(*data)); 179 DWORD size = static_cast<DWORD>(buffer_len);
195 180
196 SyncCallback local_callback; 181 DWORD actual;
197 data->overlapped.Offset = static_cast<DWORD>(offset); 182 if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) {
198 data->callback = callback ? callback : &local_callback; 183 *completed = false;
199 data->file = this; 184 if (GetLastError() == ERROR_IO_PENDING)
200 185 return true;
201 DWORD size = static_cast<DWORD>(buffer_len);
202 AddRef();
203
204 if (!ReadFileEx(platform_file_, buffer, size, &data->overlapped,
205 &IoCompletion)) {
206 Release();
207 delete data; 186 delete data;
208 return false; 187 return false;
209 } 188 }
210 189
211 if (callback) { 190 // The operation completed already. We'll be called back anyway.
212 *completed = false; 191 *completed = (actual == size);
213 // Let's check if the operation is already finished. 192 DCHECK(actual == size);
214 SleepEx(0, TRUE); 193 data->callback_ = NULL;
215 if (data->called) { 194 data->file_ = NULL; // There is no reason to hold on to this anymore.
216 *completed = (data->actual_bytes == size); 195 return *completed;
217 DCHECK(data->actual_bytes == size);
218 delete data;
219 return *completed;
220 }
221 data->async = true;
222 } else {
223 // Invoke the callback and perform cleanup on the APC.
224 data->async = true;
225 int bytes_copied;
226 local_callback.WaitForResult(&bytes_copied);
227 if (static_cast<int>(buffer_len) != bytes_copied) {
228 NOTREACHED();
229 return false;
230 }
231 }
232
233 return true;
234 } 196 }
235 197
236 bool File::Write(const void* buffer, size_t buffer_len, size_t offset, 198 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
237 FileIOCallback* callback, bool* completed) { 199 FileIOCallback* callback, bool* completed) {
238 DCHECK(init_); 200 DCHECK(init_);
201 if (!callback)
202 return Write(buffer, buffer_len, offset);
203
239 return AsyncWrite(buffer, buffer_len, offset, true, callback, completed); 204 return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
240 } 205 }
241 206
242 bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) { 207 bool File::PostWrite(const void* buffer, size_t buffer_len, size_t offset) {
243 DCHECK(init_); 208 DCHECK(init_);
244 return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL); 209 return AsyncWrite(buffer, buffer_len, offset, false, NULL, NULL);
245 } 210 }
246 211
247 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset, 212 bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
248 bool notify, FileIOCallback* callback, bool* completed) { 213 bool notify, FileIOCallback* callback, bool* completed) {
249 DCHECK(init_); 214 DCHECK(init_);
250 if (buffer_len > ULONG_MAX || offset > ULONG_MAX) 215 if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
251 return false; 216 return false;
252 217
253 MyOverlapped* data = new MyOverlapped; 218 MyOverlapped* data = new MyOverlapped(this, offset, callback);
254 memset(data, 0, sizeof(*data)); 219 bool dummy_completed;
255 220 if (!callback) {
256 SyncCallback local_callback; 221 DCHECK(!notify);
257 data->overlapped.Offset = static_cast<DWORD>(offset); 222 data->delete_buffer_ = true;
258 data->callback = callback ? callback : &local_callback; 223 data->buffer_ = buffer;
259 data->file = this; 224 completed = &dummy_completed;
260 if (!callback && !notify) {
261 data->delete_buffer = true;
262 data->callback = NULL;
263 data->buffer = buffer;
264 } 225 }
265 226
266 DWORD size = static_cast<DWORD>(buffer_len); 227 DWORD size = static_cast<DWORD>(buffer_len);
267 AddRef();
268 228
269 if (!WriteFileEx(platform_file_, buffer, size, &data->overlapped, 229 DWORD actual;
270 &IoCompletion)) { 230 if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) {
271 Release(); 231 *completed = false;
232 if (GetLastError() == ERROR_IO_PENDING)
233 return true;
272 delete data; 234 delete data;
273 return false; 235 return false;
274 } 236 }
275 237
276 if (callback) { 238 // The operation completed already. We'll be called back anyway.
277 *completed = false; 239 *completed = (actual == size);
278 SleepEx(0, TRUE); 240 DCHECK(actual == size);
279 if (data->called) { 241 data->callback_ = NULL;
280 *completed = (data->actual_bytes == size); 242 data->file_ = NULL; // There is no reason to hold on to this anymore.
281 DCHECK(data->actual_bytes == size); 243 return *completed;
282 delete data;
283 return *completed;
284 }
285 data->async = true;
286 } else if (notify) {
287 data->async = true;
288 int bytes_copied;
289 local_callback.WaitForResult(&bytes_copied);
290 if (static_cast<int>(buffer_len) != bytes_copied) {
291 NOTREACHED();
292 return false;
293 }
294 }
295
296 return true;
297 } 244 }
298 245
299 bool File::SetLength(size_t length) { 246 bool File::SetLength(size_t length) {
300 DCHECK(init_); 247 DCHECK(init_);
301 if (length > ULONG_MAX) 248 if (length > ULONG_MAX)
302 return false; 249 return false;
303 250
304 DWORD size = static_cast<DWORD>(length); 251 DWORD size = static_cast<DWORD>(length);
305 HANDLE file = platform_file(); 252 HANDLE file = platform_file();
306 if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN)) 253 if (INVALID_SET_FILE_POINTER == SetFilePointer(file, size, NULL, FILE_BEGIN))
307 return false; 254 return false;
308 255
309 return TRUE == SetEndOfFile(file); 256 return TRUE == SetEndOfFile(file);
310 } 257 }
311 258
312 size_t File::GetLength() { 259 size_t File::GetLength() {
313 DCHECK(init_); 260 DCHECK(init_);
314 LARGE_INTEGER size; 261 LARGE_INTEGER size;
315 HANDLE file = platform_file(); 262 HANDLE file = platform_file();
316 if (!GetFileSizeEx(file, &size)) 263 if (!GetFileSizeEx(file, &size))
317 return 0; 264 return 0;
318 if (size.HighPart) 265 if (size.HighPart)
319 return ULONG_MAX; 266 return ULONG_MAX;
320 267
321 return static_cast<size_t>(size.LowPart); 268 return static_cast<size_t>(size.LowPart);
322 } 269 }
323 270
324 } // namespace disk_cache 271 } // namespace disk_cache
325 272
OLDNEW
« no previous file with comments | « net/disk_cache/entry_impl.cc ('k') | net/disk_cache/mapped_file_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698