blob: a42608cb8541df9d504178bc7c0e0acd17004d87 [file] [log] [blame]
[email protected]15b12242012-01-26 19:28:471// 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
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppb_message_loop_proxy.h"
6
avie029c4132015-12-23 06:45:227#include <stddef.h>
8
Peter Boströmfb60ea02021-04-05 21:06:129#include <memory>
[email protected]15b12242012-01-26 19:28:4710#include <vector>
11
12#include "base/bind.h"
danakjdb9ae7942020-11-11 16:01:3513#include "base/callback_helpers.h"
Hans Wennborg708fa822020-04-27 17:23:1514#include "base/check.h"
[email protected]15b12242012-01-26 19:28:4715#include "base/compiler_specific.h"
gabb19326e2016-05-11 18:10:3116#include "base/threading/thread_task_runner_handle.h"
[email protected]15b12242012-01-26 19:28:4717#include "ppapi/c/pp_errors.h"
[email protected]d4ab94712012-11-15 21:01:2318#include "ppapi/c/ppb_message_loop.h"
[email protected]15b12242012-01-26 19:28:4719#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]9d11bb462012-02-05 03:07:3920#include "ppapi/proxy/plugin_globals.h"
[email protected]aed96532012-06-23 14:27:4221#include "ppapi/shared_impl/proxy_lock.h"
[email protected]15b12242012-01-26 19:28:4722#include "ppapi/thunk/enter.h"
[email protected]15b12242012-01-26 19:28:4723
24using ppapi::thunk::PPB_MessageLoop_API;
25
26namespace ppapi {
27namespace proxy {
28
29namespace {
[email protected]15b12242012-01-26 19:28:4730typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop;
[email protected]6de743a2012-08-30 20:03:2231}
[email protected]15b12242012-01-26 19:28:4732
33MessageLoopResource::MessageLoopResource(PP_Instance instance)
[email protected]77c34172012-11-08 18:55:1634 : MessageLoopShared(instance),
[email protected]15b12242012-01-26 19:28:4735 nested_invocations_(0),
36 destroyed_(false),
[email protected]6de743a2012-08-30 20:03:2237 should_destroy_(false),
dmichael44b967542014-09-24 15:41:1438 is_main_thread_loop_(false),
39 currently_handling_blocking_message_(false) {
[email protected]15b12242012-01-26 19:28:4740}
41
[email protected]77c34172012-11-08 18:55:1642MessageLoopResource::MessageLoopResource(ForMainThread for_main_thread)
43 : MessageLoopShared(for_main_thread),
[email protected]6de743a2012-08-30 20:03:2244 nested_invocations_(0),
45 destroyed_(false),
46 should_destroy_(false),
dmichael44b967542014-09-24 15:41:1447 is_main_thread_loop_(true),
48 currently_handling_blocking_message_(false) {
[email protected]6de743a2012-08-30 20:03:2249 // We attach the main thread immediately. We can't use AttachToCurrentThread,
50 // because the MessageLoop already exists.
51
52 // This must be called only once, so the slot must be empty.
53 CHECK(!PluginGlobals::Get()->msg_loop_slot());
[email protected]f137d06c2013-01-03 12:10:0054 // We don't add a reference for TLS here, so we don't release it. Instead,
55 // this loop is owned by PluginGlobals. Contrast with AttachToCurrentThread
56 // where we register ReleaseMessageLoop with TLS and call AddRef.
57 base::ThreadLocalStorage::Slot* slot = new base::ThreadLocalStorage::Slot();
[email protected]6de743a2012-08-30 20:03:2258 PluginGlobals::Get()->set_msg_loop_slot(slot);
59
[email protected]6de743a2012-08-30 20:03:2260 slot->Set(this);
61
skyostil23490d42015-06-12 12:54:2662 task_runner_ = base::ThreadTaskRunnerHandle::Get();
[email protected]6de743a2012-08-30 20:03:2263}
64
65
[email protected]15b12242012-01-26 19:28:4766MessageLoopResource::~MessageLoopResource() {
67}
68
69PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() {
70 return this;
71}
72
73int32_t MessageLoopResource::AttachToCurrentThread() {
[email protected]6de743a2012-08-30 20:03:2274 if (is_main_thread_loop_)
75 return PP_ERROR_INPROGRESS;
76
[email protected]9d11bb462012-02-05 03:07:3977 PluginGlobals* globals = PluginGlobals::Get();
78
79 base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot();
80 if (!slot) {
81 slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop);
82 globals->set_msg_loop_slot(slot);
83 } else {
84 if (slot->Get())
85 return PP_ERROR_INPROGRESS;
86 }
Alex Clarkef7fb8a82019-06-06 15:41:5387 // TODO(dmichael) check that the current thread can support a task executor.
[email protected]15b12242012-01-26 19:28:4788
89 // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an
90 // internal ref and not a plugin ref so the plugin can't accidentally
91 // release it. This is released by ReleaseMessageLoop().
92 AddRef();
[email protected]9d11bb462012-02-05 03:07:3993 slot->Set(this);
[email protected]15b12242012-01-26 19:28:4794
Peter Boströmfb60ea02021-04-05 21:06:1295 single_thread_task_executor_ =
96 std::make_unique<base::SingleThreadTaskExecutor>();
skyostil23490d42015-06-12 12:54:2697 task_runner_ = base::ThreadTaskRunnerHandle::Get();
[email protected]15b12242012-01-26 19:28:4798
Alex Clarkef7fb8a82019-06-06 15:41:5399 // Post all pending work to the task executor.
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47100 for (auto& info : pending_tasks_) {
101 PostClosure(info.from_here, std::move(info.closure), info.delay_ms);
[email protected]15b12242012-01-26 19:28:47102 }
103 pending_tasks_.clear();
104
105 return PP_OK;
106}
107
108int32_t MessageLoopResource::Run() {
109 if (!IsCurrent())
110 return PP_ERROR_WRONG_THREAD;
[email protected]6de743a2012-08-30 20:03:22111 if (is_main_thread_loop_)
112 return PP_ERROR_INPROGRESS;
[email protected]15b12242012-01-26 19:28:47113
fdoray2df4a9e2016-07-18 23:47:16114 base::RunLoop* previous_run_loop = run_loop_;
115 base::RunLoop run_loop;
116 run_loop_ = &run_loop;
117
[email protected]15b12242012-01-26 19:28:47118 nested_invocations_++;
danakje125e8d62021-01-21 22:06:31119 CallWhileUnlocked(base::BindOnce(&base::RunLoop::Run,
120 base::Unretained(run_loop_), FROM_HERE));
[email protected]15b12242012-01-26 19:28:47121 nested_invocations_--;
122
fdoray2df4a9e2016-07-18 23:47:16123 run_loop_ = previous_run_loop;
124
[email protected]15b12242012-01-26 19:28:47125 if (should_destroy_ && nested_invocations_ == 0) {
kylechar37594cb2019-11-15 16:41:17126 task_runner_.reset();
Alex Clarke636e7052019-05-30 10:49:37127 single_thread_task_executor_.reset();
[email protected]15b12242012-01-26 19:28:47128 destroyed_ = true;
129 }
130 return PP_OK;
131}
132
133int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback,
134 int64_t delay_ms) {
135 if (!callback.func)
136 return PP_ERROR_BADARGUMENT;
137 if (destroyed_)
138 return PP_ERROR_FAILED;
139 PostClosure(FROM_HERE,
Jan Wilken Dörrie15647162020-04-20 10:09:58140 base::BindOnce(callback.func, callback.user_data,
141 static_cast<int32_t>(PP_OK)),
[email protected]15b12242012-01-26 19:28:47142 delay_ms);
143 return PP_OK;
144}
145
146int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) {
[email protected]6de743a2012-08-30 20:03:22147 if (is_main_thread_loop_)
148 return PP_ERROR_WRONG_THREAD;
149
[email protected]15b12242012-01-26 19:28:47150 if (PP_ToBool(should_destroy))
151 should_destroy_ = true;
152
fdoray2df4a9e2016-07-18 23:47:16153 if (IsCurrent() && nested_invocations_ > 0) {
154 run_loop_->QuitWhenIdle();
155 } else {
Jan Wilken Dörrie15647162020-04-20 10:09:58156 PostClosure(FROM_HERE,
157 base::BindOnce(&MessageLoopResource::QuitRunLoopWhenIdle,
158 Unretained(this)),
fdoray2df4a9e2016-07-18 23:47:16159 0);
160 }
[email protected]15b12242012-01-26 19:28:47161 return PP_OK;
162}
163
[email protected]77c34172012-11-08 18:55:16164// static
165MessageLoopResource* MessageLoopResource::GetCurrent() {
166 PluginGlobals* globals = PluginGlobals::Get();
167 if (!globals->msg_loop_slot())
168 return NULL;
169 return reinterpret_cast<MessageLoopResource*>(
170 globals->msg_loop_slot()->Get());
171}
[email protected]6de743a2012-08-30 20:03:22172
[email protected]77c34172012-11-08 18:55:16173void MessageLoopResource::DetachFromThread() {
Alex Clarkef7fb8a82019-06-06 15:41:53174 // Note that the task executor must be destroyed on the thread it was created
[email protected]15b12242012-01-26 19:28:47175 // on.
kylechar37594cb2019-11-15 16:41:17176 task_runner_.reset();
Alex Clarke636e7052019-05-30 10:49:37177 single_thread_task_executor_.reset();
[email protected]15b12242012-01-26 19:28:47178
179 // Cancel out the AddRef in AttachToCurrentThread().
180 Release();
181 // DANGER: may delete this.
182}
183
184bool MessageLoopResource::IsCurrent() const {
[email protected]9d11bb462012-02-05 03:07:39185 PluginGlobals* globals = PluginGlobals::Get();
186 if (!globals->msg_loop_slot())
[email protected]15b12242012-01-26 19:28:47187 return false; // Can't be current if there's nothing in the slot.
[email protected]9d11bb462012-02-05 03:07:39188 return static_cast<const void*>(globals->msg_loop_slot()->Get()) ==
[email protected]15b12242012-01-26 19:28:47189 static_cast<const void*>(this);
190}
191
Brett Wilson9c361992017-09-12 06:05:21192void MessageLoopResource::PostClosure(const base::Location& from_here,
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47193 base::OnceClosure closure,
Brett Wilson9c361992017-09-12 06:05:21194 int64_t delay_ms) {
skyostil23490d42015-06-12 12:54:26195 if (task_runner_.get()) {
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47196 task_runner_->PostDelayedTask(from_here, std::move(closure),
Peter Kastinge5a38ed2021-10-02 03:06:35197 base::Milliseconds(delay_ms));
[email protected]15b12242012-01-26 19:28:47198 } else {
199 TaskInfo info;
200 info.from_here = FROM_HERE;
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47201 info.closure = std::move(closure);
[email protected]15b12242012-01-26 19:28:47202 info.delay_ms = delay_ms;
Jan Wilken Dörrie1d33fc62020-01-23 10:20:47203 pending_tasks_.push_back(std::move(info));
[email protected]15b12242012-01-26 19:28:47204 }
205}
206
skyostil23490d42015-06-12 12:54:26207base::SingleThreadTaskRunner* MessageLoopResource::GetTaskRunner() {
208 return task_runner_.get();
[email protected]511c58e2013-12-12 12:25:33209}
210
dmichael44b967542014-09-24 15:41:14211bool MessageLoopResource::CurrentlyHandlingBlockingMessage() {
212 return currently_handling_blocking_message_;
213}
214
fdoray2df4a9e2016-07-18 23:47:16215void MessageLoopResource::QuitRunLoopWhenIdle() {
216 DCHECK(IsCurrent());
217 DCHECK(run_loop_);
218 run_loop_->QuitWhenIdle();
219}
220
[email protected]15b12242012-01-26 19:28:47221// static
222void MessageLoopResource::ReleaseMessageLoop(void* value) {
223 static_cast<MessageLoopResource*>(value)->DetachFromThread();
224}
225
226// -----------------------------------------------------------------------------
227
228PP_Resource Create(PP_Instance instance) {
[email protected]64cbf812013-01-26 00:52:51229 ProxyAutoLock lock;
[email protected]15b12242012-01-26 19:28:47230 // Validate the instance.
231 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
232 if (!dispatcher)
233 return 0;
234 return (new MessageLoopResource(instance))->GetReference();
235}
236
237PP_Resource GetForMainThread() {
[email protected]64cbf812013-01-26 00:52:51238 ProxyAutoLock lock;
[email protected]6de743a2012-08-30 20:03:22239 return PluginGlobals::Get()->loop_for_main_thread()->GetReference();
[email protected]15b12242012-01-26 19:28:47240}
241
242PP_Resource GetCurrent() {
[email protected]64cbf812013-01-26 00:52:51243 ProxyAutoLock lock;
[email protected]77c34172012-11-08 18:55:16244 Resource* resource = MessageLoopResource::GetCurrent();
245 if (resource)
246 return resource->GetReference();
247 return 0;
[email protected]15b12242012-01-26 19:28:47248}
249
250int32_t AttachToCurrentThread(PP_Resource message_loop) {
251 EnterMessageLoop enter(message_loop, true);
252 if (enter.succeeded())
253 return enter.object()->AttachToCurrentThread();
254 return PP_ERROR_BADRESOURCE;
255}
256
257int32_t Run(PP_Resource message_loop) {
258 EnterMessageLoop enter(message_loop, true);
259 if (enter.succeeded())
260 return enter.object()->Run();
261 return PP_ERROR_BADRESOURCE;
262}
263
264int32_t PostWork(PP_Resource message_loop,
265 PP_CompletionCallback callback,
266 int64_t delay_ms) {
267 EnterMessageLoop enter(message_loop, true);
268 if (enter.succeeded())
269 return enter.object()->PostWork(callback, delay_ms);
270 return PP_ERROR_BADRESOURCE;
271}
272
273int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) {
274 EnterMessageLoop enter(message_loop, true);
275 if (enter.succeeded())
276 return enter.object()->PostQuit(should_destroy);
277 return PP_ERROR_BADRESOURCE;
278}
279
[email protected]d4ab94712012-11-15 21:01:23280const PPB_MessageLoop_1_0 ppb_message_loop_interface = {
[email protected]15b12242012-01-26 19:28:47281 &Create,
282 &GetForMainThread,
283 &GetCurrent,
284 &AttachToCurrentThread,
285 &Run,
286 &PostWork,
287 &PostQuit
288};
289
[email protected]15b12242012-01-26 19:28:47290PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
291 : InterfaceProxy(dispatcher) {
292}
293
294PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
295}
296
297// static
[email protected]d4ab94712012-11-15 21:01:23298const PPB_MessageLoop_1_0* PPB_MessageLoop_Proxy::GetInterface() {
[email protected]15b12242012-01-26 19:28:47299 return &ppb_message_loop_interface;
300}
301
302} // namespace proxy
303} // namespace ppapi