diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-26 19:28:47 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-26 19:28:47 +0000 |
commit | 15b1224dc8e1918d0aa534676e65c802617a739b (patch) | |
tree | 3c7f85eb4fe1338a824b702139cdd0d025ba1651 /ppapi | |
parent | d6d971b26a2a174c4142560999c3f0ad5c33d6d9 (diff) | |
download | chromium_src-15b1224dc8e1918d0aa534676e65c802617a739b.zip chromium_src-15b1224dc8e1918d0aa534676e65c802617a739b.tar.gz chromium_src-15b1224dc8e1918d0aa534676e65c802617a739b.tar.bz2 |
Revert 119200 - Revert 119198 - First pass at implementing the MessageLoop interface. This includes a simple
example and a helper class. The current example just asserts due to thread
checks we have in there now, but this should provide a good starting point.
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com/9097006
TBR=brettw@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9290040
TBR=brettw@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9234068
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119268 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/ppapi_proxy.gypi | 2 | ||||
-rw-r--r-- | ppapi/ppapi_shared.gypi | 1 | ||||
-rw-r--r-- | ppapi/ppapi_sources.gypi | 2 | ||||
-rw-r--r-- | ppapi/proxy/interface_list.cc | 4 | ||||
-rw-r--r-- | ppapi/proxy/ppb_message_loop_proxy.cc | 287 | ||||
-rw-r--r-- | ppapi/proxy/ppb_message_loop_proxy.h | 30 | ||||
-rw-r--r-- | ppapi/shared_impl/resource.h | 1 | ||||
-rw-r--r-- | ppapi/thunk/ppb_message_loop_api.h | 25 |
8 files changed, 352 insertions, 0 deletions
diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index bd50b3b..16081a3 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -99,6 +99,8 @@ 'proxy/ppb_image_data_proxy.h', 'proxy/ppb_instance_proxy.cc', 'proxy/ppb_instance_proxy.h', + 'proxy/ppb_message_loop_proxy.cc', + 'proxy/ppb_message_loop_proxy.h', 'proxy/ppb_pdf_proxy.cc', 'proxy/ppb_pdf_proxy.h', 'proxy/ppb_tcp_socket_private_proxy.cc', diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index 5aff613..4dc7a0f 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -198,6 +198,7 @@ 'thunk/ppb_instance_thunk.cc', 'thunk/ppb_layer_compositor_api.h', 'thunk/ppb_layer_compositor_thunk.cc', + 'thunk/ppb_message_loop_api.h', 'thunk/ppb_messaging_thunk.cc', 'thunk/ppb_mouse_lock_thunk.cc', 'thunk/ppb_pdf_api.h', diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index 4336ff6..e7b869c 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -267,6 +267,8 @@ 'utility/graphics/paint_aggregator.h', 'utility/graphics/paint_manager.cc', 'utility/graphics/paint_manager.h', + 'utility/threading/simple_thread.cc', + 'utility/threading/simple_thread.h', ], # # Common Testing source for trusted and untrusted (NaCl) pugins. diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index f5c4d31..5833a8d 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -17,6 +17,7 @@ #include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h" #include "ppapi/c/dev/ppb_ime_input_event_dev.h" #include "ppapi/c/dev/ppb_memory_dev.h" +#include "ppapi/c/dev/ppb_message_loop_dev.h" #include "ppapi/c/dev/ppb_resource_array_dev.h" #include "ppapi/c/dev/ppb_testing_dev.h" #include "ppapi/c/dev/ppb_text_input_dev.h" @@ -80,6 +81,7 @@ #include "ppapi/proxy/ppb_graphics_3d_proxy.h" #include "ppapi/proxy/ppb_image_data_proxy.h" #include "ppapi/proxy/ppb_instance_proxy.h" +#include "ppapi/proxy/ppb_message_loop_proxy.h" #include "ppapi/proxy/ppb_pdf_proxy.h" #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" #include "ppapi/proxy/ppb_testing_proxy.h" @@ -169,6 +171,8 @@ InterfaceList::InterfaceList() { AddProxy(API_ID_PPP_CLASS, &PPP_Class_Proxy::Create); AddPPB(PPB_CORE_INTERFACE_1_0, API_ID_PPB_CORE, PPB_Core_Proxy::GetPPB_Core_Interface()); + AddPPB(PPB_MESSAGELOOP_DEV_INTERFACE_0_1, API_ID_NONE, + PPB_MessageLoop_Proxy::GetInterface()); AddPPB(PPB_OPENGLES2_INTERFACE_1_0, API_ID_NONE, PPB_OpenGLES2_Shared::GetInterface()); AddPPB(PPB_VAR_INTERFACE_1_1, API_ID_NONE, diff --git a/ppapi/proxy/ppb_message_loop_proxy.cc b/ppapi/proxy/ppb_message_loop_proxy.cc new file mode 100644 index 0000000..5a0cf23 --- /dev/null +++ b/ppapi/proxy/ppb_message_loop_proxy.cc @@ -0,0 +1,287 @@ +// 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/proxy/ppb_message_loop_proxy.h" + +#include <vector> + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/message_loop.h" +#include "base/threading/thread_local_storage.h" +#include "ppapi/c/dev/ppb_message_loop_dev.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_message_loop_api.h" + +using ppapi::thunk::PPB_MessageLoop_API; + +namespace ppapi { +namespace proxy { + +namespace { + +typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop; + +static base::ThreadLocalStorage::Slot tls_slot(base::LINKER_INITIALIZED); + +class MessageLoopResource : public Resource, public PPB_MessageLoop_API { + public: + MessageLoopResource(PP_Instance instance); + virtual ~MessageLoopResource(); + + // Resource overrides. + virtual PPB_MessageLoop_API* AsPPB_MessageLoop_API() OVERRIDE; + + // PPB_MessageLoop_API implementation. + virtual int32_t AttachToCurrentThread() OVERRIDE; + virtual int32_t Run() OVERRIDE; + virtual int32_t PostWork(PP_CompletionCallback callback, + int64_t delay_ms) OVERRIDE; + virtual int32_t PostQuit(PP_Bool should_destroy) OVERRIDE; + + void DetachFromThread(); + + private: + struct TaskInfo { + tracked_objects::Location from_here; + base::Closure closure; + int64 delay_ms; + }; + + // Returns true if the object is associated with the current thread. + bool IsCurrent() const; + + // Handles posting to the message loop if there is one, or the pending queue + // if there isn't. + void PostClosure(const tracked_objects::Location& from_here, + const base::Closure& closure, + int64 delay_ms); + + // TLS destructor function. + static void ReleaseMessageLoop(void* value); + + // Created when we attach to the current thread, since MessageLoop assumes + // that it's created on the thread it will run on. + scoped_ptr<MessageLoop> loop_; + + // Number of invocations of Run currently on the stack. + int nested_invocations_; + + // Set to true when the message loop is destroyed to prevent forther + // posting of work. + bool destroyed_; + + // Set to true if all message loop invocations should exit and that the + // loop should be destroyed once it reaches the outermost Run invocation. + bool should_destroy_; + + // Since we allow tasks to be posted before the message loop is actually + // created (when it's associated with a thread), we keep tasks posted here + // until that happens. Once the loop_ is created, this is unused. + std::vector<TaskInfo> pending_tasks_; + + DISALLOW_COPY_AND_ASSIGN(MessageLoopResource); +}; + +MessageLoopResource::MessageLoopResource(PP_Instance instance) + : Resource(HostResource::MakeInstanceOnly(instance)), + nested_invocations_(0), + destroyed_(false), + should_destroy_(false) { +} + +MessageLoopResource::~MessageLoopResource() { +} + +PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() { + return this; +} + +int32_t MessageLoopResource::AttachToCurrentThread() { + if (tls_slot.initialized()) + return PP_ERROR_INPROGRESS; + // TODO(brettw) check that the current thread can support a message loop. + + // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an + // internal ref and not a plugin ref so the plugin can't accidentally + // release it. This is released by ReleaseMessageLoop(). + AddRef(); + tls_slot.Initialize(&ReleaseMessageLoop); + tls_slot.Set(this); + + loop_.reset(new MessageLoop(MessageLoop::TYPE_DEFAULT)); + + // Post all pending work to the message loop. + for (size_t i = 0; i < pending_tasks_.size(); i++) { + const TaskInfo& info = pending_tasks_[i]; + PostClosure(info.from_here, info.closure, info.delay_ms); + } + pending_tasks_.clear(); + + return PP_OK; +} + +int32_t MessageLoopResource::Run() { + if (!IsCurrent()) + return PP_ERROR_WRONG_THREAD; + // TODO(brettw) prevent this from happening on the main thread & return + // PP_ERROR_BLOCKS_MAIN_THREAD. Maybe have a special constructor for that + // one? + + // TODO(brettw) figure out how to release the lock. Can't run the message + // loop while holding the lock. + nested_invocations_++; + loop_->Run(); + nested_invocations_--; + + if (should_destroy_ && nested_invocations_ == 0) { + loop_.reset(); + destroyed_ = true; + } + return PP_OK; +} + +int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback, + int64_t delay_ms) { + if (!callback.func) + return PP_ERROR_BADARGUMENT; + if (destroyed_) + return PP_ERROR_FAILED; + PostClosure(FROM_HERE, + base::Bind(callback.func, callback.user_data, + static_cast<int32_t>(PP_OK)), + delay_ms); + return PP_OK; +} + +int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) { + if (PP_ToBool(should_destroy)) + should_destroy_ = true; + + if (IsCurrent()) + loop_->Quit(); + else + PostClosure(FROM_HERE, MessageLoop::QuitClosure(), 0); + return PP_OK; +} + +void MessageLoopResource::DetachFromThread() { + // Note that the message loop must be destroyed on the thread is was created + // on. + loop_.reset(); + + // Cancel out the AddRef in AttachToCurrentThread(). + Release(); + // DANGER: may delete this. +} + +bool MessageLoopResource::IsCurrent() const { + if (!tls_slot.initialized()) + return false; // Can't be current if there's nothing in the slot. + return static_cast<const void*>(tls_slot.Get()) == + static_cast<const void*>(this); +} + +void MessageLoopResource::PostClosure( + const tracked_objects::Location& from_here, + const base::Closure& closure, + int64 delay_ms) { + if (loop_.get()) { + loop_->PostDelayedTask(from_here, closure, delay_ms); + } else { + TaskInfo info; + info.from_here = FROM_HERE; + info.closure = closure; + info.delay_ms = delay_ms; + pending_tasks_.push_back(info); + } +} + +// static +void MessageLoopResource::ReleaseMessageLoop(void* value) { + static_cast<MessageLoopResource*>(value)->DetachFromThread(); +} + +// ----------------------------------------------------------------------------- + +PP_Resource Create(PP_Instance instance) { + // Validate the instance. + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return 0; + return (new MessageLoopResource(instance))->GetReference(); +} + +PP_Resource GetForMainThread() { + // TODO(brettw). + return 0; +} + +PP_Resource GetCurrent() { + if (!tls_slot.initialized()) + return 0; + MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>( + tls_slot.Get()); + return loop->GetReference(); +} + +int32_t AttachToCurrentThread(PP_Resource message_loop) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->AttachToCurrentThread(); + return PP_ERROR_BADRESOURCE; +} + +int32_t Run(PP_Resource message_loop) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->Run(); + return PP_ERROR_BADRESOURCE; +} + +int32_t PostWork(PP_Resource message_loop, + PP_CompletionCallback callback, + int64_t delay_ms) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->PostWork(callback, delay_ms); + return PP_ERROR_BADRESOURCE; +} + +int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) { + EnterMessageLoop enter(message_loop, true); + if (enter.succeeded()) + return enter.object()->PostQuit(should_destroy); + return PP_ERROR_BADRESOURCE; +} + +const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = { + &Create, + &GetForMainThread, + &GetCurrent, + &AttachToCurrentThread, + &Run, + &PostWork, + &PostQuit +}; + +} // namespace + +PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher) + : InterfaceProxy(dispatcher) { +} + +PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() { +} + +// static +const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() { + return &ppb_message_loop_interface; +} + +} // namespace proxy +} // namespace ppapi diff --git a/ppapi/proxy/ppb_message_loop_proxy.h b/ppapi/proxy/ppb_message_loop_proxy.h new file mode 100644 index 0000000..aaf120a --- /dev/null +++ b/ppapi/proxy/ppb_message_loop_proxy.h @@ -0,0 +1,30 @@ +// 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_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ +#define PPAPI_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ + +#include "base/basictypes.h" +#include "ppapi/proxy/interface_proxy.h" + +struct PPB_MessageLoop_Dev_0_1; + +namespace ppapi { +namespace proxy { + +class PPB_MessageLoop_Proxy : public InterfaceProxy { + public: + PPB_MessageLoop_Proxy(Dispatcher* dispatcher); + virtual ~PPB_MessageLoop_Proxy(); + + static const PPB_MessageLoop_Dev_0_1* GetInterface(); + + private: + DISALLOW_COPY_AND_ASSIGN(PPB_MessageLoop_Proxy); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_PPB_MESSAGE_LOOP_PROXY_H_ diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h index c0efdb8..1c268b0 100644 --- a/ppapi/shared_impl/resource.h +++ b/ppapi/shared_impl/resource.h @@ -39,6 +39,7 @@ F(PPB_ImageData_API) \ F(PPB_InputEvent_API) \ F(PPB_LayerCompositor_API) \ + F(PPB_MessageLoop_API) \ F(PPB_PDFFont_API) \ F(PPB_ResourceArray_API) \ F(PPB_Scrollbar_API) \ diff --git a/ppapi/thunk/ppb_message_loop_api.h b/ppapi/thunk/ppb_message_loop_api.h new file mode 100644 index 0000000..36f2f1a --- /dev/null +++ b/ppapi/thunk/ppb_message_loop_api.h @@ -0,0 +1,25 @@ +// 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_THUNK_PPB_MESSAGE_LOOP_API_H_ +#define PPAPI_THUNK_PPB_MESSAGE_LOOP_API_H_ + +namespace ppapi { +namespace thunk { + +class PPB_MessageLoop_API { + public: + virtual ~PPB_MessageLoop_API() {} + + virtual int32_t AttachToCurrentThread() = 0; + virtual int32_t Run() = 0; + virtual int32_t PostWork(PP_CompletionCallback callback, + int64_t delay_ms) = 0; + virtual int32_t PostQuit(PP_Bool should_destroy) = 0; +}; + +} // namespace thunk +} // namespace ppapi + +#endif // PPAPI_THUNK_PPB_MESSAGE_LOOP_API_H_ |