Chromium Code Reviews| 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..8350a871bd00b7a1377455fa5a231a434a2ddb90 100644 |
| --- a/ppapi/proxy/file_io_resource.cc |
| +++ b/ppapi/proxy/file_io_resource.cc |
| @@ -22,6 +22,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,10 +42,19 @@ void DoClose(base::PlatformFile file) { |
| namespace ppapi { |
| namespace proxy { |
| +FileIOResource::ReadData::ReadData(int32_t bytes_to_read) |
| + : buffer_(new char[bytes_to_read]), |
| + bytes_read_(0) { |
| +} |
| + |
| +FileIOResource::ReadData::~ReadData() { |
| +} |
| + |
| FileIOResource::FileIOResource(Connection connection, PP_Instance instance) |
| : PluginResource(connection, instance), |
| file_handle_(base::kInvalidPlatformFileValue), |
| - file_system_type_(PP_FILESYSTEMTYPE_INVALID) { |
| + file_system_type_(PP_FILESYSTEMTYPE_INVALID), |
| + query_result_(0) { |
| SendCreate(RENDERER, PpapiHostMsg_FileIO_Create()); |
| } |
| @@ -92,33 +106,32 @@ 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); |
| - 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()) { |
| { |
| + // 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; |
| + DoQuery(); |
| } |
| - if ((result == PP_OK) && TrackedCallback::IsPending(callback)) { |
| - ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type_, |
| - info); |
| - } |
| - |
| - state_manager_.SetOperationFinished(); |
| - return result; |
| + return OnQueryComplete(info, PP_OK); |
|
dmichael (off chromium)
2013/08/09 17:37:42
I think you could pass the result of the query to
bbudge
2013/08/09 21:43:24
Done.
|
| } |
| - 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. |
| + PpapiGlobals::Get()->GetFileTaskRunner(pp_instance())->PostTaskAndReply( |
| + FROM_HERE, |
| + Bind(&FileIOResource::DoQuery, this), |
| + RunWhileLocked( |
| + Bind(&FileIOResource::OnFileTaskComplete, this, callback))); |
| + callback->set_completion_task( |
| + Bind(&FileIOResource::OnQueryComplete, this, info)); |
| - state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); |
| return PP_OK_COMPLETIONPENDING; |
| } |
| @@ -274,41 +287,33 @@ 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<ReadData> read_data(new ReadData(bytes_to_read)); |
|
dmichael (off chromium)
2013/08/09 17:37:42
It would be better to create an empty ReadData her
bbudge
2013/08/09 21:43:24
It would be messy, as the allocation has to happen
bbudge
2013/08/09 21:58:14
Turns out I was needlessly worried about allocatin
|
| + if (callback->is_blocking()) { |
| + // Release the proxy lock while making a potentially slow file call. |
| + { |
| + ProxyAutoUnlock unlock; |
| + DoRead(offset, bytes_to_read, read_data); |
|
dmichael (off chromium)
2013/08/09 17:37:42
I'm thinking maybe DoRead can return the result (i
bbudge
2013/08/09 21:43:24
Done.
|
| } |
| - |
| - state_manager_.SetOperationFinished(); |
| - return result; |
| + return OnReadComplete(read_data, array_output, PP_OK); |
|
dmichael (off chromium)
2013/08/09 17:37:42
would it work to pass read_data->bytes_read() inst
bbudge
2013/08/09 21:43:24
Done.
|
| } |
| - 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. |
| + PpapiGlobals::Get()->GetFileTaskRunner(pp_instance())->PostTaskAndReply( |
| + FROM_HERE, |
| + Bind(&FileIOResource::DoRead, this, offset, bytes_to_read, read_data), |
| + RunWhileLocked( |
| + Bind(&FileIOResource::OnFileTaskComplete, this, callback))); |
|
dmichael (off chromium)
2013/08/09 17:37:42
If you make OnFileTaskComplete take a result param
bbudge
2013/08/09 21:43:24
Done.
|
| + callback->set_completion_task( |
| + Bind(&FileIOResource::OnReadComplete, this, read_data, array_output)); |
|
dmichael (off chromium)
2013/08/09 17:37:42
If you are able to remove the "result" part of Rea
bbudge
2013/08/09 21:43:24
I couldn't get this to work, since in the abort ca
|
| + |
| return PP_OK_COMPLETIONPENDING; |
| } |
| @@ -324,6 +329,58 @@ void FileIOResource::CloseFileHandle() { |
| } |
| } |
| +void FileIOResource::DoQuery() { |
| + query_result_ = base::GetPlatformFileInfo(file_handle_, &file_info_) ? |
| + PP_OK : PP_ERROR_FAILED; |
| +} |
| + |
| +void FileIOResource::DoRead(int64_t offset, |
| + int32_t bytes_to_read, |
| + scoped_refptr<ReadData> read_data) { |
| + read_data->set_bytes_read(base::ReadPlatformFile( |
| + file_handle_, offset, read_data->buffer(), bytes_to_read)); |
| +} |
| + |
| +void FileIOResource::OnFileTaskComplete( |
| + scoped_refptr<TrackedCallback> callback) { |
| + callback->Run(PP_OK); |
|
dmichael (off chromium)
2013/08/09 17:37:42
I think OnFileTaskComplete should take a result pa
bbudge
2013/08/09 21:43:24
Done.
|
| +} |
| + |
| +int32_t FileIOResource::OnQueryComplete(PP_FileInfo* info, int32_t result) { |
| + DCHECK(state_manager_.get_pending_operation() == |
| + FileIOStateManager::OPERATION_EXCLUSIVE); |
| + |
| + if (result == PP_OK && query_result_ == PP_OK) { |
| + ppapi::PlatformFileInfoToPepperFileInfo(file_info_, file_system_type_, |
| + info); |
| + } |
| + state_manager_.SetOperationFinished(); |
| + return result; |
|
dmichael (off chromium)
2013/08/09 17:37:42
Given the way this is all structured currently, I
bbudge
2013/08/09 21:43:24
Done.
|
| +} |
| + |
| +int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadData> read_data, |
| + PP_ArrayOutput array_output, |
| + int32_t result) { |
| + DCHECK(state_manager_.get_pending_operation() == |
| + FileIOStateManager::OPERATION_READ); |
| + if (result == PP_OK) { |
| + result = read_data->bytes_read(); |
| + if (result >= 0) { |
| + ArrayWriter output; |
| + output.set_pp_array_output(array_output); |
| + if (output.is_valid()) |
| + output.StoreArray(read_data->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 +412,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, |