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

Side by Side Diff: ppapi/proxy/file_io_resource.cc

Issue 22646005: Do PPB_FileIO Query and Read in the plugin process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Defer buffer allocation until we read. Created 7 years, 4 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "ppapi/proxy/file_io_resource.h" 5 #include "ppapi/proxy/file_io_resource.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/task_runner_util.h"
8 #include "ipc/ipc_message.h" 9 #include "ipc/ipc_message.h"
9 #include "ppapi/c/pp_errors.h" 10 #include "ppapi/c/pp_errors.h"
10 #include "ppapi/proxy/ppapi_messages.h" 11 #include "ppapi/proxy/ppapi_messages.h"
11 #include "ppapi/shared_impl/array_writer.h" 12 #include "ppapi/shared_impl/array_writer.h"
12 #include "ppapi/shared_impl/file_type_conversion.h" 13 #include "ppapi/shared_impl/file_type_conversion.h"
13 #include "ppapi/shared_impl/ppapi_globals.h" 14 #include "ppapi/shared_impl/ppapi_globals.h"
14 #include "ppapi/shared_impl/proxy_lock.h" 15 #include "ppapi/shared_impl/proxy_lock.h"
15 #include "ppapi/shared_impl/resource_tracker.h" 16 #include "ppapi/shared_impl/resource_tracker.h"
16 #include "ppapi/thunk/enter.h" 17 #include "ppapi/thunk/enter.h"
17 #include "ppapi/thunk/ppb_file_ref_api.h" 18 #include "ppapi/thunk/ppb_file_ref_api.h"
18 19
19 using ppapi::thunk::EnterResourceNoLock; 20 using ppapi::thunk::EnterResourceNoLock;
20 using ppapi::thunk::PPB_FileIO_API; 21 using ppapi::thunk::PPB_FileIO_API;
21 using ppapi::thunk::PPB_FileRef_API; 22 using ppapi::thunk::PPB_FileRef_API;
22 23
23 namespace { 24 namespace {
24 25
26 // We must allocate a buffer sized according to the request of the plugin. To
27 // reduce the chance of out-of-memory errors, we cap the read size to 32MB.
28 // This is OK since the API specifies that it may perform a partial read.
29 static const int32_t kMaxReadSize = 32 * 1024 * 1024; // 32MB
30
25 // An adapter to let Read() share the same implementation with ReadToArray(). 31 // An adapter to let Read() share the same implementation with ReadToArray().
26 void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) { 32 void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
27 return user_data; 33 return user_data;
28 } 34 }
29 35
30 // File thread task to close the file handle. 36 // File thread task to close the file handle.
31 void DoClose(base::PlatformFile file) { 37 void DoClose(base::PlatformFile file) {
32 base::ClosePlatformFile(file); 38 base::ClosePlatformFile(file);
33 } 39 }
34 40
35 } // namespace 41 } // namespace
36 42
37 namespace ppapi { 43 namespace ppapi {
38 namespace proxy { 44 namespace proxy {
39 45
46 FileIOResource::QueryOp::QueryOp(PP_FileHandle file_handle)
47 : file_handle_(file_handle) {
48 }
49
50 FileIOResource::QueryOp::~QueryOp() {
51 }
52
53 int32_t FileIOResource::QueryOp::DoWork() {
54 return base::GetPlatformFileInfo(file_handle_, &file_info_) ?
55 PP_OK : PP_ERROR_FAILED;
56 }
57
58 FileIOResource::ReadOp::ReadOp(PP_FileHandle file_handle,
59 int64_t offset,
60 int32_t bytes_to_read)
61 : file_handle_(file_handle),
62 offset_(offset),
63 bytes_to_read_(bytes_to_read) {
64 }
65
66 FileIOResource::ReadOp::~ReadOp() {
67 }
68
69 int32_t FileIOResource::ReadOp::DoWork() {
70 DCHECK(!buffer_.get());
71 buffer_.reset(new char[bytes_to_read_]);
72 return base::ReadPlatformFile(
73 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
74 }
75
40 FileIOResource::FileIOResource(Connection connection, PP_Instance instance) 76 FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
41 : PluginResource(connection, instance), 77 : PluginResource(connection, instance),
42 file_handle_(base::kInvalidPlatformFileValue), 78 file_handle_(base::kInvalidPlatformFileValue),
43 file_system_type_(PP_FILESYSTEMTYPE_INVALID) { 79 file_system_type_(PP_FILESYSTEMTYPE_INVALID) {
44 SendCreate(RENDERER, PpapiHostMsg_FileIO_Create()); 80 SendCreate(RENDERER, PpapiHostMsg_FileIO_Create());
45 } 81 }
46 82
47 FileIOResource::~FileIOResource() { 83 FileIOResource::~FileIOResource() {
48 CloseFileHandle(); 84 CloseFileHandle();
49 } 85 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 121 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
86 return PP_OK_COMPLETIONPENDING; 122 return PP_OK_COMPLETIONPENDING;
87 } 123 }
88 124
89 int32_t FileIOResource::Query(PP_FileInfo* info, 125 int32_t FileIOResource::Query(PP_FileInfo* info,
90 scoped_refptr<TrackedCallback> callback) { 126 scoped_refptr<TrackedCallback> callback) {
91 int32_t rv = state_manager_.CheckOperationState( 127 int32_t rv = state_manager_.CheckOperationState(
92 FileIOStateManager::OPERATION_EXCLUSIVE, true); 128 FileIOStateManager::OPERATION_EXCLUSIVE, true);
93 if (rv != PP_OK) 129 if (rv != PP_OK)
94 return rv; 130 return rv;
131 if (!info)
132 return PP_ERROR_BADARGUMENT;
133 if (file_handle_ == base::kInvalidPlatformFileValue)
134 return PP_ERROR_FAILED;
95 135
96 if (callback->is_blocking() && 136 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
97 file_handle_ != base::kInvalidPlatformFileValue) { 137 scoped_refptr<QueryOp> query_op(new QueryOp(file_handle_));
98 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 138
99 int32_t result = PP_ERROR_FAILED; 139 // If the callback is blocking, perform the task on the calling thread.
100 base::PlatformFileInfo file_info; 140 if (callback->is_blocking()) {
101 // Release the proxy lock while making a potentially blocking file call. 141 int32_t result;
102 { 142 {
143 // Release the proxy lock while making a potentially slow file call.
103 ProxyAutoUnlock unlock; 144 ProxyAutoUnlock unlock;
104 result = base::GetPlatformFileInfo(file_handle_, &file_info) ? 145 result = query_op->DoWork();
105 PP_OK : PP_ERROR_FAILED;
106 } 146 }
107 if ((result == PP_OK) && TrackedCallback::IsPending(callback)) { 147 return OnQueryComplete(query_op, info, result);
108 ppapi::PlatformFileInfoToPepperFileInfo(file_info, file_system_type_,
109 info);
110 }
111
112 state_manager_.SetOperationFinished();
113 return result;
114 } 148 }
115 149
116 Call<PpapiPluginMsg_FileIO_QueryReply>(RENDERER, 150 // For the non-blocking case, post a task to the file thread and add a
117 PpapiHostMsg_FileIO_Query(), 151 // completion task to write the result.
118 base::Bind(&FileIOResource::OnPluginMsgQueryComplete, this, 152 base::PostTaskAndReplyWithResult(
119 callback, info)); 153 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
154 FROM_HERE,
155 Bind(&FileIOResource::QueryOp::DoWork, query_op),
156 RunWhileLocked(
157 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.
158 callback->set_completion_task(
159 Bind(&FileIOResource::OnQueryComplete, this, query_op, info));
120 160
121 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
122 return PP_OK_COMPLETIONPENDING; 161 return PP_OK_COMPLETIONPENDING;
123 } 162 }
124 163
125 int32_t FileIOResource::Touch(PP_Time last_access_time, 164 int32_t FileIOResource::Touch(PP_Time last_access_time,
126 PP_Time last_modified_time, 165 PP_Time last_modified_time,
127 scoped_refptr<TrackedCallback> callback) { 166 scoped_refptr<TrackedCallback> callback) {
128 int32_t rv = state_manager_.CheckOperationState( 167 int32_t rv = state_manager_.CheckOperationState(
129 FileIOStateManager::OPERATION_EXCLUSIVE, true); 168 FileIOStateManager::OPERATION_EXCLUSIVE, true);
130 if (rv != PP_OK) 169 if (rv != PP_OK)
131 return rv; 170 return rv;
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback)); 306 base::Bind(&FileIOResource::OnPluginMsgGeneralComplete, this, callback));
268 307
269 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); 308 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE);
270 return PP_OK_COMPLETIONPENDING; 309 return PP_OK_COMPLETIONPENDING;
271 } 310 }
272 311
273 int32_t FileIOResource::ReadValidated(int64_t offset, 312 int32_t FileIOResource::ReadValidated(int64_t offset,
274 int32_t bytes_to_read, 313 int32_t bytes_to_read,
275 const PP_ArrayOutput& array_output, 314 const PP_ArrayOutput& array_output,
276 scoped_refptr<TrackedCallback> callback) { 315 scoped_refptr<TrackedCallback> callback) {
316 if (bytes_to_read < 0)
317 return PP_ERROR_FAILED;
318 if (file_handle_ == base::kInvalidPlatformFileValue)
319 return PP_ERROR_FAILED;
320
277 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ); 321 state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_READ);
278 322
279 if (callback->is_blocking() && 323 bytes_to_read = std::min(bytes_to_read, kMaxReadSize);
280 file_handle_ != base::kInvalidPlatformFileValue) { 324 scoped_refptr<ReadOp> read_op(
281 int32_t result = PP_ERROR_FAILED; 325 new ReadOp(file_handle_, offset, bytes_to_read));
282 if (bytes_to_read >= 0) { 326 if (callback->is_blocking()) {
283 // We need a buffer (and therefore we must copy) since we don't know until 327 int32_t result;
284 // reacquire the lock whether to write data to the plugin's buffer. 328 {
285 scoped_ptr<char[]> buffer; 329 // Release the proxy lock while making a potentially slow file call.
286 // Release the proxy lock while making a potentially blocking file call. 330 ProxyAutoUnlock unlock;
287 { 331 result = read_op->DoWork();
288 ProxyAutoUnlock unlock;
289 buffer.reset(new char[bytes_to_read]);
290 int32_t bytes_read = base::ReadPlatformFile(
291 file_handle_, offset, buffer.get(), bytes_to_read);
292 result = (bytes_read < 0) ? PP_ERROR_FAILED : bytes_read;
293 }
294 if ((result >= 0) && TrackedCallback::IsPending(callback)) {
295 ArrayWriter output;
296 output.set_pp_array_output(array_output);
297 if (output.is_valid())
298 output.StoreArray(buffer.get(), result);
299 else
300 result = PP_ERROR_FAILED;
301 }
302 } 332 }
303 333 return OnReadComplete(read_op, array_output, result);
304 state_manager_.SetOperationFinished();
305 return result;
306 } 334 }
307 335
308 Call<PpapiPluginMsg_FileIO_ReadReply>(RENDERER, 336 // For the non-blocking case, post a task to the file thread.
309 PpapiHostMsg_FileIO_Read(offset, bytes_to_read), 337 base::PostTaskAndReplyWithResult(
310 base::Bind(&FileIOResource::OnPluginMsgReadComplete, this, 338 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()),
311 callback, array_output)); 339 FROM_HERE,
340 Bind(&FileIOResource::ReadOp::DoWork, read_op),
341 RunWhileLocked(
342 Bind(&FileIOResource::OnFileTaskComplete, this, callback)));
dmichael (off chromium) 2013/08/09 22:20:56 ditto
bbudge 2013/08/09 23:05:28 Done.
343 callback->set_completion_task(
344 Bind(&FileIOResource::OnReadComplete, this, read_op, array_output));
345
312 return PP_OK_COMPLETIONPENDING; 346 return PP_OK_COMPLETIONPENDING;
313 } 347 }
314 348
315 void FileIOResource::CloseFileHandle() { 349 void FileIOResource::CloseFileHandle() {
316 if (file_handle_ != base::kInvalidPlatformFileValue) { 350 if (file_handle_ != base::kInvalidPlatformFileValue) {
317 // Close our local fd on the file thread. 351 // Close our local fd on the file thread.
318 base::TaskRunner* file_task_runner = 352 base::TaskRunner* file_task_runner =
319 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance()); 353 PpapiGlobals::Get()->GetFileTaskRunner(pp_instance());
320 file_task_runner->PostTask(FROM_HERE, 354 file_task_runner->PostTask(FROM_HERE,
321 base::Bind(&DoClose, file_handle_)); 355 base::Bind(&DoClose, file_handle_));
322 356
323 file_handle_ = base::kInvalidPlatformFileValue; 357 file_handle_ = base::kInvalidPlatformFileValue;
324 } 358 }
325 } 359 }
326 360
361 void FileIOResource::OnFileTaskComplete(scoped_refptr<TrackedCallback> callback,
362 int32_t result) {
363 callback->Run(result);
364 }
365
366 int32_t FileIOResource::OnQueryComplete(scoped_refptr<QueryOp> query_op,
367 PP_FileInfo* info,
368 int32_t result) {
369 DCHECK(state_manager_.get_pending_operation() ==
370 FileIOStateManager::OPERATION_EXCLUSIVE);
371
372 if (result == PP_OK) {
373 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.
374 file_system_type_,
375 info);
376 }
377 state_manager_.SetOperationFinished();
378 return result;
379 }
380
381 int32_t FileIOResource::OnReadComplete(scoped_refptr<ReadOp> read_op,
382 PP_ArrayOutput array_output,
383 int32_t result) {
384 DCHECK(state_manager_.get_pending_operation() ==
385 FileIOStateManager::OPERATION_READ);
386 if (result >= 0) {
387 ArrayWriter output;
388 output.set_pp_array_output(array_output);
389 if (output.is_valid())
390 output.StoreArray(read_op->buffer(), result);
391 else
392 result = PP_ERROR_FAILED;
393 } else {
394 // The read operation failed.
395 result = PP_ERROR_FAILED;
396 }
397 state_manager_.SetOperationFinished();
398 return result;
399 }
400
327 void FileIOResource::OnPluginMsgGeneralComplete( 401 void FileIOResource::OnPluginMsgGeneralComplete(
328 scoped_refptr<TrackedCallback> callback, 402 scoped_refptr<TrackedCallback> callback,
329 const ResourceMessageReplyParams& params) { 403 const ResourceMessageReplyParams& params) {
330 DCHECK(state_manager_.get_pending_operation() == 404 DCHECK(state_manager_.get_pending_operation() ==
331 FileIOStateManager::OPERATION_EXCLUSIVE || 405 FileIOStateManager::OPERATION_EXCLUSIVE ||
332 state_manager_.get_pending_operation() == 406 state_manager_.get_pending_operation() ==
333 FileIOStateManager::OPERATION_WRITE); 407 FileIOStateManager::OPERATION_WRITE);
334 // End this operation now, so the user's callback can execute another FileIO 408 // End this operation now, so the user's callback can execute another FileIO
335 // operation, assuming there are no other pending operations. 409 // operation, assuming there are no other pending operations.
336 state_manager_.SetOperationFinished(); 410 state_manager_.SetOperationFinished();
(...skipping 11 matching lines...) Expand all
348 int32_t result = params.result(); 422 int32_t result = params.result();
349 IPC::PlatformFileForTransit transit_file; 423 IPC::PlatformFileForTransit transit_file;
350 if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file)) 424 if ((result == PP_OK) && params.TakeFileHandleAtIndex(0, &transit_file))
351 file_handle_ = IPC::PlatformFileForTransitToPlatformFile(transit_file); 425 file_handle_ = IPC::PlatformFileForTransitToPlatformFile(transit_file);
352 // End this operation now, so the user's callback can execute another FileIO 426 // End this operation now, so the user's callback can execute another FileIO
353 // operation, assuming there are no other pending operations. 427 // operation, assuming there are no other pending operations.
354 state_manager_.SetOperationFinished(); 428 state_manager_.SetOperationFinished();
355 callback->Run(result); 429 callback->Run(result);
356 } 430 }
357 431
358 void FileIOResource::OnPluginMsgQueryComplete(
359 scoped_refptr<TrackedCallback> callback,
360 PP_FileInfo* output_info,
361 const ResourceMessageReplyParams& params,
362 const PP_FileInfo& info) {
363 DCHECK(state_manager_.get_pending_operation() ==
364 FileIOStateManager::OPERATION_EXCLUSIVE);
365 *output_info = info;
366 // End this operation now, so the user's callback can execute another FileIO
367 // operation, assuming there are no other pending operations.
368 state_manager_.SetOperationFinished();
369 callback->Run(params.result());
370 }
371
372 void FileIOResource::OnPluginMsgReadComplete(
373 scoped_refptr<TrackedCallback> callback,
374 PP_ArrayOutput array_output,
375 const ResourceMessageReplyParams& params,
376 const std::string& data) {
377 DCHECK(state_manager_.get_pending_operation() ==
378 FileIOStateManager::OPERATION_READ);
379
380 // The result code should contain the data size if it's positive.
381 int32_t result = params.result();
382 DCHECK((result < 0 && data.size() == 0) ||
383 result == static_cast<int32_t>(data.size()));
384
385 ArrayWriter output;
386 output.set_pp_array_output(array_output);
387 if (output.is_valid())
388 output.StoreArray(data.data(), std::max(0, result));
389 else
390 result = PP_ERROR_FAILED;
391
392 // End this operation now, so the user's callback can execute another FileIO
393 // operation, assuming there are no other pending operations.
394 state_manager_.SetOperationFinished();
395 callback->Run(result);
396 }
397
398 void FileIOResource::OnPluginMsgRequestOSFileHandleComplete( 432 void FileIOResource::OnPluginMsgRequestOSFileHandleComplete(
399 scoped_refptr<TrackedCallback> callback, 433 scoped_refptr<TrackedCallback> callback,
400 PP_FileHandle* output_handle, 434 PP_FileHandle* output_handle,
401 const ResourceMessageReplyParams& params) { 435 const ResourceMessageReplyParams& params) {
402 DCHECK(state_manager_.get_pending_operation() == 436 DCHECK(state_manager_.get_pending_operation() ==
403 FileIOStateManager::OPERATION_EXCLUSIVE); 437 FileIOStateManager::OPERATION_EXCLUSIVE);
404 438
405 if (!TrackedCallback::IsPending(callback)) { 439 if (!TrackedCallback::IsPending(callback)) {
406 state_manager_.SetOperationFinished(); 440 state_manager_.SetOperationFinished();
407 return; 441 return;
408 } 442 }
409 443
410 int32_t result = params.result(); 444 int32_t result = params.result();
411 IPC::PlatformFileForTransit transit_file; 445 IPC::PlatformFileForTransit transit_file;
412 if (!params.TakeFileHandleAtIndex(0, &transit_file)) 446 if (!params.TakeFileHandleAtIndex(0, &transit_file))
413 result = PP_ERROR_FAILED; 447 result = PP_ERROR_FAILED;
414 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file); 448 *output_handle = IPC::PlatformFileForTransitToPlatformFile(transit_file);
415 449
416 // End this operation now, so the user's callback can execute another FileIO 450 // End this operation now, so the user's callback can execute another FileIO
417 // operation, assuming there are no other pending operations. 451 // operation, assuming there are no other pending operations.
418 state_manager_.SetOperationFinished(); 452 state_manager_.SetOperationFinished();
419 callback->Run(result); 453 callback->Run(result);
420 } 454 }
421 455
422 } // namespace proxy 456 } // namespace proxy
423 } // namespace ppapi 457 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698