| Index: net/disk_cache/file_win.cc
|
| ===================================================================
|
| --- net/disk_cache/file_win.cc (revision 4870)
|
| +++ net/disk_cache/file_win.cc (working copy)
|
| @@ -4,92 +4,79 @@
|
|
|
| #include "net/disk_cache/file.h"
|
|
|
| +#include "base/message_loop.h"
|
| +#include "base/singleton.h"
|
| #include "net/disk_cache/disk_cache.h"
|
|
|
| namespace {
|
|
|
| -// This class implements FileIOCallback to perform IO operations
|
| -// when the callback parameter of the operation is NULL.
|
| -class SyncCallback: public disk_cache::FileIOCallback {
|
| - public:
|
| - SyncCallback() : called_(false) {}
|
| - ~SyncCallback() {}
|
| +// Structure used for asynchronous operations.
|
| +struct MyOverlapped {
|
| + MyOverlapped(disk_cache::File* file, size_t offset,
|
| + disk_cache::FileIOCallback* callback);
|
| + ~MyOverlapped();
|
| + OVERLAPPED* overlapped() {
|
| + return &context_.overlapped;
|
| + }
|
|
|
| - virtual void OnFileIOComplete(int bytes_copied);
|
| - void WaitForResult(int* bytes_copied);
|
| - private:
|
| - bool called_;
|
| - int actual_;
|
| + MessageLoopForIO::IOContext context_;
|
| + scoped_refptr<disk_cache::File> file_;
|
| + disk_cache::FileIOCallback* callback_;
|
| + const void* buffer_;
|
| + bool delete_buffer_; // Delete the user buffer at completion.
|
| };
|
|
|
| -void SyncCallback::OnFileIOComplete(int bytes_copied) {
|
| - actual_ = bytes_copied;
|
| - called_ = true;
|
| -}
|
| +COMPILE_ASSERT(!offsetof(MyOverlapped, context_), starts_with_overlapped);
|
|
|
| -// Waits for the IO operation to complete.
|
| -void SyncCallback::WaitForResult(int* bytes_copied) {
|
| - for (;;) {
|
| - SleepEx(INFINITE, TRUE);
|
| - if (called_)
|
| - break;
|
| - }
|
| - *bytes_copied = actual_;
|
| -}
|
| -
|
| -// Structure used for asynchronous operations.
|
| -struct MyOverlapped {
|
| - OVERLAPPED overlapped;
|
| - disk_cache::File* file;
|
| - disk_cache::FileIOCallback* callback;
|
| - const void* buffer;
|
| - DWORD actual_bytes;
|
| - bool async; // Invoke the callback form the completion.
|
| - bool called; // Completion received.
|
| - bool delete_buffer; // Delete the user buffer at completion.
|
| +// Helper class to handle the IO completion notifications from the message loop.
|
| +class CompletionHandler : public MessageLoopForIO::IOHandler {
|
| + virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
|
| + DWORD actual_bytes, DWORD error);
|
| };
|
|
|
| -COMPILE_ASSERT(!offsetof(MyOverlapped, overlapped), starts_with_overlapped);
|
| +void CompletionHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
|
| + DWORD actual_bytes, DWORD error) {
|
| + MyOverlapped* data = reinterpret_cast<MyOverlapped*>(context);
|
|
|
| -} // namespace
|
| -
|
| -namespace disk_cache {
|
| -
|
| -// SyncCallback to be invoked as an APC when the asynchronous operation
|
| -// completes.
|
| -void CALLBACK IoCompletion(DWORD error, DWORD actual_bytes,
|
| - OVERLAPPED* overlapped) {
|
| - MyOverlapped* data = reinterpret_cast<MyOverlapped*>(overlapped);
|
| -
|
| if (error) {
|
| DCHECK(!actual_bytes);
|
| actual_bytes = static_cast<DWORD>(-1);
|
| NOTREACHED();
|
| }
|
|
|
| - if (data->delete_buffer) {
|
| - DCHECK(!data->callback);
|
| - data->file->Release();
|
| - delete data->buffer;
|
| - delete data;
|
| - return;
|
| - }
|
| + if (data->callback_)
|
| + data->callback_->OnFileIOComplete(static_cast<int>(actual_bytes));
|
|
|
| - if (data->async) {
|
| - data->callback->OnFileIOComplete(static_cast<int>(actual_bytes));
|
| - data->file->Release();
|
| - delete data;
|
| - } else {
|
| - // Somebody is waiting for this so don't delete data and instead notify
|
| - // that we were called.
|
| - data->actual_bytes = actual_bytes;
|
| - data->file->Release();
|
| - data->called = true;
|
| + delete data;
|
| +}
|
| +
|
| +MyOverlapped::MyOverlapped(disk_cache::File* file, size_t offset,
|
| + disk_cache::FileIOCallback* callback) {
|
| + memset(this, 0, sizeof(*this));
|
| + context_.handler = Singleton<CompletionHandler>::get();
|
| + context_.overlapped.Offset = static_cast<DWORD>(offset);
|
| + file_ = file;
|
| + callback_ = callback;
|
| +}
|
| +
|
| +MyOverlapped::~MyOverlapped() {
|
| + if (delete_buffer_) {
|
| + DCHECK(!callback_);
|
| + delete buffer_;
|
| }
|
| }
|
|
|
| +} // namespace
|
| +
|
| +namespace disk_cache {
|
| +
|
| +// Used from WaitForPendingIO() when the cache is being destroyed.
|
| +MessageLoopForIO::IOHandler* GetFileIOHandler() {
|
| + return Singleton<CompletionHandler>::get();
|
| +}
|
| +
|
| File::File(base::PlatformFile file)
|
| - : init_(true), mixed_(true), platform_file_(INVALID_HANDLE_VALUE),
|
| + : init_(true), platform_file_(INVALID_HANDLE_VALUE),
|
| sync_platform_file_(file) {
|
| }
|
|
|
| @@ -99,23 +86,22 @@
|
| return false;
|
|
|
| platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
|
| - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
| - FILE_FLAG_OVERLAPPED, NULL);
|
| + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
| + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
|
|
| if (INVALID_HANDLE_VALUE == platform_file_)
|
| return false;
|
|
|
| + MessageLoopForIO::current()->RegisterIOHandler(
|
| + platform_file_, Singleton<CompletionHandler>::get());
|
| +
|
| init_ = true;
|
| - if (mixed_) {
|
| - sync_platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
|
| - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
| - OPEN_EXISTING, 0, NULL);
|
| + sync_platform_file_ = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
|
| + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
| + OPEN_EXISTING, 0, NULL);
|
|
|
| - if (INVALID_HANDLE_VALUE == sync_platform_file_)
|
| - return false;
|
| - } else {
|
| - sync_platform_file_ = INVALID_HANDLE_VALUE;
|
| - }
|
| + if (INVALID_HANDLE_VALUE == sync_platform_file_)
|
| + return false;
|
|
|
| return true;
|
| }
|
| @@ -126,13 +112,13 @@
|
|
|
| if (INVALID_HANDLE_VALUE != platform_file_)
|
| CloseHandle(platform_file_);
|
| - if (mixed_ && INVALID_HANDLE_VALUE != sync_platform_file_)
|
| + if (INVALID_HANDLE_VALUE != sync_platform_file_)
|
| CloseHandle(sync_platform_file_);
|
| }
|
|
|
| base::PlatformFile File::platform_file() const {
|
| DCHECK(init_);
|
| - return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
|
| + return (INVALID_HANDLE_VALUE == platform_file_) ? sync_platform_file_ :
|
| platform_file_;
|
| }
|
|
|
| @@ -145,13 +131,11 @@
|
|
|
| bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
|
| DCHECK(init_);
|
| - if (!mixed_ || buffer_len > ULONG_MAX || offset > LONG_MAX)
|
| + if (buffer_len > ULONG_MAX || offset > LONG_MAX)
|
| return false;
|
|
|
| - DWORD ret = SetFilePointer(sync_platform_file_,
|
| - static_cast<LONG>(offset),
|
| - NULL,
|
| - FILE_BEGIN);
|
| + DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
|
| + NULL, FILE_BEGIN);
|
| if (INVALID_SET_FILE_POINTER == ret)
|
| return false;
|
|
|
| @@ -164,13 +148,11 @@
|
|
|
| bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
|
| DCHECK(init_);
|
| - if (!mixed_ || buffer_len > ULONG_MAX || offset > ULONG_MAX)
|
| + if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
|
| return false;
|
|
|
| - DWORD ret = SetFilePointer(sync_platform_file_,
|
| - static_cast<LONG>(offset),
|
| - NULL,
|
| - FILE_BEGIN);
|
| + DWORD ret = SetFilePointer(sync_platform_file_, static_cast<LONG>(offset),
|
| + NULL, FILE_BEGIN);
|
| if (INVALID_SET_FILE_POINTER == ret)
|
| return false;
|
|
|
| @@ -187,55 +169,38 @@
|
| bool File::Read(void* buffer, size_t buffer_len, size_t offset,
|
| FileIOCallback* callback, bool* completed) {
|
| DCHECK(init_);
|
| + if (!callback)
|
| + return Read(buffer, buffer_len, offset);
|
| +
|
| if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
|
| return false;
|
|
|
| - MyOverlapped* data = new MyOverlapped;
|
| - memset(data, 0, sizeof(*data));
|
| -
|
| - SyncCallback local_callback;
|
| - data->overlapped.Offset = static_cast<DWORD>(offset);
|
| - data->callback = callback ? callback : &local_callback;
|
| - data->file = this;
|
| -
|
| + MyOverlapped* data = new MyOverlapped(this, offset, callback);
|
| DWORD size = static_cast<DWORD>(buffer_len);
|
| - AddRef();
|
|
|
| - if (!ReadFileEx(platform_file_, buffer, size, &data->overlapped,
|
| - &IoCompletion)) {
|
| - Release();
|
| + DWORD actual;
|
| + if (!ReadFile(platform_file_, buffer, size, &actual, data->overlapped())) {
|
| + *completed = false;
|
| + if (GetLastError() == ERROR_IO_PENDING)
|
| + return true;
|
| delete data;
|
| return false;
|
| }
|
|
|
| - if (callback) {
|
| - *completed = false;
|
| - // Let's check if the operation is already finished.
|
| - SleepEx(0, TRUE);
|
| - if (data->called) {
|
| - *completed = (data->actual_bytes == size);
|
| - DCHECK(data->actual_bytes == size);
|
| - delete data;
|
| - return *completed;
|
| - }
|
| - data->async = true;
|
| - } else {
|
| - // Invoke the callback and perform cleanup on the APC.
|
| - data->async = true;
|
| - int bytes_copied;
|
| - local_callback.WaitForResult(&bytes_copied);
|
| - if (static_cast<int>(buffer_len) != bytes_copied) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - return true;
|
| + // The operation completed already. We'll be called back anyway.
|
| + *completed = (actual == size);
|
| + DCHECK(actual == size);
|
| + data->callback_ = NULL;
|
| + data->file_ = NULL; // There is no reason to hold on to this anymore.
|
| + return *completed;
|
| }
|
|
|
| bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
|
| FileIOCallback* callback, bool* completed) {
|
| DCHECK(init_);
|
| + if (!callback)
|
| + return Write(buffer, buffer_len, offset);
|
| +
|
| return AsyncWrite(buffer, buffer_len, offset, true, callback, completed);
|
| }
|
|
|
| @@ -250,50 +215,32 @@
|
| if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
|
| return false;
|
|
|
| - MyOverlapped* data = new MyOverlapped;
|
| - memset(data, 0, sizeof(*data));
|
| -
|
| - SyncCallback local_callback;
|
| - data->overlapped.Offset = static_cast<DWORD>(offset);
|
| - data->callback = callback ? callback : &local_callback;
|
| - data->file = this;
|
| - if (!callback && !notify) {
|
| - data->delete_buffer = true;
|
| - data->callback = NULL;
|
| - data->buffer = buffer;
|
| + MyOverlapped* data = new MyOverlapped(this, offset, callback);
|
| + bool dummy_completed;
|
| + if (!callback) {
|
| + DCHECK(!notify);
|
| + data->delete_buffer_ = true;
|
| + data->buffer_ = buffer;
|
| + completed = &dummy_completed;
|
| }
|
|
|
| DWORD size = static_cast<DWORD>(buffer_len);
|
| - AddRef();
|
|
|
| - if (!WriteFileEx(platform_file_, buffer, size, &data->overlapped,
|
| - &IoCompletion)) {
|
| - Release();
|
| + DWORD actual;
|
| + if (!WriteFile(platform_file_, buffer, size, &actual, data->overlapped())) {
|
| + *completed = false;
|
| + if (GetLastError() == ERROR_IO_PENDING)
|
| + return true;
|
| delete data;
|
| return false;
|
| }
|
|
|
| - if (callback) {
|
| - *completed = false;
|
| - SleepEx(0, TRUE);
|
| - if (data->called) {
|
| - *completed = (data->actual_bytes == size);
|
| - DCHECK(data->actual_bytes == size);
|
| - delete data;
|
| - return *completed;
|
| - }
|
| - data->async = true;
|
| - } else if (notify) {
|
| - data->async = true;
|
| - int bytes_copied;
|
| - local_callback.WaitForResult(&bytes_copied);
|
| - if (static_cast<int>(buffer_len) != bytes_copied) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - return true;
|
| + // The operation completed already. We'll be called back anyway.
|
| + *completed = (actual == size);
|
| + DCHECK(actual == size);
|
| + data->callback_ = NULL;
|
| + data->file_ = NULL; // There is no reason to hold on to this anymore.
|
| + return *completed;
|
| }
|
|
|
| bool File::SetLength(size_t length) {
|
|
|