diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-13 06:38:15 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-13 06:38:15 +0000 |
commit | dbb6fde18898bd2d2d35b6304412dd3cdd9fc049 (patch) | |
tree | 3d077e227add029871989f84a9d1b1dafb8dfffb /webkit | |
parent | bde493da11f65b382f38bf96c15b3dcab0bd6661 (diff) | |
download | chromium_src-dbb6fde18898bd2d2d35b6304412dd3cdd9fc049.zip chromium_src-dbb6fde18898bd2d2d35b6304412dd3cdd9fc049.tar.gz chromium_src-dbb6fde18898bd2d2d35b6304412dd3cdd9fc049.tar.bz2 |
Support overlapped calls of FileIO::{Read,Write}.
BUG=84883
TEST=test_file_io
Review URL: http://codereview.chromium.org/7258002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/plugins/ppapi/ppb_file_io_impl.cc | 132 | ||||
-rw-r--r-- | webkit/plugins/ppapi/ppb_file_io_impl.h | 49 |
2 files changed, 130 insertions, 51 deletions
diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.cc b/webkit/plugins/ppapi/ppb_file_io_impl.cc index 9bf407e..8a3b3d1 100644 --- a/webkit/plugins/ppapi/ppb_file_io_impl.cc +++ b/webkit/plugins/ppapi/ppb_file_io_impl.cc @@ -34,13 +34,24 @@ using ppapi::thunk::PPB_FileRef_API; namespace webkit { namespace ppapi { +PPB_FileIO_Impl::CallbackEntry::CallbackEntry() + : read_buffer(NULL) { +} + +PPB_FileIO_Impl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) + : callback(entry.callback), + read_buffer(entry.read_buffer) { +} + +PPB_FileIO_Impl::CallbackEntry::~CallbackEntry() { +} + PPB_FileIO_Impl::PPB_FileIO_Impl(PluginInstance* instance) : Resource(instance), ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), file_(base::kInvalidPlatformFileValue), - callback_(), - info_(NULL), - read_buffer_(NULL) { + pending_op_(OPERATION_NONE), + info_(NULL) { } PPB_FileIO_Impl::~PPB_FileIO_Impl() { @@ -59,7 +70,7 @@ int32_t PPB_FileIO_Impl::Open(PP_Resource pp_file_ref, return PP_ERROR_BADRESOURCE; PPB_FileRef_Impl* file_ref = static_cast<PPB_FileRef_Impl*>(enter.object()); - int32_t rv = CommonCallValidation(false, callback); + int32_t rv = CommonCallValidation(false, OPERATION_EXCLUSIVE, callback); if (rv != PP_OK) return rv; @@ -88,13 +99,13 @@ int32_t PPB_FileIO_Impl::Open(PP_Resource pp_file_ref, return PP_ERROR_FAILED; } - RegisterCallback(callback); + RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); return PP_OK_COMPLETIONPENDING; } int32_t PPB_FileIO_Impl::Query(PP_FileInfo* info, PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); if (rv != PP_OK) return rv; @@ -109,14 +120,14 @@ int32_t PPB_FileIO_Impl::Query(PP_FileInfo* info, callback_factory_.NewCallback(&PPB_FileIO_Impl::QueryInfoCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); return PP_OK_COMPLETIONPENDING; } int32_t PPB_FileIO_Impl::Touch(PP_Time last_access_time, PP_Time last_modified_time, PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); if (rv != PP_OK) return rv; @@ -127,7 +138,7 @@ int32_t PPB_FileIO_Impl::Touch(PP_Time last_access_time, callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); return PP_OK_COMPLETIONPENDING; } @@ -135,21 +146,17 @@ int32_t PPB_FileIO_Impl::Read(int64_t offset, char* buffer, int32_t bytes_to_read, PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + int32_t rv = CommonCallValidation(true, OPERATION_READ, callback); if (rv != PP_OK) return rv; - // If |read_buffer__|, a callback should be pending (caught above). - DCHECK(!read_buffer_); - read_buffer_ = buffer; - if (!base::FileUtilProxy::Read( instance()->delegate()->GetFileThreadMessageLoopProxy(), file_, offset, bytes_to_read, callback_factory_.NewCallback(&PPB_FileIO_Impl::ReadCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_READ, callback, buffer); return PP_OK_COMPLETIONPENDING; } @@ -157,7 +164,7 @@ int32_t PPB_FileIO_Impl::Write(int64_t offset, const char* buffer, int32_t bytes_to_write, PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + int32_t rv = CommonCallValidation(true, OPERATION_WRITE, callback); if (rv != PP_OK) return rv; @@ -167,13 +174,13 @@ int32_t PPB_FileIO_Impl::Write(int64_t offset, callback_factory_.NewCallback(&PPB_FileIO_Impl::WriteCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_WRITE, callback, NULL); return PP_OK_COMPLETIONPENDING; } int32_t PPB_FileIO_Impl::SetLength(int64_t length, - PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); if (rv != PP_OK) return rv; @@ -183,12 +190,12 @@ int32_t PPB_FileIO_Impl::SetLength(int64_t length, callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); return PP_OK_COMPLETIONPENDING; } int32_t PPB_FileIO_Impl::Flush(PP_CompletionCallback callback) { - int32_t rv = CommonCallValidation(true, callback); + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); if (rv != PP_OK) return rv; @@ -197,7 +204,7 @@ int32_t PPB_FileIO_Impl::Flush(PP_CompletionCallback callback) { callback_factory_.NewCallback(&PPB_FileIO_Impl::StatusCallback))) return PP_ERROR_FAILED; - RegisterCallback(callback); + RegisterCallback(OPERATION_EXCLUSIVE, callback, NULL); return PP_OK_COMPLETIONPENDING; } @@ -233,6 +240,7 @@ int32_t PPB_FileIO_Impl::WillSetLength(int64_t length, } int32_t PPB_FileIO_Impl::CommonCallValidation(bool should_be_open, + OperationType new_op, PP_CompletionCallback callback) { // Only asynchronous operation is supported. if (!callback.func) { @@ -248,43 +256,73 @@ int32_t PPB_FileIO_Impl::CommonCallValidation(bool should_be_open, return PP_ERROR_FAILED; } - if (callback_.get() && !callback_->completed()) + if (pending_op_ != OPERATION_NONE && + (pending_op_ != new_op || pending_op_ == OPERATION_EXCLUSIVE)) { return PP_ERROR_INPROGRESS; + } return PP_OK; } -void PPB_FileIO_Impl::RegisterCallback(PP_CompletionCallback callback) { +void PPB_FileIO_Impl::RegisterCallback(OperationType op, + PP_CompletionCallback callback, + char* read_buffer) { DCHECK(callback.func); - DCHECK(!callback_.get() || callback_->completed()); + DCHECK(pending_op_ == OPERATION_NONE || + (pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op)); + CallbackEntry entry; PP_Resource resource_id = GetReferenceNoAddRef(); CHECK(resource_id); - callback_ = new TrackedCompletionCallback( + entry.callback = new TrackedCompletionCallback( instance()->module()->GetCallbackTracker(), resource_id, callback); + entry.read_buffer = read_buffer; + + callbacks_.push(entry); + pending_op_ = op; } -void PPB_FileIO_Impl::RunPendingCallback(int32_t result) { - scoped_refptr<TrackedCompletionCallback> callback; - callback.swap(callback_); - callback->Run(result); // Will complete abortively if necessary. +void PPB_FileIO_Impl::RunAndRemoveFirstPendingCallback(int32_t result) { + DCHECK(!callbacks_.empty()); + + CallbackEntry front = callbacks_.front(); + callbacks_.pop(); + if (callbacks_.empty()) + pending_op_ = OPERATION_NONE; + + front.callback->Run(result); // Will complete abortively if necessary. } void PPB_FileIO_Impl::StatusCallback(base::PlatformFileError error_code) { - RunPendingCallback(PlatformFileErrorToPepperError(error_code)); + if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { + NOTREACHED(); + return; + } + + RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); } void PPB_FileIO_Impl::AsyncOpenFileCallback( base::PlatformFileError error_code, base::PlatformFile file) { + if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { + NOTREACHED(); + return; + } + DCHECK(file_ == base::kInvalidPlatformFileValue); file_ = file; - RunPendingCallback(PlatformFileErrorToPepperError(error_code)); + RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); } void PPB_FileIO_Impl::QueryInfoCallback( base::PlatformFileError error_code, const base::PlatformFileInfo& file_info) { + if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty()) { + NOTREACHED(); + return; + } + DCHECK(info_); if (error_code == base::PLATFORM_FILE_OK) { info_->size = file_info.size; @@ -298,33 +336,45 @@ void PPB_FileIO_Impl::QueryInfoCallback( info_->type = PP_FILETYPE_REGULAR; } info_ = NULL; - RunPendingCallback(PlatformFileErrorToPepperError(error_code)); + RunAndRemoveFirstPendingCallback(PlatformFileErrorToPepperError(error_code)); } void PPB_FileIO_Impl::ReadCallback(base::PlatformFileError error_code, const char* data, int bytes_read) { + if (pending_op_ != OPERATION_READ || callbacks_.empty()) { + NOTREACHED(); + return; + } + + char* read_buffer = callbacks_.front().read_buffer; DCHECK(data); - DCHECK(read_buffer_); + DCHECK(read_buffer); int rv; if (error_code == base::PLATFORM_FILE_OK) { rv = bytes_read; if (file_ != base::kInvalidPlatformFileValue) - memcpy(read_buffer_, data, bytes_read); + memcpy(read_buffer, data, bytes_read); } else { rv = PlatformFileErrorToPepperError(error_code); } - read_buffer_ = NULL; - RunPendingCallback(rv); + RunAndRemoveFirstPendingCallback(rv); } void PPB_FileIO_Impl::WriteCallback(base::PlatformFileError error_code, int bytes_written) { - if (error_code != base::PLATFORM_FILE_OK) - RunPendingCallback(PlatformFileErrorToPepperError(error_code)); - else - RunPendingCallback(bytes_written); + if (pending_op_ != OPERATION_WRITE || callbacks_.empty()) { + NOTREACHED(); + return; + } + + if (error_code != base::PLATFORM_FILE_OK) { + RunAndRemoveFirstPendingCallback( + PlatformFileErrorToPepperError(error_code)); + } else { + RunAndRemoveFirstPendingCallback(bytes_written); + } } } // namespace ppapi diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.h b/webkit/plugins/ppapi/ppb_file_io_impl.h index f805330..0fc3507 100644 --- a/webkit/plugins/ppapi/ppb_file_io_impl.h +++ b/webkit/plugins/ppapi/ppb_file_io_impl.h @@ -5,6 +5,8 @@ #ifndef WEBKIT_PLUGINS_PPAPI_PPB_FILE_IO_IMPL_H_ #define WEBKIT_PLUGINS_PPAPI_PPB_FILE_IO_IMPL_H_ +#include <queue> + #include "base/basictypes.h" #include "base/file_path.h" #include "base/memory/ref_counted.h" @@ -66,20 +68,50 @@ class PPB_FileIO_Impl : public Resource, PP_CompletionCallback callback) OVERRIDE; private: + struct CallbackEntry { + CallbackEntry(); + CallbackEntry(const CallbackEntry& entry); + ~CallbackEntry(); + + scoped_refptr<TrackedCompletionCallback> callback; + // Pointer back to the caller's read buffer; only used by |Read()|. + // Not owned. + char* read_buffer; + }; + + enum OperationType { + // If there are pending reads, any other kind of async operation is not + // allowed. + OPERATION_READ, + // If there are pending writes, any other kind of async operation is not + // allowed. + OPERATION_WRITE, + // If there is a pending operation that is neither read nor write, no + // further async operation is allowed. + OPERATION_EXCLUSIVE, + // There is no pending operation right now. + OPERATION_NONE, + }; + // Verifies: // - that |callback| is valid (only nonblocking operation supported); // - that the file is already open or not, depending on |should_be_open|; and - // - that no callback is already pending. + // - that no callback is already pending, or it is a read(write) request + // and currently the pending operations are reads(writes). // Returns |PP_OK| to indicate that everything is valid or |PP_ERROR_...| if // the call should be aborted and that code returned to the plugin. int32_t CommonCallValidation(bool should_be_open, + OperationType new_op, PP_CompletionCallback callback); - // Sets up |callback| as the pending callback. This should only be called once - // it is certain that |PP_OK_COMPLETIONPENDING| will be returned. - void RegisterCallback(PP_CompletionCallback callback); + // Sets up a pending callback. This should only be called once it is certain + // that |PP_OK_COMPLETIONPENDING| will be returned. + // |read_buffer| is only used by read operations. + void RegisterCallback(OperationType op, + PP_CompletionCallback callback, + char* rend_buffer); - void RunPendingCallback(int32_t result); + void RunAndRemoveFirstPendingCallback(int32_t result); void StatusCallback(base::PlatformFileError error_code); void AsyncOpenFileCallback(base::PlatformFileError error_code, @@ -95,16 +127,13 @@ class PPB_FileIO_Impl : public Resource, base::PlatformFile file_; PP_FileSystemType file_system_type_; - // Any pending callback for any PPB_FileIO(Trusted) call taking a callback. - scoped_refptr<TrackedCompletionCallback> callback_; + std::queue<CallbackEntry> callbacks_; + OperationType pending_op_; // Output buffer pointer for |Query()|; only non-null when a callback is // pending for it. PP_FileInfo* info_; - // Pointer back to the caller's read buffer; used by |Read()|. Not owned. - char* read_buffer_; - DISALLOW_COPY_AND_ASSIGN(PPB_FileIO_Impl); }; |