diff options
author | teravest@chromium.org <teravest@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-19 20:42:33 +0000 |
---|---|---|
committer | teravest@chromium.org <teravest@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-19 20:42:33 +0000 |
commit | 30e1cb75b8fa46b67cfc7faa146eacdca5e90241 (patch) | |
tree | 2b6b293673d938f49843aa6b76143ca7d5950315 /ppapi | |
parent | ae5df4b22be0cfee27c09c6a1e4721eb0935eab2 (diff) | |
download | chromium_src-30e1cb75b8fa46b67cfc7faa146eacdca5e90241.zip chromium_src-30e1cb75b8fa46b67cfc7faa146eacdca5e90241.tar.gz chromium_src-30e1cb75b8fa46b67cfc7faa146eacdca5e90241.tar.bz2 |
Pepper: Use shared memory for ArrayBufferVar.
This change improves performance for sending ArrayBufferVars between the
plugin and the host. It copies the data from the var into a shared
memory region and sends the shared memory handle over IPC.
This required defining a new message for plugins to request the host to
create shared memory.
BUG=
Review URL: https://chromiumcodereview.appspot.com/11827059
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@189089 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/host/instance_message_filter.cc | 19 | ||||
-rw-r--r-- | ppapi/host/instance_message_filter.h | 41 | ||||
-rw-r--r-- | ppapi/host/ppapi_host.cc | 20 | ||||
-rw-r--r-- | ppapi/host/ppapi_host.h | 11 | ||||
-rw-r--r-- | ppapi/ppapi_host.gypi | 2 | ||||
-rw-r--r-- | ppapi/ppapi_proxy.gypi | 1 | ||||
-rw-r--r-- | ppapi/proxy/handle_converter.cc | 26 | ||||
-rw-r--r-- | ppapi/proxy/plugin_array_buffer_var.cc | 84 | ||||
-rw-r--r-- | ppapi/proxy/plugin_array_buffer_var.h | 16 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.cc | 22 | ||||
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.h | 11 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.h | 11 | ||||
-rw-r--r-- | ppapi/proxy/ppb_instance_proxy.cc | 7 | ||||
-rw-r--r-- | ppapi/proxy/ppp_messaging_proxy.cc | 4 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.cc | 175 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.h | 47 | ||||
-rw-r--r-- | ppapi/shared_impl/test_globals.h | 17 | ||||
-rw-r--r-- | ppapi/shared_impl/var.h | 15 | ||||
-rw-r--r-- | ppapi/shared_impl/var_tracker.cc | 13 | ||||
-rw-r--r-- | ppapi/shared_impl/var_tracker.h | 26 | ||||
-rw-r--r-- | ppapi/tests/test_post_message.cc | 6 |
21 files changed, 544 insertions, 30 deletions
diff --git a/ppapi/host/instance_message_filter.cc b/ppapi/host/instance_message_filter.cc new file mode 100644 index 0000000..229235f --- /dev/null +++ b/ppapi/host/instance_message_filter.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/host/instance_message_filter.h" + +#include "ppapi/host/ppapi_host.h" + +namespace ppapi { +namespace host { + +InstanceMessageFilter::InstanceMessageFilter(PpapiHost* host) : host_(host) { +} + +InstanceMessageFilter::~InstanceMessageFilter() { +} + +} // namespace host +} // namespace ppapi diff --git a/ppapi/host/instance_message_filter.h b/ppapi/host/instance_message_filter.h new file mode 100644 index 0000000..2b072e9 --- /dev/null +++ b/ppapi/host/instance_message_filter.h @@ -0,0 +1,41 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_HOST_INSTANCE_MESSAGE_FILTER_H_ +#define PPAPI_HOST_INSTANCE_MESSAGE_FILTER_H_ + +#include "base/basictypes.h" +#include "ppapi/host/ppapi_host_export.h" + +namespace IPC { +class Message; +} + +namespace ppapi { +namespace host { + +class PpapiHost; + +class PPAPI_HOST_EXPORT InstanceMessageFilter { + public: + explicit InstanceMessageFilter(PpapiHost* host); + virtual ~InstanceMessageFilter(); + + // Processes an instance message from the plugin process. Returns true if the + // message was handled. On false, the PpapiHost will forward the message to + // the next filter. + virtual bool OnInstanceMessageReceived(const IPC::Message& msg) = 0; + + PpapiHost* host() { return host_; } + + private: + PpapiHost* host_; + + DISALLOW_COPY_AND_ASSIGN(InstanceMessageFilter); +}; + +} // namespace host +} // namespace ppapi + +#endif // PPAPI_HOST_INSTANCE_MESSAGE_FILTER_H_ diff --git a/ppapi/host/ppapi_host.cc b/ppapi/host/ppapi_host.cc index 6423f1e..87dfb11 100644 --- a/ppapi/host/ppapi_host.cc +++ b/ppapi/host/ppapi_host.cc @@ -8,6 +8,7 @@ #include "ppapi/c/pp_errors.h" #include "ppapi/host/host_factory.h" #include "ppapi/host/host_message_context.h" +#include "ppapi/host/instance_message_filter.h" #include "ppapi/host/resource_host.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/resource_message_params.h" @@ -33,8 +34,11 @@ PpapiHost::PpapiHost(IPC::Sender* sender, PpapiHost::~PpapiHost() { // Delete these explicitly before destruction since then the host is still - // technically alive in case one of the hosts accesses us from the + // technically alive in case one of the filters accesses us from the // destructor. + instance_message_filters_.clear(); + + // The resources may also want to use us in their destructors. resources_.clear(); pending_resource_hosts_.clear(); } @@ -59,6 +63,15 @@ bool PpapiHost::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() + if (!handled) { + for (size_t i = 0; i < instance_message_filters_.size(); i++) { + if (instance_message_filters_[i]->OnInstanceMessageReceived(msg)) { + handled = true; + break; + } + } + } + return handled; } @@ -94,6 +107,11 @@ void PpapiHost::AddHostFactoryFilter(scoped_ptr<HostFactory> filter) { host_factory_filters_.push_back(filter.release()); } +void PpapiHost::AddInstanceMessageFilter( + scoped_ptr<InstanceMessageFilter> filter) { + instance_message_filters_.push_back(filter.release()); +} + void PpapiHost::OnHostMsgResourceCall( const proxy::ResourceMessageCallParams& params, const IPC::Message& nested_msg) { diff --git a/ppapi/host/ppapi_host.h b/ppapi/host/ppapi_host.h index 5e44d1a..c661a9b 100644 --- a/ppapi/host/ppapi_host.h +++ b/ppapi/host/ppapi_host.h @@ -30,6 +30,7 @@ namespace host { class HostFactory; struct HostMessageContext; +class InstanceMessageFilter; struct ReplyMessageContext; class ResourceHost; @@ -69,6 +70,10 @@ class PPAPI_HOST_EXPORT PpapiHost : public IPC::Sender, public IPC::Listener { // ownership of the pointer. void AddHostFactoryFilter(scoped_ptr<HostFactory> filter); + // Adds the given message filter to the host. The PpapiHost will take + // ownership of the pointer. + void AddInstanceMessageFilter(scoped_ptr<InstanceMessageFilter> filter); + // Returns null if the resource doesn't exist. host::ResourceHost* GetResourceHost(PP_Resource resource) const; @@ -104,6 +109,12 @@ class PPAPI_HOST_EXPORT PpapiHost : public IPC::Sender, public IPC::Listener { // an ObserverList. ScopedVector<HostFactory> host_factory_filters_; + // Filters for instance messages. Note that since we don't support deleting + // these dynamically we don't need to worry about modifications during + // iteration. If we add that capability, this should be replaced with an + // ObserverList. + ScopedVector<InstanceMessageFilter> instance_message_filters_; + typedef std::map<PP_Resource, linked_ptr<ResourceHost> > ResourceMap; ResourceMap resources_; diff --git a/ppapi/ppapi_host.gypi b/ppapi/ppapi_host.gypi index a2afd58..4031c77 100644 --- a/ppapi/ppapi_host.gypi +++ b/ppapi/ppapi_host.gypi @@ -25,6 +25,8 @@ 'host/host_factory.h', 'host/host_message_context.cc', 'host/host_message_context.h', + 'host/instance_message_filter.cc', + 'host/instance_message_filter.h', 'host/message_filter_host.cc', 'host/message_filter_host.h', 'host/ppapi_host.cc', diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index 9978a42..838bbc6 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -88,6 +88,7 @@ 'proxy/plugin_var_tracker.h', 'proxy/ppapi_command_buffer_proxy.h', 'proxy/ppapi_command_buffer_proxy.cc', + 'proxy/ppapi_messages.h', 'proxy/ppapi_message_utils.h', 'proxy/ppb_audio_proxy.cc', 'proxy/ppb_audio_proxy.h', diff --git a/ppapi/proxy/handle_converter.cc b/ppapi/proxy/handle_converter.cc index a669062..ef4102c 100644 --- a/ppapi/proxy/handle_converter.cc +++ b/ppapi/proxy/handle_converter.cc @@ -4,11 +4,15 @@ #include "ppapi/proxy/handle_converter.h" +#include <vector> #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/resource_message_params.h" #include "ppapi/proxy/serialized_handle.h" +#include "ppapi/proxy/serialized_var.h" + +class NaClDescImcShm; namespace IPC { class Message; @@ -28,9 +32,9 @@ void WriteHandle(int handle_index, typedef std::vector<ppapi::proxy::SerializedHandle> Handles; -// We define overload for catching SerializedHandles, so that we can share -// them correctly to the untrusted side, and another for handling all other -// parameters. See ConvertHandlesImpl for how these get used. +// We define overloads for catching SerializedHandles so that we can share +// them correctly to the untrusted side. +// See ConvertHandlesImpl for how these get used. void ConvertHandlesInParam(const ppapi::proxy::SerializedHandle& handle, Handles* handles, IPC::Message* msg, @@ -40,6 +44,20 @@ void ConvertHandlesInParam(const ppapi::proxy::SerializedHandle& handle, WriteHandle((*handle_index)++, handle, msg); } +void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var, + Handles* handles, + IPC::Message* msg, + int* handle_index) { + ppapi::proxy::SerializedHandle *handle = var.GetPluginShmemHandle(); + if (handle) { + handles->push_back(*handle); + if (msg) { + var.WriteRawVarHeader(msg); + WriteHandle((*handle_index)++, *handle, msg); + } + } +} + // For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, // the handles are carried inside the ResourceMessageReplyParams. // NOTE: We only translate handles from host->NaCl. The only kind of @@ -218,6 +236,7 @@ bool HandleConverter::ConvertNativeHandlesToPosix( switch (msg.type()) { CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) + CASE_FOR_MESSAGE(PpapiMsg_PPPMessaging_HandleMessage) CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) case IPC_REPLY_ID: { int id = IPC::SyncMessage::GetMessageId(msg); @@ -232,6 +251,7 @@ bool HandleConverter::ConvertNativeHandlesToPosix( CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl) CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) + CASE_FOR_REPLY(PpapiHostMsg_SharedMemory_CreateSharedMemory) default: // Do nothing for messages we don't know. break; diff --git a/ppapi/proxy/plugin_array_buffer_var.cc b/ppapi/proxy/plugin_array_buffer_var.cc index c9d302f..e990ed8 100644 --- a/ppapi/proxy/plugin_array_buffer_var.cc +++ b/ppapi/proxy/plugin_array_buffer_var.cc @@ -8,28 +8,104 @@ #include <limits> +#include "base/process_util.h" +#include "base/shared_memory.h" +#include "ppapi/c/dev/ppb_buffer_dev.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/serialized_structs.h" +#include "ppapi/shared_impl/host_resource.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_buffer_api.h" + +using base::SharedMemory; +using base::SharedMemoryHandle; +using ppapi::proxy::PluginGlobals; +using ppapi::proxy::PluginResourceTracker; + namespace ppapi { PluginArrayBufferVar::PluginArrayBufferVar(uint32 size_in_bytes) - : buffer_(size_in_bytes) { + : buffer_(size_in_bytes), + plugin_handle_(base::SharedMemory::NULLHandle()), + size_in_bytes_(size_in_bytes) { +} + +PluginArrayBufferVar::PluginArrayBufferVar(uint32 size_in_bytes, + SharedMemoryHandle plugin_handle) + : plugin_handle_(plugin_handle), + size_in_bytes_(size_in_bytes) { } PluginArrayBufferVar::~PluginArrayBufferVar() { + Unmap(); + + if (shmem_.get() == NULL) { + // The SharedMemory destuctor can't close the handle for us. + if (SharedMemory::IsHandleValid(plugin_handle_)) + SharedMemory::CloseHandle(plugin_handle_); + } else { + // Delete SharedMemory, if we have one. + shmem_.reset(); + } } void* PluginArrayBufferVar::Map() { + if (shmem_.get()) + return shmem_->memory(); + if (SharedMemory::IsHandleValid(plugin_handle_)) { + shmem_.reset(new SharedMemory(plugin_handle_, false)); + if (!shmem_->Map(size_in_bytes_)) { + shmem_.reset(); + return NULL; + } + return shmem_->memory(); + } if (buffer_.empty()) return NULL; return &(buffer_[0]); } void PluginArrayBufferVar::Unmap() { - // We don't actually use shared memory yet, so do nothing. + if (shmem_.get()) + shmem_->Unmap(); } uint32 PluginArrayBufferVar::ByteLength() { - return static_cast<uint32>(buffer_.size()); + return size_in_bytes_; } -} // namespace ppapi +bool PluginArrayBufferVar::CopyToNewShmem( + PP_Instance instance, + int* host_handle_id, + SharedMemoryHandle* plugin_out_handle) { + ppapi::proxy::PluginDispatcher* dispatcher = + ppapi::proxy::PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return false; + ppapi::proxy::SerializedHandle plugin_handle; + dispatcher->Send(new PpapiHostMsg_SharedMemory_CreateSharedMemory( + instance, ByteLength(), host_handle_id, &plugin_handle)); + if (!plugin_handle.IsHandleValid() || !plugin_handle.is_shmem() || + *host_handle_id == -1) + return false; + + base::SharedMemoryHandle tmp_handle = plugin_handle.shmem(); + SharedMemory s(tmp_handle, false); + if (!s.Map(ByteLength())) + return false; + memcpy(s.memory(), Map(), ByteLength()); + s.Unmap(); + + // We don't need to keep the shared memory around on the plugin side; + // we've already copied all our data into it. We'll make it invalid + // just to be safe. + *plugin_out_handle = base::SharedMemory::NULLHandle(); + + return true; +} + +} // namespace ppapi diff --git a/ppapi/proxy/plugin_array_buffer_var.h b/ppapi/proxy/plugin_array_buffer_var.h index 2eed216..bcafe8c 100644 --- a/ppapi/proxy/plugin_array_buffer_var.h +++ b/ppapi/proxy/plugin_array_buffer_var.h @@ -8,6 +8,9 @@ #include <vector> #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/shared_memory.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_stdint.h" #include "ppapi/shared_impl/var.h" @@ -18,17 +21,28 @@ namespace ppapi { class PluginArrayBufferVar : public ArrayBufferVar { public: explicit PluginArrayBufferVar(uint32 size_in_bytes); + PluginArrayBufferVar(uint32 size_in_bytes, + base::SharedMemoryHandle plugin_handle); virtual ~PluginArrayBufferVar(); // ArrayBufferVar implementation. virtual void* Map() OVERRIDE; virtual void Unmap() OVERRIDE; virtual uint32 ByteLength() OVERRIDE; + virtual bool CopyToNewShmem( + PP_Instance instance, + int* host_handle, + base::SharedMemoryHandle* plugin_handle) OVERRIDE; private: - // TODO(dmichael): Use shared memory for this. + // Non-shared memory std::vector<uint8> buffer_; + // Shared memory + base::SharedMemoryHandle plugin_handle_; + scoped_ptr<base::SharedMemory> shmem_; + uint32 size_in_bytes_; + DISALLOW_COPY_AND_ASSIGN(PluginArrayBufferVar); }; diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc index 384eb3ec..cff8fa1 100644 --- a/ppapi/proxy/plugin_var_tracker.cc +++ b/ppapi/proxy/plugin_var_tracker.cc @@ -194,6 +194,12 @@ ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) { return new PluginArrayBufferVar(size_in_bytes); } +ArrayBufferVar* PluginVarTracker::CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) { + return new PluginArrayBufferVar(size_in_bytes, handle); +} + void PluginVarTracker::PluginImplementedObjectCreated( PP_Instance instance, const PP_Var& created_var, @@ -369,5 +375,21 @@ scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar( return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar()); } +int PluginVarTracker::TrackSharedMemoryHandle(PP_Instance instance, + base::SharedMemoryHandle handle, + uint32 size_in_bytes) { + NOTREACHED(); + return -1; +} + +bool PluginVarTracker::StopTrackingSharedMemoryHandle( + int id, + PP_Instance instance, + base::SharedMemoryHandle* handle, + uint32* size_in_bytes) { + NOTREACHED(); + return false; +} + } // namesace proxy } // namespace ppapi diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h index 3e287be..a8b229397 100644 --- a/ppapi/proxy/plugin_var_tracker.h +++ b/ppapi/proxy/plugin_var_tracker.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" +#include "base/shared_memory.h" #include "ppapi/c/pp_stdint.h" #include "ppapi/c/pp_var.h" #include "ppapi/proxy/ppapi_proxy_export.h" @@ -59,6 +60,13 @@ class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { // VarTracker public overrides. void DidDeleteInstance(PP_Instance instance) OVERRIDE; + virtual int TrackSharedMemoryHandle(PP_Instance instance, + base::SharedMemoryHandle file, + uint32 size_in_bytes) OVERRIDE; + virtual bool StopTrackingSharedMemoryHandle(int id, + PP_Instance instance, + base::SharedMemoryHandle* handle, + uint32* size_in_bytes) OVERRIDE; // Notification that a plugin-implemented object (PPP_Class) was created by // the plugin or deallocated by WebKit over IPC. @@ -86,6 +94,9 @@ class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { virtual void ObjectGettingZeroRef(VarMap::iterator iter) OVERRIDE; virtual bool DeleteObjectInfoIfNecessary(VarMap::iterator iter) OVERRIDE; virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE; + virtual ArrayBufferVar* CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) OVERRIDE; private: friend struct DefaultSingletonTraits<PluginVarTracker>; diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 9ccd930..6ae94ab 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -1455,6 +1455,17 @@ IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_GetDefaultPrintSettings) IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply, PP_PrintSettings_Dev /* print_settings */) +// Shared memory --------------------------------------------------------------- +// Creates shared memory on the host side, returning a handle to the shared +// memory on the plugin and keeping the memory mapped in on the host. +// We return a "host handle_id" that can be mapped back to the +// handle on the host side by PpapiGlobals::UntrackSharedMemoryHandle(). +IPC_SYNC_MESSAGE_CONTROL2_2(PpapiHostMsg_SharedMemory_CreateSharedMemory, + PP_Instance /* instance */, + uint32_t /* size */, + int /* host_handle_id */, + ppapi::proxy::SerializedHandle /* plugin_handle */) + // WebSocket ------------------------------------------------------------------ IPC_MESSAGE_CONTROL0(PpapiHostMsg_WebSocket_Create) diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc index 58b1593..bc51675 100644 --- a/ppapi/proxy/ppb_instance_proxy.cc +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -680,7 +680,8 @@ void PPB_Instance_Proxy::PostMessage(PP_Instance instance, PP_Var message) { dispatcher()->Send(new PpapiHostMsg_PPBInstance_PostMessage( API_ID_PPB_INSTANCE, - instance, SerializedVarSendInput(dispatcher(), message))); + instance, SerializedVarSendInputShmem(dispatcher(), message, + instance))); } PP_Bool PPB_Instance_Proxy::SetCursor(PP_Instance instance, @@ -912,7 +913,9 @@ void PPB_Instance_Proxy::OnHostMsgPostMessage( SerializedVarReceiveInput message) { EnterInstanceNoLock enter(instance); if (enter.succeeded()) - enter.functions()->PostMessage(instance, message.Get(dispatcher())); + enter.functions()->PostMessage(instance, + message.GetForInstance(dispatcher(), + instance)); } void PPB_Instance_Proxy::OnHostMsgLockMouse(PP_Instance instance) { diff --git a/ppapi/proxy/ppp_messaging_proxy.cc b/ppapi/proxy/ppp_messaging_proxy.cc index 690e874..5a12419 100644 --- a/ppapi/proxy/ppp_messaging_proxy.cc +++ b/ppapi/proxy/ppp_messaging_proxy.cc @@ -34,7 +34,7 @@ void HandleMessage(PP_Instance instance, PP_Var message_data) { dispatcher->Send(new PpapiMsg_PPPMessaging_HandleMessage( API_ID_PPP_MESSAGING, instance, - SerializedVarSendInput(dispatcher, message_data))); + SerializedVarSendInputShmem(dispatcher, message_data, instance))); } static const PPP_Messaging messaging_interface = { @@ -90,7 +90,7 @@ bool PPP_Messaging_Proxy::OnMessageReceived(const IPC::Message& msg) { void PPP_Messaging_Proxy::OnMsgHandleMessage( PP_Instance instance, SerializedVarReceiveInput message_data) { - PP_Var received_var(message_data.Get(dispatcher())); + PP_Var received_var(message_data.GetForInstance(dispatcher(), instance)); // SerializedVarReceiveInput will decrement the reference count, but we want // to give the recipient a reference. PpapiGlobals::Get()->GetVarTracker()->AddRefVar(received_var); diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc index 5352e8f..698d920 100644 --- a/ppapi/proxy/serialized_var.cc +++ b/ppapi/proxy/serialized_var.cc @@ -6,20 +6,29 @@ #include "base/logging.h" #include "ipc/ipc_message_utils.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/proxy/dispatcher.h" #include "ppapi/proxy/interface_proxy.h" #include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/ppb_buffer_proxy.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/var.h" +#include "ppapi/thunk/enter.h" namespace ppapi { namespace proxy { +// When sending array buffers, if the size is over 256K, we use shared +// memory instead of sending the data over IPC. Light testing suggests +// shared memory is much faster for 256K and larger messages. +static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024; + // SerializedVar::Inner -------------------------------------------------------- SerializedVar::Inner::Inner() : serialization_rules_(NULL), var_(PP_MakeUndefined()), + instance_(0), cleanup_mode_(CLEANUP_NONE) { #ifndef NDEBUG has_been_serialized_ = false; @@ -30,6 +39,7 @@ SerializedVar::Inner::Inner() SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) : serialization_rules_(serialization_rules), var_(PP_MakeUndefined()), + instance_(0), cleanup_mode_(CLEANUP_NONE) { #ifndef NDEBUG has_been_serialized_ = false; @@ -65,11 +75,30 @@ void SerializedVar::Inner::SetVar(PP_Var var) { raw_var_data_.reset(NULL); } +void SerializedVar::Inner::SetInstance(PP_Instance instance) { + instance_ = instance; +} + void SerializedVar::Inner::ForceSetVarValueForTest(PP_Var value) { var_ = value; raw_var_data_.reset(NULL); } +void SerializedVar::Inner::WriteRawVarHeader(IPC::Message* m) const { + // Write raw_var_data_ when we're called from + // chrome/nacl/nacl_ipc_adapter.cc. + DCHECK(raw_var_data_.get()); + DCHECK_EQ(PP_VARTYPE_ARRAY_BUFFER, raw_var_data_->type); + DCHECK(raw_var_data_->shmem_size != 0); + + // The serialization for this message MUST MATCH the implementation at + // SerializedVar::Inner::WriteToMessage for ARRAY_BUFFER_SHMEM_PLUGIN. + m->WriteInt(static_cast<int>(raw_var_data_->type)); + m->WriteInt(ARRAY_BUFFER_SHMEM_PLUGIN); + m->WriteInt(raw_var_data_->shmem_size); + // NaClIPCAdapter will write the handles for us. +} + void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { // When writing to the IPC messages, a serialization rules handler should // always have been set. @@ -124,14 +153,45 @@ void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { // handle the invalid string as if it was in process rather than seeing // what looks like a valid empty ArraryBuffer. ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var_); - if (buffer_var) { - // TODO(dmichael): If it wasn't already Mapped, Unmap it. (Though once - // we use shared memory, this will probably be - // completely different anyway). - m->WriteData(static_cast<const char*>(buffer_var->Map()), - buffer_var->ByteLength()); - } else { - m->WriteData(NULL, 0); + bool using_shmem = false; + if (buffer_var && + buffer_var->ByteLength() >= kMinimumArrayBufferSizeForShmem && + instance_ != 0) { + int host_shm_handle_id; + base::SharedMemoryHandle plugin_shm_handle; + using_shmem = buffer_var->CopyToNewShmem(instance_, + &host_shm_handle_id, + &plugin_shm_handle); + if (using_shmem) { + // The serialization for this message MUST MATCH the implementation + // at SerializedVar::Inner::WriteRawVarHeader for + // ARRAY_BUFFER_SHMEM_PLUGIN. + if (host_shm_handle_id != -1) { + DCHECK(!base::SharedMemory::IsHandleValid(plugin_shm_handle)); + DCHECK(PpapiGlobals::Get()->IsPluginGlobals()); + m->WriteInt(ARRAY_BUFFER_SHMEM_HOST); + m->WriteInt(host_shm_handle_id); + } else { + DCHECK(base::SharedMemory::IsHandleValid(plugin_shm_handle)); + DCHECK(PpapiGlobals::Get()->IsHostGlobals()); + m->WriteInt(ARRAY_BUFFER_SHMEM_PLUGIN); + m->WriteInt(buffer_var->ByteLength()); + SerializedHandle handle(plugin_shm_handle, + buffer_var->ByteLength()); + IPC::ParamTraits<SerializedHandle>::Write(m, handle); + } + } + } + if (!using_shmem) { + if (buffer_var) { + m->WriteInt(ARRAY_BUFFER_NO_SHMEM); + m->WriteData(static_cast<const char*>(buffer_var->Map()), + buffer_var->ByteLength()); + } else { + // TODO(teravest): Introduce an ARRAY_BUFFER_EMPTY message type. + m->WriteBool(ARRAY_BUFFER_NO_SHMEM); + m->WriteData(NULL, 0); + } } break; } @@ -159,7 +219,6 @@ bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, DCHECK(!has_been_deserialized_); has_been_deserialized_ = true; #endif - // When reading, the dispatcher should be set when we get a Deserialize // call (which will supply a dispatcher). int type; @@ -197,11 +256,40 @@ bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, case PP_VARTYPE_ARRAY_BUFFER: { int length = 0; const char* message_bytes = NULL; - success = m->ReadData(iter, &message_bytes, &length); + int shmem_type; + success = m->ReadInt(iter, &shmem_type); if (success) { - raw_var_data_.reset(new RawVarData); - raw_var_data_->type = PP_VARTYPE_ARRAY_BUFFER; - raw_var_data_->data.assign(message_bytes, length); + if (shmem_type == ARRAY_BUFFER_NO_SHMEM) { + success = m->ReadData(iter, &message_bytes, &length); + if (success) { + raw_var_data_.reset(new RawVarData); + raw_var_data_->type = PP_VARTYPE_ARRAY_BUFFER; + raw_var_data_->shmem_type = static_cast<ShmemType>(shmem_type); + raw_var_data_->shmem_size = 0; + raw_var_data_->data.assign(message_bytes, length); + } + } else if (shmem_type == ARRAY_BUFFER_SHMEM_HOST) { + int host_handle_id; + success = m->ReadInt(iter, &host_handle_id); + if (success) { + raw_var_data_.reset(new RawVarData); + raw_var_data_->type = PP_VARTYPE_ARRAY_BUFFER; + raw_var_data_->shmem_type = static_cast<ShmemType>(shmem_type); + raw_var_data_->host_handle_id = host_handle_id; + } + } else if (shmem_type == ARRAY_BUFFER_SHMEM_PLUGIN) { + SerializedHandle plugin_handle; + success = m->ReadInt(iter, &length); + success &= IPC::ParamTraits<SerializedHandle>::Read( + m, iter, &plugin_handle); + if (success) { + raw_var_data_.reset(new RawVarData); + raw_var_data_->type = PP_VARTYPE_ARRAY_BUFFER; + raw_var_data_->shmem_type = static_cast<ShmemType>(shmem_type); + raw_var_data_->shmem_size = length; + raw_var_data_->plugin_handle = plugin_handle; + } + } } break; } @@ -237,6 +325,9 @@ void SerializedVar::Inner::SetCleanupModeToEndReceiveCallerOwned() { } void SerializedVar::Inner::ConvertRawVarData() { +#if defined(NACL_WIN64) + NOTREACHED(); +#else if (!raw_var_data_.get()) return; @@ -248,15 +339,49 @@ void SerializedVar::Inner::ConvertRawVarData() { break; } case PP_VARTYPE_ARRAY_BUFFER: { - var_ = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( - static_cast<uint32>(raw_var_data_->data.size()), - raw_var_data_->data.data()); + if (raw_var_data_->shmem_type == ARRAY_BUFFER_SHMEM_HOST) { + base::SharedMemoryHandle host_handle; + uint32 size_in_bytes; + bool ok = + PpapiGlobals::Get()->GetVarTracker()-> + StopTrackingSharedMemoryHandle(raw_var_data_->host_handle_id, + instance_, + &host_handle, + &size_in_bytes); + if (ok) { + var_ = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + size_in_bytes, host_handle); + } else { + LOG(ERROR) << "Couldn't find array buffer id: " + << raw_var_data_->host_handle_id; + var_ = PP_MakeUndefined(); + } + } else if (raw_var_data_->shmem_type == ARRAY_BUFFER_SHMEM_PLUGIN) { + var_ = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + raw_var_data_->shmem_size, + raw_var_data_->plugin_handle.shmem()); + } else { + var_ = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( + static_cast<uint32>(raw_var_data_->data.size()), + raw_var_data_->data.data()); + } break; } default: NOTREACHED(); } raw_var_data_.reset(NULL); +#endif +} + +SerializedHandle* SerializedVar::Inner::GetPluginShmemHandle() const { + if (raw_var_data_.get()) { + if (raw_var_data_->type == PP_VARTYPE_ARRAY_BUFFER) { + if (raw_var_data_->shmem_size != 0) + return &raw_var_data_->plugin_handle; + } + } + return NULL; } // SerializedVar --------------------------------------------------------------- @@ -289,6 +414,17 @@ void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, output->push_back(SerializedVarSendInput(dispatcher, input[i])); } +// SerializedVarSendInputShmem ------------------------------------------------- + +SerializedVarSendInputShmem::SerializedVarSendInputShmem( + Dispatcher* dispatcher, + const PP_Var& var, + const PP_Instance& instance) + : SerializedVar(dispatcher->serialization_rules()) { + inner_->SetVar(dispatcher->serialization_rules()->SendCallerOwned(var)); + inner_->SetInstance(instance); +} + // ReceiveSerializedVarReturnValue --------------------------------------------- ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { @@ -394,6 +530,13 @@ PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { return serialized_.inner_->GetVar(); } + +PP_Var SerializedVarReceiveInput::GetForInstance(Dispatcher* dispatcher, + PP_Instance instance) { + serialized_.inner_->SetInstance(instance); + return Get(dispatcher); +} + // SerializedVarVectorReceiveInput --------------------------------------------- SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h index 3b74a3e..f283590 100644 --- a/ppapi/proxy/serialized_var.h +++ b/ppapi/proxy/serialized_var.h @@ -11,8 +11,12 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/shared_memory.h" +#include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_var.h" #include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/proxy/serialized_handle.h" +#include "ppapi/proxy/serialized_structs.h" #include "ppapi/proxy/var_serialization_rules.h" class PickleIterator; @@ -79,11 +83,20 @@ class PPAPI_PROXY_EXPORT SerializedVar { return inner_->ReadFromMessage(m, iter); } + // Used by chrome/nacl/nacl_ipc_adapter.cc + SerializedHandle* GetPluginShmemHandle() const { + return inner_->GetPluginShmemHandle(); + } + void WriteRawVarHeader(IPC::Message* m) const { + inner_->WriteRawVarHeader(m); + } + protected: friend class SerializedVarReceiveInput; friend class SerializedVarReturnValue; friend class SerializedVarOutParam; friend class SerializedVarSendInput; + friend class SerializedVarSendInputShmem; friend class SerializedVarTestConstructor; friend class SerializedVarVectorReceiveInput; @@ -103,6 +116,7 @@ class PPAPI_PROXY_EXPORT SerializedVar { // See outer class's declarations above. PP_Var GetVar(); void SetVar(PP_Var var); + void SetInstance(PP_Instance instance); // For the SerializedVarTestConstructor, this writes the Var value as if // it was just received off the wire, without any serialization rules. @@ -115,6 +129,12 @@ class PPAPI_PROXY_EXPORT SerializedVar { void SetCleanupModeToEndSendPassRef(); void SetCleanupModeToEndReceiveCallerOwned(); + // Returns a handle in the underlying data, if it exists. + SerializedHandle* GetPluginShmemHandle() const; + + // Writes raw var data, excluding handles. + void WriteRawVarHeader(IPC::Message* m) const; + private: enum CleanupMode { // The serialized var won't do anything special in the destructor @@ -128,6 +148,13 @@ class PPAPI_PROXY_EXPORT SerializedVar { END_RECEIVE_CALLER_OWNED }; + // Enum for array buffer message types. + enum ShmemType { + ARRAY_BUFFER_NO_SHMEM, + ARRAY_BUFFER_SHMEM_HOST, + ARRAY_BUFFER_SHMEM_PLUGIN, + }; + // ReadFromMessage() may be called on the I/O thread, e.g., when reading the // reply to a sync message. We cannot use the var tracker on the I/O thread, // which means we cannot create PP_Var for PP_VARTYPE_STRING and @@ -136,7 +163,11 @@ class PPAPI_PROXY_EXPORT SerializedVar { // the main thread. struct RawVarData { PP_VarType type; + ShmemType shmem_type; std::string data; + uint32 shmem_size; + int host_handle_id; + SerializedHandle plugin_handle; }; // Converts |raw_var_data_| to |var_|. It is a no-op if |raw_var_data_| is @@ -158,6 +189,8 @@ class PPAPI_PROXY_EXPORT SerializedVar { // a string ID. Before this, the as_id will be 0 for VARTYPE_STRING. PP_Var var_; + PP_Instance instance_; + CleanupMode cleanup_mode_; #ifndef NDEBUG @@ -208,6 +241,19 @@ class PPAPI_PROXY_EXPORT SerializedVarSendInput : public SerializedVar { SerializedVarSendInput(); }; +// Specialization for optionally sending over shared memory. +class PPAPI_PROXY_EXPORT SerializedVarSendInputShmem : public SerializedVar { + public: + SerializedVarSendInputShmem(Dispatcher* dispatcher, const PP_Var& var, + const PP_Instance& instance); + + private: + // Disallow the empty constructor, but keep the default copy constructor + // which is required to send the object to the IPC system. + SerializedVarSendInputShmem(); +}; + + // For the calling side of a function returning a var. The sending side uses // SerializedVarReturnValue. // @@ -324,6 +370,7 @@ class PPAPI_PROXY_EXPORT SerializedVarReceiveInput { ~SerializedVarReceiveInput(); PP_Var Get(Dispatcher* dispatcher); + PP_Var GetForInstance(Dispatcher* dispatcher, PP_Instance instance); private: const SerializedVar& serialized_; diff --git a/ppapi/shared_impl/test_globals.h b/ppapi/shared_impl/test_globals.h index 68a997a..5579b09 100644 --- a/ppapi/shared_impl/test_globals.h +++ b/ppapi/shared_impl/test_globals.h @@ -6,6 +6,7 @@ #define PPAPI_SHARED_IMPL_TEST_GLOBALS_H_ #include "base/compiler_specific.h" +#include "base/shared_memory.h" #include "ppapi/shared_impl/callback_tracker.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/resource_tracker.h" @@ -20,8 +21,24 @@ class TestVarTracker : public VarTracker { virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE { return NULL; } + virtual ArrayBufferVar* CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) OVERRIDE { + return NULL; + } virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE { } + virtual int TrackSharedMemoryHandle(PP_Instance instance, + base::SharedMemoryHandle handle, + uint32 size_in_bytes) OVERRIDE { + return -1; + } + virtual bool StopTrackingSharedMemoryHandle(int id, + PP_Instance instance, + base::SharedMemoryHandle* handle, + uint32* size_in_bytes) OVERRIDE { + return false; + } }; // Implementation of PpapiGlobals for tests that don't need either the host- or diff --git a/ppapi/shared_impl/var.h b/ppapi/shared_impl/var.h index d5e33d5..50c13b9 100644 --- a/ppapi/shared_impl/var.h +++ b/ppapi/shared_impl/var.h @@ -9,7 +9,10 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" +#include "base/platform_file.h" +#include "base/shared_memory.h" #include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/host_resource.h" #include "ppapi/shared_impl/ppapi_shared_export.h" namespace ppapi { @@ -160,6 +163,18 @@ class PPAPI_SHARED_EXPORT ArrayBufferVar : public Var { virtual void Unmap() = 0; virtual uint32 ByteLength() = 0; + // Creates a new shared memory region, and copies the data in the + // ArrayBufferVar into it. On the plugin side, host_shm_handle_id will be set + // to some value that is not -1. On the host side, plugin_shm_handle will be + // set to a valid SharedMemoryHandle. + // + // Returns true if creating the shared memory (and copying) is successful, + // false otherwise. + virtual bool CopyToNewShmem( + PP_Instance instance, + int *host_shm_handle_id, + base::SharedMemoryHandle *plugin_shm_handle) = 0; + // Var override. virtual ArrayBufferVar* AsArrayBufferVar() OVERRIDE; virtual PP_VarType GetType() const OVERRIDE; diff --git a/ppapi/shared_impl/var_tracker.cc b/ppapi/shared_impl/var_tracker.cc index a704c3a..434121e 100644 --- a/ppapi/shared_impl/var_tracker.cc +++ b/ppapi/shared_impl/var_tracker.cc @@ -9,6 +9,8 @@ #include <limits> #include "base/logging.h" +#include "base/shared_memory.h" +#include "ppapi/shared_impl/host_resource.h" #include "ppapi/shared_impl/id_assignment.h" #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/var.h" @@ -216,6 +218,17 @@ ArrayBufferVar* VarTracker::MakeArrayBufferVar(uint32 size_in_bytes, return array_buffer; } +PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes, + base::SharedMemoryHandle handle) { + DCHECK(CalledOnValidThread()); + + scoped_refptr<ArrayBufferVar> array_buffer( + CreateShmArrayBuffer(size_in_bytes, handle)); + if (!array_buffer) + return PP_MakeNull(); + return array_buffer->GetPPVar(); +} + std::vector<PP_Var> VarTracker::GetLiveVars() { DCHECK(CalledOnValidThread()); ProxyLock::AssertAcquired(); diff --git a/ppapi/shared_impl/var_tracker.h b/ppapi/shared_impl/var_tracker.h index 1d0c0d6..32acdeb 100644 --- a/ppapi/shared_impl/var_tracker.h +++ b/ppapi/shared_impl/var_tracker.h @@ -10,10 +10,13 @@ #include "base/basictypes.h" #include "base/hash_tables.h" #include "base/memory/ref_counted.h" +#include "base/shared_memory.h" #include "base/threading/non_thread_safe.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_module.h" +#include "ppapi/c/pp_resource.h" #include "ppapi/c/pp_var.h" +#include "ppapi/shared_impl/host_resource.h" #include "ppapi/shared_impl/ppapi_shared_export.h" namespace ppapi { @@ -72,6 +75,10 @@ class PPAPI_SHARED_EXPORT VarTracker PP_Var MakeArrayBufferPPVar(uint32 size_in_bytes); // Same as above, but copy the contents of |data| in to the new array buffer. PP_Var MakeArrayBufferPPVar(uint32 size_in_bytes, const void* data); + // Same as above, but copy the contents of the shared memory in |h| + // into the new array buffer. + PP_Var MakeArrayBufferPPVar(uint32 size_in_bytes, + base::SharedMemoryHandle h); // Create an ArrayBuffer and copy the contents of |data| in to it. The // returned object has 0 reference count in the tracker, and like all @@ -94,6 +101,22 @@ class PPAPI_SHARED_EXPORT VarTracker // Called after an instance is deleted to do var cleanup. virtual void DidDeleteInstance(PP_Instance instance) = 0; + // Returns an "id" for a shared memory handle that can be safely sent between + // the host and plugin, and resolved back into the original handle on the + // host. Not implemented on the plugin side. + virtual int TrackSharedMemoryHandle(PP_Instance instance, + base::SharedMemoryHandle handle, + uint32 size_in_bytes) = 0; + + // Resolves an "id" generated by TrackSharedMemoryHandle back into + // a SharedMemory handle and its size on the host. + // Not implemented on the plugin side. + virtual bool StopTrackingSharedMemoryHandle( + int id, + PP_Instance instance, + base::SharedMemoryHandle *handle, + uint32* size_in_bytes) = 0; + protected: struct VarInfo { VarInfo(); @@ -171,6 +194,9 @@ class PPAPI_SHARED_EXPORT VarTracker // implemented by the Host and Plugin tracker separately, so that it can be // a real WebKit ArrayBuffer on the host side. virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) = 0; + virtual ArrayBufferVar* CreateShmArrayBuffer( + uint32 size_in_bytes, + base::SharedMemoryHandle handle) = 0; DISALLOW_COPY_AND_ASSIGN(VarTracker); }; diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc index 68fe633..8b16620 100644 --- a/ppapi/tests/test_post_message.cc +++ b/ppapi/tests/test_post_message.cc @@ -261,7 +261,11 @@ std::string TestPostMessage::TestSendingArrayBuffer() { // TODO(sehr,dmichael): Add testing of longer array buffers when // crbug.com/110086 is fixed. - uint32_t sizes[] = { 0, 100, 1000, 10000, 100000 }; +#if defined(OS_LINUX) + uint32_t sizes[] = { 0, 100, 1000, 10000, 100000, 1000000 }; +#else + uint32_t sizes[] = { 0, 100, 1000, 10000, 100000 }; +#endif for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) { std::ostringstream size_stream; size_stream << sizes[i]; |