Index: ppapi/proxy/file_io_resource.cc |
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc |
index 1df67ccba1be125a9b47b902a1a9e08564ed86a1..c5c947d10888f9c0916cc49056280222eda9171c 100644 |
--- a/ppapi/proxy/file_io_resource.cc |
+++ b/ppapi/proxy/file_io_resource.cc |
@@ -5,6 +5,7 @@ |
#include "ppapi/proxy/file_io_resource.h" |
#include "base/bind.h" |
+#include "base/task_runner_util.h" |
#include "ipc/ipc_message.h" |
#include "ppapi/c/pp_errors.h" |
#include "ppapi/proxy/ppapi_messages.h" |
@@ -22,6 +23,11 @@ using ppapi::thunk::PPB_FileRef_API; |
namespace { |
+// We must allocate a buffer sized according to the request of the plugin. To |
+// reduce the chance of out-of-memory errors, we cap the read size to 32MB. |
+// This is OK since the API specifies that it may perform a partial read. |
+static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB |
+ |
// An adapter to let Read() share the same implementation with ReadToArray(). |
void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) { |
return user_data; |
@@ -37,6 +43,36 @@ void DoClose(base::PlatformFile file) { |
namespace ppapi { |
namespace proxy { |
+FileIOResource::QueryOp::QueryOp(PP_FileHandle file_handle) |
+ : file_handle_(file_handle) { |
+} |
+ |
+FileIOResource::QueryOp::~QueryOp() { |
+} |
+ |
+int32_t FileIOResource::QueryOp::DoWork() { |
+ return base::GetPlatformFileInfo(file_handle_, &file_info_) ? |
+ PP_OK : PP_ERROR_FAILED; |
+} |
+ |
+FileIOResource::ReadOp::ReadOp(PP_FileHandle file_handle, |
+ int64_t offset, |
+ int32_t bytes_to_read) |
+ : file_handle_(file_handle), |
+ offset_(offset), |
+ bytes_to_read_(bytes_to_read) { |
+} |
+ |
+FileIOResource::ReadOp::~ReadOp() { |
+} |
+ |
+int32_t FileIOResource::ReadOp::DoWork() { |
+ DCHECK(!buffer_.get()); |
+ buffer_.reset(new char[bytes_to_read_]); |
+ return base::ReadPlatformFile( |
+ file_handle_, offset_, buffer_.get(), bytes_to_read_); |
dmichael (off chromium)
2013/08/09 22:20:56
We don't have the lock, so file_handle_ could be c
bbudge
2013/08/09 23:05:28
Yes, I think the file call will fail gracefully (e
|
+} |
+ |
FileIOResource::FileIOResource(Connection connection, PP_Instance instance) |
: PluginResource(connection, instance), |
file_handle_(base::kInvalidPlatformFileValue), |
@@ -92,33 +128,36 @@ int32_t FileIOResource::Query(PP_FileInfo* info, |
FileIOStateManager::OPERATION_EXCLUSIVE, true); |
if (rv != PP_OK) |
return rv; |
+ if (!info) |
+ return PP_ERROR_BADARGUMENT; |
+ if (file_handle_ == base::kInvalidPlatformFileValue) |
+ return PP_ERROR_FAILED; |
+ |
+ state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); |
+ scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_)); |
- if (callback->is_blocking() && |
- file_handle_ != base::kInvalidPlatformFileValue) { |
- state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); |
- int32_t result = PP_ERROR_FAILED; |
- base::PlatformFileInfo file_info; |
- // Release the proxy lock while making a potentially blocking file call. |
+ // If the callback is blocking, perform the task on the calling thread. |
+ if (callback->is_blocking()) { |
+ int32_t result; |
{ |
+ // Release the proxy lock while making a potentially slow file call. |
ProxyAutoUnlock unlock; |
- result = base::GetPlatformFileInfo(file_handle_, &file_info) ? |
- PP_OK : PP_ERROR_FAILED; |
- } |
- if ((result == PP_OK) && TrackedCallback::IsPending(callback)) { |
- ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type_, |
- info); |
+ result = query_op->DoWork(); |
} |
- |
- state_manager_.SetOperationFinished(); |
- return result; |
+ return OnQueryComplete(query_op, info, result); |
} |
- Call<PpapiPluginMsg_FileIO_QueryReply>(RENDERER, |
- PpapiHostMsg_FileIO_Query(), |
- base::Bind(&FileIOResource::OnPluginMsgQueryComplete, this, |
- callback, info)); |
+ // For the non-blocking case, post a task to the file thread and add a |
+ // completion task to write the result. |
+ base::PostTaskAndReplyWithResult( |
+ PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()), |
+ FROM_HERE, |
+ Bind(&FileIOResource::QueryOp::DoWork, query_op), |
+ RunWhileLocked( |
+ Bind(&FileIOResource::OnFileTaskComplete, this, callback))); |
dmichael (off chromium)
2013/08/09 22:20:56
Oh, I think you could just use:
Bind(&TrackedCallb
bbudge
2013/08/09 23:05:28
Yep. Done.
|
+ callback->set_completion_task( |
+ Bind(&FileIOResource::OnQueryComplete, this, query_op, info)); |
- state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); |
return PP_OK_COMPLETIONPENDING; |
} |
@@ -274,41 +313,36 @@ int32_t FileIOResource::ReadValidated(int64_t offset, |
int32_t bytes_to_read, |
const PP_ArrayOutput& array_output, |
scoped_refptr<TrackedCallback> callback) { |
+ if (bytes_to_read < 0) |
+ return PP_ERROR_FAILED; |
+ if (file_handle_ == base::kInvalidPlatformFileValue) |
+ return PP_ERROR_FAILED; |
+ |
state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); |
- if (callback->is_blocking() && |
- file_handle_ != base::kInvalidPlatformFileValue) { |
- int32_t result = PP_ERROR_FAILED; |
- if (bytes_to_read >= 0) { |
- // We need a buffer (and therefore we must copy) since we don't know until |
- // reacquire the lock whether to write data to the plugin's buffer. |
- scoped_ptr<char[]> buffer; |
- // Release the proxy lock while making a potentially blocking file call. |
- { |
- ProxyAutoUnlock unlock; |
- buffer.reset(new char[bytes_to_read]); |
- int32_t bytes_read = base::ReadPlatformFile( |
- file_handle_, offset, buffer.get(), bytes_to_read); |
- result = (bytes_read < 0) ? PP_ERROR_FAILED : bytes_read; |
- } |
- if ((result >= 0) && TrackedCallback::IsPending(callback)) { |
- ArrayWriter output; |
- output.set_pp_array_output(array_output); |
- if (output.is_valid()) |
- output.StoreArray(buffer.get(), result); |
- else |
- result = PP_ERROR_FAILED; |
- } |
+ bytes_to_read = std::min(bytes_to_read, kMaxReadSize); |
+ scoped_refptr<ReadOp> read_op( |
+ new ReadOp(file_handle_, offset, bytes_to_read)); |
+ if (callback->is_blocking()) { |
+ int32_t result; |
+ { |
+ // Release the proxy lock while making a potentially slow file call. |
+ ProxyAutoUnlock unlock; |
+ result = read_op->DoWork(); |
} |
- |
- state_manager_.SetOperationFinished(); |
- return result; |
+ return OnReadComplete(read_op, array_output, result); |
} |
- Call<PpapiPluginMsg_FileIO_ReadReply>(RENDERER, |
- PpapiHostMsg_FileIO_Read(offset, bytes_to_read), |
- base::Bind(&FileIOResource::OnPluginMsgReadComplete, this, |
- callback, array_output)); |
+ // For the non-blocking case, post a task to the file thread. |
+ base::PostTaskAndReplyWithResult( |
+ PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()), |
+ FROM_HERE, |
+ Bind(&FileIOResource::ReadOp::DoWork, read_op), |
+ RunWhileLocked( |
+ Bind(&FileIOResource::OnFileTaskComplete, this, callback))); |
dmichael (off chromium)
2013/08/09 22:20:56
ditto
bbudge
2013/08/09 23:05:28
Done.
|
+ callback->set_completion_task( |
+ Bind(&FileIOResource::OnReadComplete, this, read_op, array_output)); |
+ |
return PP_OK_COMPLETIONPENDING; |
} |
@@ -324,6 +358,46 @@ void FileIOResource::CloseFileHandle() { |
} |
} |
+void FileIOResource::OnFileTaskComplete(scoped_refptr<TrackedCallback> callback, |
+ int32_t result) { |
+ callback->Run(result); |
+} |
+ |
+int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op, |
+ PP_FileInfo* info, |
+ int32_t result) { |
+ DCHECK(state_manager_.get_pending_operation() == |
+ FileIOStateManager::OPERATION_EXCLUSIVE); |
+ |
+ if (result == PP_OK) { |
+ ppapi::PlatformFileInfoToPepperFileInfo(query_op->file_info(), |
dmichael (off chromium)
2013/08/09 22:20:56
It might be good to call out with a comment that t
bbudge
2013/08/09 23:05:28
Done.
|
+ file_system_type_, |
+ info); |
+ } |
+ state_manager_.SetOperationFinished(); |
+ return result; |
+} |
+ |
+int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op, |
+ PP_ArrayOutput array_output, |
+ int32_t result) { |
+ DCHECK(state_manager_.get_pending_operation() == |
+ FileIOStateManager::OPERATION_READ); |
+ if (result >= 0) { |
+ ArrayWriter output; |
+ output.set_pp_array_output(array_output); |
+ if (output.is_valid()) |
+ output.StoreArray(read_op->buffer(), result); |
+ else |
+ result = PP_ERROR_FAILED; |
+ } else { |
+ // The read operation failed. |
+ result = PP_ERROR_FAILED; |
+ } |
+ state_manager_.SetOperationFinished(); |
+ return result; |
+} |
+ |
void FileIOResource::OnPluginMsgGeneralComplete( |
scoped_refptr<TrackedCallback> callback, |
const ResourceMessageReplyParams& params) { |
@@ -355,46 +429,6 @@ void FileIOResource::OnPluginMsgOpenFileComplete( |
callback->Run(result); |
} |
-void FileIOResource::OnPluginMsgQueryComplete( |
- scoped_refptr<TrackedCallback> callback, |
- PP_FileInfo* output_info, |
- const ResourceMessageReplyParams& params, |
- const PP_FileInfo& info) { |
- DCHECK(state_manager_.get_pending_operation() == |
- FileIOStateManager::OPERATION_EXCLUSIVE); |
- *output_info = info; |
- // End this operation now, so the user's callback can execute another FileIO |
- // operation, assuming there are no other pending operations. |
- state_manager_.SetOperationFinished(); |
- callback->Run(params.result()); |
-} |
- |
-void FileIOResource::OnPluginMsgReadComplete( |
- scoped_refptr<TrackedCallback> callback, |
- PP_ArrayOutput array_output, |
- const ResourceMessageReplyParams& params, |
- const std::string& data) { |
- DCHECK(state_manager_.get_pending_operation() == |
- FileIOStateManager::OPERATION_READ); |
- |
- // The result code should contain the data size if it's positive. |
- int32_t result = params.result(); |
- DCHECK((result < 0 && data.size() == 0) || |
- result == static_cast<int32_t>(data.size())); |
- |
- ArrayWriter output; |
- output.set_pp_array_output(array_output); |
- if (output.is_valid()) |
- output.StoreArray(data.data(), std::max(0, result)); |
- else |
- result = PP_ERROR_FAILED; |
- |
- // End this operation now, so the user's callback can execute another FileIO |
- // operation, assuming there are no other pending operations. |
- state_manager_.SetOperationFinished(); |
- callback->Run(result); |
-} |
- |
void FileIOResource::OnPluginMsgRequestOSFileHandleComplete( |
scoped_refptr<TrackedCallback> callback, |
PP_FileHandle* output_handle, |